diff --git a/.circleci/config.yml b/.circleci/config.yml index b623da36bb..4c6c73b37c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,242 +1,21 @@ version: 2.1 -parameters: - xcode_version: - type: string - default: "13.4.1" - ios_current_version: - type: string - default: "15.5" - ios_previous_version: - type: string - default: "14.5" - ios_sdk: - type: string - default: "iphonesimulator15.5" - macos_version: # The user-facing version string for macOS builds - type: string - default: "12.3.1" - macos_sdk: # The full SDK string to use for macOS builds - type: string - default: "macosx12.3" - tvos_version: # The user-facing version string of tvOS builds - type: string - default: "15.4" - tvos_sdk: - type: string - default: "appletvsimulator15.4" - -commands: - integration_test_setup: - steps: - - restore_cache: - key: starwars-server - - restore_cache: - key: apollo-server-graphql-transport-ws - - common_test_setup - - run: - command: ./scripts/install-node-v12.sh - name: Install Node - - run: - command: ./scripts/install-or-update-starwars-server.sh - name: Install/Update StarWars Server - - run: - command: cd ../starwars-server && npm start - name: Start StarWars Server - background: true - - run: - command: cd SimpleUploadServer && nvm use && npm install && npm start - name: Start Upload Server - background: true - - run: - command: sudo chmod -R +rwx SimpleUploadServer - name: Adjust permissions for simple upload server folder - - run: - command: ./scripts/install-apollo-server-docs-example-server.sh - name: Install Apollo Server (graphql-transport-ws configuration) - - run: - command: cd ../docs-examples/apollo-server/v3/subscriptions-graphql-ws && npm start - name: Start Apollo Server (graphql-transport-ws configuration) - background: true - integration_test_cleanup: - steps: - - save_cache: - key: starwars-server - paths: - - ../starwars-server - - save_cache: - key: apollo-server-graphql-transport-ws - paths: - - ../docs-examples/apollo-server/v3/subscriptions-graphql-ws - common_test_setup: - description: Commands to run for setup of every set of tests - steps: - - checkout - - run: - command: rm ~/.ssh/id_rsa - name: Remove old SSH key - - run: - command: for ip in $(dig @8.8.8.8 bitbucket.org +short); do ssh-keyscan bitbucket.org,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts || true - name: Bitbucket Key Workaround - - run: - command: for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan github.com,$ip; ssh-keyscan $ip; done 2>/dev/null >> ~/.ssh/known_hosts || true - name: Github Key Workaround - build_and_run_tests: - steps: - - run: - command: xcodebuild clean build build-for-testing -project "Apollo.xcodeproj" -scheme "${CIRCLE_XCODE_SCHEME}" -sdk "${CIRCLE_XCODE_SDK}" -destination "${DESTINATION}" -testPlan "${CIRCLE_XCODE_TEST_PLAN}" | xcpretty - name: Clean and build for testing - - run: - command: xcodebuild test-without-building -resultBundlePath ~/TestResults/ResultBundle.xcresult -project "Apollo.xcodeproj" -scheme "${CIRCLE_XCODE_SCHEME}" -sdk "${CIRCLE_XCODE_SDK}" -destination "${DESTINATION}" -testPlan "${CIRCLE_XCODE_TEST_PLAN}" | xcpretty - name: Run tests - - save-xcodebuild-artifacts - save-xcodebuild-artifacts: - description: Save artifacts logs, crash reports and test results generated by xcodebuild - steps: - - store_artifacts: - name: Save xcodebuild logs - path: logs - destination: logs - - store_artifacts: - name: Save crash logs - path: ~/Library/Logs/DiagnosticReports/ - destination: crashes - - run: - name: Zip result bundle - working_directory: ~/TestResults - command: zip -r ResultBundle.zip ResultBundle.xcresult - when: always - - store_artifacts: - name: Save test results - path: ~/TestResults/ResultBundle.zip - destination: results - -# Important! When adding a new job to `jobs`, make sure to define when it -# executes by also adding it to the `workflows` section below! -jobs: - Swift_Build: - macos: - xcode: << pipeline.parameters.xcode_version >> - steps: - - common_test_setup - - run: - command: swift build - - IntegrationTests_macOS_current: - macos: - xcode: << pipeline.parameters.xcode_version >> - environment: - DESTINATION: platform=macOS,arch=x86_64 - CIRCLE_XCODE_SCHEME: Apollo - CIRCLE_XCODE_TEST_PLAN: Apollo-IntegrationTestPlan - CIRCLE_XCODE_SDK: << pipeline.parameters.macos_sdk >> - steps: - - integration_test_setup - - build_and_run_tests - - integration_test_cleanup - - macOS_current: - macos: - xcode: << pipeline.parameters.xcode_version >> - environment: - DESTINATION: platform=macOS,arch=x86_64 - CIRCLE_XCODE_SCHEME: Apollo - CIRCLE_XCODE_TEST_PLAN: Apollo-CITestPlan - CIRCLE_XCODE_SDK: << pipeline.parameters.macos_sdk >> - steps: - - common_test_setup - - build_and_run_tests - - iOS_current: - macos: - xcode: << pipeline.parameters.xcode_version >> - environment: - DESTINATION: platform=iOS Simulator,OS=<< pipeline.parameters.ios_current_version >>,name=iPhone 12 - CIRCLE_XCODE_SCHEME: Apollo - CIRCLE_XCODE_TEST_PLAN: Apollo-CITestPlan - CIRCLE_XCODE_SDK: << pipeline.parameters.ios_sdk >> - steps: - - common_test_setup - - build_and_run_tests - - iOS_previous: - macos: - xcode: << pipeline.parameters.xcode_version >> - environment: - DESTINATION: platform=iOS Simulator,OS=<< pipeline.parameters.ios_previous_version >>,name=iPhone 12 - CIRCLE_XCODE_SCHEME: Apollo - CIRCLE_XCODE_TEST_PLAN: Apollo-CITestPlan - CIRCLE_XCODE_SDK: << pipeline.parameters.ios_sdk >> - steps: - - common_test_setup - - build_and_run_tests - - tvOS_current: - macos: - xcode: << pipeline.parameters.xcode_version >> - environment: - DESTINATION: platform=tvOS Simulator,OS=<< pipeline.parameters.tvos_version >>,name=Apple TV - CIRCLE_XCODE_SCHEME: Apollo - CIRCLE_XCODE_TEST_PLAN: Apollo-CITestPlan - CIRCLE_XCODE_SDK: << pipeline.parameters.tvos_sdk >> - steps: - - common_test_setup - - build_and_run_tests - - CodegenLib_macOS_current: - macos: - xcode: << pipeline.parameters.xcode_version >> - environment: - DESTINATION: platform=macOS,arch=x86_64 - CIRCLE_XCODE_SCHEME: ApolloCodegenLib - CIRCLE_XCODE_TEST_PLAN: Apollo-CodegenTestPlan - CIRCLE_XCODE_SDK: << pipeline.parameters.macos_sdk >> - steps: - - common_test_setup - - build_and_run_tests - - CocoaPodsTrunk: - macos: - xcode: << pipeline.parameters.xcode_version >> - steps: - - checkout - # TODO: Remove when Circle updates the version of CP installed on their - # image to one that doesn't have https://github.com/CocoaPods/CocoaPods/issues/9176 - - run: pod repo add-cdn trunk 'https://cdn.cocoapods.org/' - - run: pod trunk push Apollo.podspec - - run: pod trunk me clean-sessions --all +orbs: + secops: apollo/circleci-secops-orb@2.0.7 workflows: - version: 2 - # This workflow builds and tests the library across various operating systems and versions - build-and-test: + security-scans: jobs: - - Swift_Build: - name: Build with SPM - - IntegrationTests_macOS_current: - name: Apollo Integration Tests macOS << pipeline.parameters.macos_version >> - - macOS_current: - name: Apollo macOS << pipeline.parameters.macos_version >> - - iOS_current: - name: Apollo iOS << pipeline.parameters.ios_current_version >> - - iOS_previous: - name: Apollo iOS << pipeline.parameters.ios_previous_version >> - - tvOS_current: - name: Apollo tvOS << pipeline.parameters.tvos_version >> - - CodegenLib_macOS_current: - name: Swift Code Generation - - CocoaPodsTrunk: - name: Push Podspec to CocoaPods Trunk - requires: - - Apollo macOS << pipeline.parameters.macos_version >> - - Apollo iOS << pipeline.parameters.ios_current_version >> - - Apollo iOS << pipeline.parameters.ios_previous_version >> - - Apollo tvOS << pipeline.parameters.tvos_version >> - - Swift Code Generation - filters: - # Only build semver tags - tags: - only: /((\d*)\.(\d*)\.(\d*)).*/ - # Don't run this on any branches - branches: - ignore: /.*/ + - secops/gitleaks: + context: + - platform-docker-ro + - github-orb + - secops-oidc + git-base-revision: <<#pipeline.git.base_revision>><><> + git-revision: << pipeline.git.revision >> + - secops/semgrep: + context: + - secops-oidc + - github-orb + git-base-revision: <<#pipeline.git.base_revision>><><> + fail-on-findings: true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..3753142351 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +docs/docc/Apollo.doccarchive/** linguist-generated=true \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..e4b317af61 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# This file was automatically generated by the Apollo SecOps team +# Please customize this file as needed prior to merging. + +* @apollographql/client-swift diff --git a/.github/CODEOWNERS.md b/.github/CODEOWNERS.md deleted file mode 100644 index 0bcb000641..0000000000 --- a/.github/CODEOWNERS.md +++ /dev/null @@ -1,2 +0,0 @@ -# https://help.github.com/articles/about-code-owners/ -/docs/ @stephenbarlow \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000000..971d721982 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,42 @@ +name: Bug report +description: Create a bug report +labels: [ "bug", "needs investigation" ] +body: + - type: textarea + attributes: + label: Summary + description: A clear and concise description of what the bug is. + validations: + required: true + - type: input + attributes: + label: Version + description: Make sure the bug is still happening on the latest version. Make sure you've read [`CHANGELOG.md`](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md) to check that a new version hasn't already addressed your problem. + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce the behavior + description: | + Add context about the problem here. How it happened and how to reproduce it: + - If your project is open source, a link to the project is greatly appreciated. + - If not, please share as much information as possible to help to understand the problem: schema, queries, sample code, etc... + - Add things that you already tried. + validations: + required: true + - type: textarea + attributes: + label: Logs + description: | + Paste logs and full stacktrace here. + You can also attach files by dragging them into the area. + placeholder: This will be automatically formatted into code, so no need for backticks. + render: shell + validations: + required: false + - type: textarea + attributes: + label: Anything else? + description: Links, references, more context, or anything that will give us more information about the issue you are encountering! + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000000..127f658fe8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,18 @@ +name: Feature request +description: Suggest an idea for this project +labels: [ "feature" ] +body: + - type: textarea + attributes: + label: Use case + description: A clear and concise description of what the problem is. + validations: + required: true + - type: textarea + attributes: + label: Describe the solution you'd like + description: | + A clear and concise description of what you want to happen. + If you already have an idea of the API you would like, do not hesitate to add it to the issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/issue-template-bug.md b/.github/ISSUE_TEMPLATE/issue-template-bug.md deleted file mode 100644 index 1db722af21..0000000000 --- a/.github/ISSUE_TEMPLATE/issue-template-bug.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Bug report -about: Use this template for submitting bug reports. ---- - -## Bug report - -Please replace this line with a short description of the problem. Make sure you've read `CHANGELOG.md` in the root of the repo to make sure a new version hasn't already addressed your problem! - -## Versions - -Please fill in the versions you're currently using: - -- `apollo-ios` SDK version: -- Xcode version: -- Swift version: -- Package manager: - -## Steps to reproduce - -Please replace this line with steps to reproduce the problem. - -## Further details - -Please replace this line with any further details or context necessary to understand the problem. Delete this section if you don't have anything further to add. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/issue-template-feature-request.md b/.github/ISSUE_TEMPLATE/issue-template-feature-request.md deleted file mode 100644 index a45338fbcc..0000000000 --- a/.github/ISSUE_TEMPLATE/issue-template-feature-request.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: Feature request -about: Use this template for requesting new features or significant changes to existing features. ---- - - -## Feature request - -Please replace this line with a short description of the feature you're requesting. - -## Motivation - -Please replace this line with an explanation for why you would like this feature added. - -## Proposed solution - -Please replace this line with any proposed solution you have already started to work on. Delete this section if you don't have a proposed solution. - -## Outstanding Questions - -Please replace this line with any known question marks around how your feature would work. Delete this section if you don't have any outstanding questions. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/issue-template-question.md b/.github/ISSUE_TEMPLATE/issue-template-question.md deleted file mode 100644 index 83d8897929..0000000000 --- a/.github/ISSUE_TEMPLATE/issue-template-question.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Question -about: Please don't use issues to ask questions, use our forums instead. -labels: question ---- - - -## Question - -Before you ask, check a few things to see if there might already be an answer: - -- [`CHANGELOG.md`](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md) has all the most recent changes -- We have [extensive documentation available](https://www.apollographql.com/docs/ios) (though we're always looking for ways to improve it!) - - -If neither of those have an answer for you, we have [community forums](https://community.apollographql.com) where our users can ask and answer questions - head on over there rather than opening an issue here please! - -## Seriously - -Use the [community forums](https://community.apollographql.com) for questions, please! 😇 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/question.yaml b/.github/ISSUE_TEMPLATE/question.yaml new file mode 100644 index 0000000000..7e8cfbc7e2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.yaml @@ -0,0 +1,22 @@ +name: Question +description: Ask a general question about the project +labels: [ "question" ] +body: + - type: markdown + attributes: + value: | + Please search the existing resources before asking your question: + - [`CHANGELOG.md`](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md) + - [Documentation](https://www.apollographql.com/docs/ios) + - [GitHub issues](https://github.com/apollographql/apollo-ios/issues) + - [StackOverflow](https://stackoverflow.com/questions/tagged/apollo-ios) + - [GraphOS Discord](https://discord.com/invite/graphos) + - [Community forums](https://community.apollographql.com/tag/mobile) + + Please avoid duplicating issues and discussions. If you'd like a GitHub issue to be reopened, leave a message on the issue. + - type: textarea + attributes: + label: Question + placeholder: Please reconsider using this template and use one of the listed resources instead. + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE/pull-request-template-release.md b/.github/PULL_REQUEST_TEMPLATE/pull-request-template-release.md deleted file mode 100644 index f40729448f..0000000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull-request-template-release.md +++ /dev/null @@ -1,26 +0,0 @@ -#### Diff -Example: [0.48.0...main](https://github.com/apollographql/apollo-ios/compare/0.48.0...main). - -#### Relevant changes: -* _List the highlight changes_ - -#### Things to do in this PR -- [ ] Update the version in [`Configuration/Shared/Project-Version.xcconfig`](https://github.com/apollographql/apollo-ios/blob/main/Configuration/Shared/Project-Version.xcconfig). -- [ ] Update [`CHANGELOG.md`](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md) with all relevant changes since the prior version. Please include PR numbers and mention contributors for external PR submissions. -- [ ] Run the Documentation Generator as noted in [`api-reference.md`](https://github.com/apollographql/apollo-ios/blob/main/docs/source/api-reference.md) to re-generate documentation from source for all included libraries. - -#### Other things to do before a release - _these need to be automated by CI_ -- [ ] Validate that `main` builds with a test Swift Package Manager project. -- [ ] Validate that `main` builds with a test CocoaPods project. -- [ ] Validate that `main` builds with a test Carthage project (make sure to use `--use-xcframeworks`). - -#### Things to do as part of releasing -- [ ] Add tag of format `major.minor.patch` to GitHub for SPM/Carthage. -- [ ] Create a release on GitHub with the new tag, using the latest [`CHANGELOG.md`](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md) contents. -- [ ] Run `pod trunk push Apollo.podspec` to publish to CocoaPods. You will need write permissions for this, please contact one of the [maintainers](https://github.com/apollographql/apollo-ios/blob/main/README.md#maintainers) if you need access to do this. -- [ ] Announce the new version (Twitter, etc.) - -#### Things to do after release - _these need to be automated by CI_ -- [ ] Update to the new version of apollo-ios in the [sample application](https://github.com/apollographql/iOSTutorial). -- [ ] Update to the new version of apollo-ios in the [codegen template](https://github.com/apollographql/iOSCodegenTemplate). -- [ ] Make sure all [playground pages](https://github.com/apollographql/apollo-client-swift-playground) still execute. diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml deleted file mode 100644 index 74d2b79e22..0000000000 --- a/.github/workflows/docs-publish.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Deploy docs to production - -on: - push: - branches: - - main - - release/1.0 - paths: - - docs/** - -permissions: - contents: read - -jobs: - publish: - permissions: - contents: none - uses: apollographql/docs/.github/workflows/publish.yml@main - secrets: - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} diff --git a/.github/workflows/issue-close-user-survey.yml b/.github/workflows/issue-close-user-survey.yml new file mode 100644 index 0000000000..7a2825410e --- /dev/null +++ b/.github/workflows/issue-close-user-survey.yml @@ -0,0 +1,27 @@ +name: Issue Close User Survey + +on: + issues: + types: [closed] + +jobs: + user-survey-comment: + permissions: + issues: write + runs-on: ubuntu-latest + if: github.repository == 'apollographql/apollo-ios' + steps: + - run: | + if [ "$AUTHOR" == "MEMBER" ] && (( $COMMENTS == 0 )); then + echo "Issue opened by member with no comments, skipping user survey." + else + gh issue comment "$NUMBER" --body "$BODY" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.issue.number }} + COMMENTS: ${{ github.event.issue.comments }} + AUTHOR: ${{ github.event.issue.author_association }} + BODY: > + Do you have any feedback for the maintainers? Please tell us by taking a [one-minute survey](https://docs.google.com/forms/d/e/1FAIpQLSczNDXfJne3ZUOXjk9Ursm9JYvhTh1_nFTDfdq3XBAFWCzplQ/viewform?usp=pp_url&entry.1170701325=Apollo+iOS&entry.204965213=GitHub+Issue). Your responses will help us understand Apollo iOS usage and allow us to serve you better. diff --git a/.github/workflows/pr-close.yml b/.github/workflows/pr-close.yml new file mode 100644 index 0000000000..b1829d4d30 --- /dev/null +++ b/.github/workflows/pr-close.yml @@ -0,0 +1,14 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened] + +jobs: + run: + name: Close and Comment PR + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: "We do not accept PRs directly to the 'apollo-ios' repo. All development is done through the 'apollo-ios-dev' repo, please see the CONTRIBUTING guide for more information." \ No newline at end of file diff --git a/.github/workflows/prometheus-project-add.yml b/.github/workflows/prometheus-project-add.yml new file mode 100644 index 0000000000..9a554c2287 --- /dev/null +++ b/.github/workflows/prometheus-project-add.yml @@ -0,0 +1,26 @@ +name: Add newly opened issues to Prometheus Project +on: + issues: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - name: Add to project + uses: actions/add-to-project@v1.0.0 + with: + project-url: https://github.com/orgs/apollographql/projects/21 + github-token: ${{ secrets.PROMETHEUS_PROJECT_ACCESS_SECRET }} + - name: Set project variables + if: ${{ success() }} + uses: austenstone/project-update@v1 + with: + project-number: 21 + item-id: ${{ github.event.number }} + github-token: ${{ secrets.PROMETHEUS_PROJECT_ACCESS_SECRET }} + organization: apollographql + fields: Status,Project + fields-value: Triage,Client (Swift) diff --git a/.gitignore b/.gitignore index 47f06525d4..514275e0fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ ## Build generated build/ DerivedData/ +apollo-ios-cli +!apollo-ios-cli/ ## Various settings *.pbxuser @@ -19,6 +21,9 @@ xcuserdata/ *.xcscmblueprint .DS_Store +## Visual Studio Code +.vscode/launch.json + ## Obj-C/Swift specific *.hmap *.ipa @@ -41,7 +46,7 @@ playground.xcworkspace # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # -# Pods/ +**/Pods/ # Carthage # @@ -64,3 +69,20 @@ SwiftScripts/.build-** # Local Netlify folder .netlify + +# Generated js files we don't need committed +Sources/ApolloCodegenLib/Frontend/dist/ + +# Local generated packages we don't need in the main project +Sources/AnimalKingdomAPI/Generated/Package.swift +Sources/AnimalKingdomAPI/Generated/Package.resolved +Tests/TestCodeGenConfigurations/**/AnimalKingdomAPI/ +Tests/TestCodeGenConfigurations/**/AnimalKingdomAPITestMocks +Tests/TestCodeGenConfigurations/**/Package.resolved +Tests/TestCodeGenConfigurations/**/Podfile.lock +Tests/TestCodeGenConfigurations/**/TestMocks +Tests/TestCodeGenConfigurations/EmbeddedInTarget-RelativeAbsolute/PackageOne/**/*.graphql.swift +Tests/TestCodeGenConfigurations/EmbeddedInTarget-RelativeAbsolute/PackageTwo/Sources/PackageTwo +!Tests/TestCodeGenConfigurations/**/SchemaConfiguration.swift +!Tests/TestCodeGenConfigurations/Other-CustomTarget/AnimalKingdomAPI/AnimalKingdomAPI.h +!Tests/TestCodeGenConfigurations/EmbeddedInTarget-RelativeAbsolute/PackageTwo/Sources/PackageTwo/PackageTwo.swift diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000000..fd9bf43c4e --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,41 @@ +# This file exists primarily to influence scheduled scans that Apollo runs of all repos in Apollo-managed orgs. +# This is an Apollo-Internal link, but more information about these scans is available here: +# https://apollographql.atlassian.net/wiki/spaces/SecOps/pages/81330213/Everything+Static+Application+Security+Testing#Scheduled-Scans.1 +# +# Apollo is using Gitleaks (https://github.com/gitleaks/gitleaks) to run these scans. +# However, this file is not something that Gitleaks natively consumes. This file is an +# Apollo-convention. Prior to scanning a repo, Apollo merges +# our standard Gitleaks configuration (which is largely just the Gitleaks-default config) with +# this file if it exists in a repo. The combined config is then used to scan a repo. +# +# We did this because the natively-supported allowlisting functionality in Gitleaks didn't do everything we wanted +# or wasn't as robust as we needed. For example, one of the allowlisting options offered by Gitleaks depends on the line number +# on which a false positive secret exists to allowlist it. (https://github.com/gitleaks/gitleaks#gitleaksignore). +# This creates a fairly fragile allowlisting mechanism. This file allows us to leverage the full capabilities of the Gitleaks rule syntax +# to create allowlisting functionality. + +[[ rules ]] + id = "high-entropy-base64" + [ rules.allowlist ] + commits = [ + "2568a4c9921ccb04e8391200554bdd8897000fa6", + + ] + +[[ rules ]] + id = "generic-api-key" + [ rules.allowlist ] + + paths = [ + # Allowlists a false positive detection at + # https://github.com/apollographql/apollo-ios/blob/474554504e7e33cef2a71774f825d5b3947ff797/Tests/ApolloCodegenTests/TestHelpers/ASTMatchers.swift#L72 + # This was previously allowlisted via commit hash, but updating that rule + # To support allowlisting false positive detections in the files below as well. + '''Tests/ApolloCodegenTests/TestHelpers/ASTMatchers.swift''', + + # Allowlist the various high-entropy strings in xcscmblueprint files + '''Apollo.xcodeproj/project.xcworkspace/xcshareddata/Apollo.xcscmblueprint$''', + '''ApolloSQLite.xcodeproj/project.xcworkspace/xcshareddata/ApolloSQLite.xcscmblueprint$''', + '''Apollo.xcworkspace/xcshareddata/Apollo.xcscmblueprint$''', + ] + diff --git a/.gitmodules b/.gitmodules index e69de29bb2..6ed3784fc9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "docs/renderer"] + path = docs/renderer + url = https://github.com/apollographql/swift-docc-render.git diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a625..0000000000 --- a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Apollo.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Apollo.xcscheme deleted file mode 100644 index d04ab95beb..0000000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Apollo.xcscheme +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme deleted file mode 100644 index d1f1128ce7..0000000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ApolloSQLite.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ApolloSQLite.xcscheme deleted file mode 100644 index 95042e0acd..0000000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ApolloSQLite.xcscheme +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ApolloWebSocket.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ApolloWebSocket.xcscheme deleted file mode 100644 index 98c8e1a168..0000000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ApolloWebSocket.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.podspec b/Apollo.podspec index 7dd106971c..d87665e785 100644 --- a/Apollo.podspec +++ b/Apollo.podspec @@ -1,31 +1,28 @@ Pod::Spec.new do |s| - s.name = 'Apollo' - s.version = `scripts/get-version.sh` - s.author = 'Meteor Development Group' - s.homepage = 'https://github.com/apollographql/apollo-ios' - s.license = { :type => 'MIT', :file => 'LICENSE' } - - s.summary = "A GraphQL client for iOS, written in Swift." - - s.source = { :git => 'https://github.com/apollographql/apollo-ios.git', :tag => s.version } - + s.name = 'Apollo' + s.version = `scripts/get-version.sh` + s.author = 'Apollo GraphQL' + s.homepage = 'https://github.com/apollographql/apollo-ios' + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.summary = "A GraphQL client for iOS, written in Swift." + s.source = { :git => 'https://github.com/apollographql/apollo-ios.git', :tag => s.version } s.requires_arc = true - - s.swift_version = '5.0' - + s.swift_version = '5.6' s.default_subspecs = 'Core' - s.ios.deployment_target = '12.0' s.osx.deployment_target = '10.14' s.tvos.deployment_target = '12.0' s.watchos.deployment_target = '5.0' + cli_binary_name = 'apollo-ios-cli' + s.preserve_paths = [cli_binary_name] + s.prepare_command = <<-CMD + make unpack-cli + CMD + s.subspec 'Core' do |ss| - ss.source_files = 'Sources/Apollo/*.swift','Sources/ApolloUtils/*.swift','Sources/ApolloAPI/*.swift' - ss.exclude_files = 'Sources/ApolloAPI/CodegenV1/*.swift' - ss.preserve_paths = [ - 'scripts/run-bundled-codegen.sh', - ] + ss.source_files = 'Sources/Apollo/**/*.swift','Sources/ApolloAPI/**/*.swift' + ss.resource_bundles = {'Apollo' => ['Sources/Apollo/Resources/PrivacyInfo.xcprivacy']} end # Apollo provides exactly one persistent cache out-of-the-box, as a reasonable default choice for @@ -34,12 +31,18 @@ Pod::Spec.new do |s| ss.source_files = 'Sources/ApolloSQLite/*.swift' ss.dependency 'Apollo/Core' ss.dependency 'SQLite.swift', '~>0.13.1' + ss.resource_bundles = { + 'ApolloSQLite' => ['Sources/ApolloSQLite/Resources/PrivacyInfo.xcprivacy'] + } end # Websocket and subscription support based on Starscream s.subspec 'WebSocket' do |ss| ss.source_files = 'Sources/ApolloWebSocket/**/*.swift' ss.dependency 'Apollo/Core' + ss.resource_bundles = { + 'ApolloWebSocket' => ['Sources/ApolloWebSocket/Resources/PrivacyInfo.xcprivacy'] + } end end diff --git a/Apollo.xcodeproj/project.pbxproj b/Apollo.xcodeproj/project.pbxproj deleted file mode 100644 index 4e1da7cb78..0000000000 --- a/Apollo.xcodeproj/project.pbxproj +++ /dev/null @@ -1,3666 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 52; - objects = { - -/* Begin PBXBuildFile section */ - 19E9F6AC26D58A9A003AB80E /* OperationMessageIdCreatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19E9F6AA26D58A92003AB80E /* OperationMessageIdCreatorTests.swift */; }; - 19E9F6B526D6BF25003AB80E /* OperationMessageIdCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19E9F6A826D5867E003AB80E /* OperationMessageIdCreator.swift */; }; - 2EE7FFD0276802E30035DC39 /* CacheKeyConstructionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EE7FFCF276802E30035DC39 /* CacheKeyConstructionTests.swift */; }; - 54DDB0921EA045870009DD99 /* InMemoryNormalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54DDB0911EA045870009DD99 /* InMemoryNormalizedCache.swift */; }; - 5AC6CA4322AAF7B200B7C94D /* GraphQLHTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AC6CA4222AAF7B200B7C94D /* GraphQLHTTPMethod.swift */; }; - 5BB2C0232380836100774170 /* VersionNumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB2C0222380836100774170 /* VersionNumberTests.swift */; }; - 9B1CCDD92360F02C007C9032 /* Bundle+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B1CCDD82360F02C007C9032 /* Bundle+Helpers.swift */; }; - 9B21FD752422C29D00998B5C /* GraphQLFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B21FD742422C29D00998B5C /* GraphQLFileTests.swift */; }; - 9B260BEB245A020300562176 /* ApolloInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BEA245A020300562176 /* ApolloInterceptor.swift */; }; - 9B260BF1245A025400562176 /* HTTPRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BF0245A025400562176 /* HTTPRequest.swift */; }; - 9B260BF3245A026F00562176 /* RequestChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BF2245A026F00562176 /* RequestChain.swift */; }; - 9B260BF5245A028D00562176 /* HTTPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BF4245A028D00562176 /* HTTPResponse.swift */; }; - 9B260BF9245A030100562176 /* ResponseCodeInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BF8245A030100562176 /* ResponseCodeInterceptor.swift */; }; - 9B260BFB245A031900562176 /* NetworkFetchInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BFA245A031900562176 /* NetworkFetchInterceptor.swift */; }; - 9B260BFF245A054700562176 /* JSONRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260BFE245A054700562176 /* JSONRequest.swift */; }; - 9B260C04245A090600562176 /* RequestChainNetworkTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260C03245A090600562176 /* RequestChainNetworkTransport.swift */; }; - 9B260C08245A437400562176 /* InterceptorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260C07245A437400562176 /* InterceptorProvider.swift */; }; - 9B260C0A245A532500562176 /* JSONResponseParsingInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B260C09245A532500562176 /* JSONResponseParsingInterceptor.swift */; }; - 9B2B66F42513FAFE00B53ABF /* CancellationHandlingInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2B66F32513FAFE00B53ABF /* CancellationHandlingInterceptor.swift */; }; - 9B2DFBBF24E1FA1A00ED3AE6 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9B2DFBC024E1FA1A00ED3AE6 /* Apollo.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9B2DFBC724E1FA4800ED3AE6 /* UploadAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B2DFBC524E1FA3E00ED3AE6 /* UploadAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9B2DFBCD24E201A800ED3AE6 /* UploadAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2DFBB624E1FA0D00ED3AE6 /* UploadAPI.framework */; }; - 9B2DFBCF24E201DD00ED3AE6 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B2DFBCE24E201DD00ED3AE6 /* API.swift */; }; - 9B455CDF2492D05E002255A9 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6CB23D238077B60007259D /* Atomic.swift */; }; - 9B455CE52492D0A3002255A9 /* ApolloExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B455CE22492D0A3002255A9 /* ApolloExtension.swift */; }; - 9B455CE72492D0A3002255A9 /* Collection+Apollo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B455CE42492D0A3002255A9 /* Collection+Apollo.swift */; }; - 9B455CEB2492FB03002255A9 /* String+SHA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B455CEA2492FB03002255A9 /* String+SHA.swift */; }; - 9B4F453F244A27B900C2CF7D /* URLSessionClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4F453E244A27B900C2CF7D /* URLSessionClient.swift */; }; - 9B518C87235F819E004C426D /* CLIDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B518C85235F8125004C426D /* CLIDownloader.swift */; }; - 9B518C8C235F8B5F004C426D /* ApolloFilePathHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B518C8A235F8B05004C426D /* ApolloFilePathHelper.swift */; }; - 9B518C8D235F8B9E004C426D /* CLIDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B518C88235F8AD4004C426D /* CLIDownloaderTests.swift */; }; - 9B554CC4247DC29A002F452A /* TaskData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B554CC3247DC29A002F452A /* TaskData.swift */; }; - 9B64F6762354D219002D1BB5 /* URL+QueryDict.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B64F6752354D219002D1BB5 /* URL+QueryDict.swift */; }; - 9B68F0552416B33300E97318 /* LineByLineComparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B68F0542416B33300E97318 /* LineByLineComparison.swift */; }; - 9B708AAD2305884500604A11 /* ApolloClientProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B708AAC2305884500604A11 /* ApolloClientProtocol.swift */; }; - 9B78C71E2326E86E000C8C32 /* ErrorGenerationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B78C71B2326E859000C8C32 /* ErrorGenerationTests.swift */; }; - 9B7B6F59233C287200F32205 /* ApolloCodegen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7B6F57233C287100F32205 /* ApolloCodegen.swift */; }; - 9B7B6F5A233C287200F32205 /* ApolloCodegenOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7B6F58233C287100F32205 /* ApolloCodegenOptions.swift */; }; - 9B7B6F69233C2C0C00F32205 /* FileManager+Apollo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7B6F68233C2C0C00F32205 /* FileManager+Apollo.swift */; }; - 9B7BDA9B23FDE94C00ACD198 /* WebSocketError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA9423FDE94C00ACD198 /* WebSocketError.swift */; }; - 9B7BDA9C23FDE94C00ACD198 /* WebSocketTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA9523FDE94C00ACD198 /* WebSocketTask.swift */; }; - 9B7BDA9D23FDE94C00ACD198 /* SplitNetworkTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA9623FDE94C00ACD198 /* SplitNetworkTransport.swift */; }; - 9B7BDA9E23FDE94C00ACD198 /* OperationMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA9723FDE94C00ACD198 /* OperationMessage.swift */; }; - 9B7BDA9F23FDE94C00ACD198 /* WebSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA9823FDE94C00ACD198 /* WebSocketClient.swift */; }; - 9B7BDAA023FDE94C00ACD198 /* WebSocketTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA9923FDE94C00ACD198 /* WebSocketTransport.swift */; }; - 9B7BDAD023FDEBE300ACD198 /* SQLiteSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDACD23FDEBE300ACD198 /* SQLiteSerialization.swift */; }; - 9B7BDAD223FDEBE300ACD198 /* SQLiteNormalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDACF23FDEBE300ACD198 /* SQLiteNormalizedCache.swift */; }; - 9B7BDAF623FDEE2600ACD198 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 9B7BDAF523FDEE2600ACD198 /* SQLite */; }; - 9B7BDAFA23FDEE8A00ACD198 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9B7BDAFD23FDEE9300ACD198 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9B8C3FB3248DA2FE00707B13 /* URL+Apollo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B8C3FB1248DA2EA00707B13 /* URL+Apollo.swift */; }; - 9B8C3FB5248DA3E000707B13 /* URLExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B8C3FB4248DA3E000707B13 /* URLExtensionsTests.swift */; }; - 9B95EDC022CAA0B000702BB2 /* GETTransformerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B95EDBF22CAA0AF00702BB2 /* GETTransformerTests.swift */; }; - 9B96500A24BE62B7003C29C0 /* RequestChainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B96500824BE6201003C29C0 /* RequestChainTests.swift */; }; - 9B96500C24BE7239003C29C0 /* CacheReadInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B96500B24BE7239003C29C0 /* CacheReadInterceptor.swift */; }; - 9B9BBAF324DB39D70021C30F /* UploadRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9BBAF224DB39D70021C30F /* UploadRequest.swift */; }; - 9B9BBAF524DB4F890021C30F /* AutomaticPersistedQueryInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9BBAF424DB4F890021C30F /* AutomaticPersistedQueryInterceptor.swift */; }; - 9B9BBB1C24DB760B0021C30F /* UploadRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9BBB1A24DB75E60021C30F /* UploadRequestTests.swift */; }; - 9B9F16A726013DAB00FB2F31 /* SQLiteDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9F16A626013DAB00FB2F31 /* SQLiteDatabase.swift */; }; - 9B9F16B82601532500FB2F31 /* SQLiteDotSwiftDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B9F16B72601532500FB2F31 /* SQLiteDotSwiftDatabase.swift */; }; - 9BA1244A22D8A8EA00BF1D24 /* JSONSerialization+Sorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BA1244922D8A8EA00BF1D24 /* JSONSerialization+Sorting.swift */; }; - 9BA3130E2302BEA5007B7FC5 /* DispatchQueue+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BA3130D2302BEA5007B7FC5 /* DispatchQueue+Optional.swift */; }; - 9BAEEBEE2346644600808306 /* ApolloSchemaDownloadConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEBED2346644600808306 /* ApolloSchemaDownloadConfiguration.swift */; }; - 9BAEEBEF2346644B00808306 /* ApolloSchemaDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEBEB234663F200808306 /* ApolloSchemaDownloader.swift */; }; - 9BAEEBF123467E0A00808306 /* ApolloCLI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEBF023467E0A00808306 /* ApolloCLI.swift */; }; - 9BAEEBF32346DDAD00808306 /* CodegenLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEBF22346DDAD00808306 /* CodegenLogger.swift */; }; - 9BAEEBF52346E90700808306 /* CLIExtractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEBF42346E90700808306 /* CLIExtractor.swift */; }; - 9BAEEBF72346F0A000808306 /* StaticString+Apollo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEBF62346F0A000808306 /* StaticString+Apollo.swift */; }; - 9BAEEC01234BB8FD00808306 /* ApolloCodegenLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7B6F47233C26D100F32205 /* ApolloCodegenLib.framework */; }; - 9BAEEC10234BB95B00808306 /* FileManagerExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEC0D234BB95B00808306 /* FileManagerExtensionsTests.swift */; }; - 9BAEEC15234C132600808306 /* CLIExtractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEC14234C132600808306 /* CLIExtractorTests.swift */; }; - 9BAEEC17234C275600808306 /* ApolloSchemaPublicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEC16234C275600808306 /* ApolloSchemaPublicTests.swift */; }; - 9BAEEC19234C297800808306 /* ApolloCodegenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEC18234C297800808306 /* ApolloCodegenTests.swift */; }; - 9BC139A424EDCA6C00876D29 /* InterceptorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC139A224EDCA4400876D29 /* InterceptorTests.swift */; }; - 9BC139A624EDCAD900876D29 /* BlindRetryingTestInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC139A524EDCAD900876D29 /* BlindRetryingTestInterceptor.swift */; }; - 9BC139A824EDCE4F00876D29 /* RetryToCountThenSucceedInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC139A724EDCE4F00876D29 /* RetryToCountThenSucceedInterceptor.swift */; }; - 9BC2D9D3233C6EF0007BD083 /* Basher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC2D9D1233C6DC0007BD083 /* Basher.swift */; }; - 9BC742AC24CFB2FF0029282C /* ApolloErrorInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC742AB24CFB2FF0029282C /* ApolloErrorInterceptor.swift */; }; - 9BC742AE24CFB6450029282C /* CacheWriteInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC742AD24CFB6450029282C /* CacheWriteInterceptor.swift */; }; - 9BCA8C0926618226004FF2F6 /* UntypedGraphQLRequestBodyCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCA8C0826618226004FF2F6 /* UntypedGraphQLRequestBodyCreator.swift */; }; - 9BCF0CE023FC9CA50031D2A2 /* TestCacheProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCF0CD923FC9CA50031D2A2 /* TestCacheProvider.swift */; }; - 9BCF0CE323FC9CA50031D2A2 /* XCTAssertHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCF0CDC23FC9CA50031D2A2 /* XCTAssertHelpers.swift */; }; - 9BCF0CE423FC9CA50031D2A2 /* MockURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCF0CDD23FC9CA50031D2A2 /* MockURLSession.swift */; }; - 9BCF0CE523FC9CA50031D2A2 /* MockNetworkTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCF0CDF23FC9CA50031D2A2 /* MockNetworkTransport.swift */; }; - 9BCF0CE623FC9D7B0031D2A2 /* ApolloTestSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BCF0CDA23FC9CA50031D2A2 /* ApolloTestSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9BCF0D0123FC9F060031D2A2 /* StarWarsAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BCF0CF123FC9F060031D2A2 /* StarWarsAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9BCF0D0223FC9F060031D2A2 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BCF0CFC23FC9F060031D2A2 /* API.swift */; }; - 9BDE43D122C6655300FD7C7F /* Cancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BDE43D022C6655200FD7C7F /* Cancellable.swift */; }; - 9BDE43DF22C6708600FD7C7F /* GraphQLHTTPRequestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BDE43DE22C6708600FD7C7F /* GraphQLHTTPRequestError.swift */; }; - 9BDF201323FDC37600153E2B /* GitHubAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BDF200C23FDC37600153E2B /* GitHubAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9BDF201423FDC37600153E2B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF201123FDC37600153E2B /* API.swift */; }; - 9BE071AD2368D08700FA5952 /* Collection+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE071AC2368D08700FA5952 /* Collection+Helpers.swift */; }; - 9BE74D3D23FB4A8E006D354F /* FileFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE74D3C23FB4A8E006D354F /* FileFinder.swift */; }; - 9BEDC79E22E5D2CF00549BF6 /* RequestBodyCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEDC79D22E5D2CF00549BF6 /* RequestBodyCreator.swift */; }; - 9BEEDC2824E351E5001D1294 /* MaxRetryInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEEDC2724E351E5001D1294 /* MaxRetryInterceptor.swift */; }; - 9BEEDC2B24E61995001D1294 /* TestURLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEEDC2A24E61995001D1294 /* TestURLs.swift */; }; - 9BF1A95122CA6E71005292C2 /* GraphQLGETTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BF1A95022CA6E71005292C2 /* GraphQLGETTransformer.swift */; }; - 9BF6C94325194DE2000D5B93 /* MultipartFormData+Testing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BF6C91725194D7B000D5B93 /* MultipartFormData+Testing.swift */; }; - 9BF6C97025194ED7000D5B93 /* MultipartFormDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BF6C95225194EA5000D5B93 /* MultipartFormDataTests.swift */; }; - 9BF6C99C25195019000D5B93 /* String+IncludesForTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BF6C99B25195019000D5B93 /* String+IncludesForTesting.swift */; }; - 9BFE8DA9265D5D8F000BBF81 /* URLDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BFE8DA8265D5D8F000BBF81 /* URLDownloader.swift */; }; - 9F1A966B258F34BB00A06EEB /* ApolloCodegenFrontend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1A9665258F34BB00A06EEB /* ApolloCodegenFrontend.swift */; }; - 9F1A966C258F34BB00A06EEB /* GraphQLSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1A9667258F34BB00A06EEB /* GraphQLSchema.swift */; }; - 9F1A966D258F34BB00A06EEB /* CompilationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1A9668258F34BB00A06EEB /* CompilationResult.swift */; }; - 9F1A966F258F34BB00A06EEB /* JavaScriptBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1A966A258F34BB00A06EEB /* JavaScriptBridge.swift */; }; - 9F21730E2567E6F000566121 /* DataLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FADC8531E6B86D900C677E6 /* DataLoaderTests.swift */; }; - 9F21735B2568F3E200566121 /* PossiblyDeferredTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F21735A2568F3E200566121 /* PossiblyDeferredTests.swift */; }; - 9F295E311E27534800A24949 /* NormalizeQueryResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F295E301E27534800A24949 /* NormalizeQueryResults.swift */; }; - 9F295E381E277B2A00A24949 /* GraphQLResultNormalizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F295E371E277B2A00A24949 /* GraphQLResultNormalizer.swift */; }; - 9F3910272549741400AF54A6 /* MockGraphQLServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3910262549741400AF54A6 /* MockGraphQLServer.swift */; }; - 9F41CBF025A3490600C02CB7 /* schema.graphqls in Resources */ = {isa = PBXBuildFile; fileRef = 9F41CBEF25A3490600C02CB7 /* schema.graphqls */; }; - 9F41CC0025A3491E00C02CB7 /* schema.json in Resources */ = {isa = PBXBuildFile; fileRef = 9B2061622591B3860020D1E0 /* schema.json */; }; - 9F438D071E6C2FD9007BDC1A /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9F533AB31E6C4A4200CBE097 /* BatchedLoadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F438D0B1E6C494C007BDC1A /* BatchedLoadTests.swift */; }; - 9F54C8B7255D760B0065AFD6 /* ParsingPerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F54C8B6255D760B0065AFD6 /* ParsingPerformanceTests.swift */; }; - 9F54C8B9255D760B0065AFD6 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9F54C90F255D79C80065AFD6 /* ApolloTestSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */; }; - 9F54C910255D79C80065AFD6 /* GitHubAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FACA9C61F42E67200AE2DBD /* GitHubAPI.framework */; }; - 9F55347B1DE1DB2100E54264 /* ApolloStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55347A1DE1DB2100E54264 /* ApolloStore.swift */; }; - 9F578D901D8D2CB300C0EA36 /* HTTPURLResponse+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F578D8F1D8D2CB300C0EA36 /* HTTPURLResponse+Helpers.swift */; }; - 9F628E9525935BE600F94F9D /* GraphQLType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F628E9425935BE600F94F9D /* GraphQLType.swift */; }; - 9F628EB52593651B00F94F9D /* GraphQLValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F628EB42593651B00F94F9D /* GraphQLValue.swift */; }; - 9F62DF8E2590539A00E6E808 /* SchemaIntrospectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F62DF8D2590539A00E6E808 /* SchemaIntrospectionTests.swift */; }; - 9F62DFAE2590557F00E6E808 /* DocumentParsingAndValidationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F62DFAD2590557F00E6E808 /* DocumentParsingAndValidationTests.swift */; }; - 9F62DFBF2590560000E6E808 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F62DFBE2590560000E6E808 /* Helpers.swift */; }; - 9F62DFD02590710E00E6E808 /* GraphQLSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F62DFCF2590710E00E6E808 /* GraphQLSource.swift */; }; - 9F62E0102590728000E6E808 /* CompilationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F62E00F2590728000E6E808 /* CompilationTests.swift */; }; - 9F62E03F2590896400E6E808 /* GraphQLError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F62E03E2590896400E6E808 /* GraphQLError.swift */; }; - 9F65B1211EC106F30090B25F /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9F68F9F125415827004F26D0 /* XCTestCase+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F68F9F025415827004F26D0 /* XCTestCase+Helpers.swift */; }; - 9F69FFA91D42855900E000B1 /* NetworkTransport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F69FFA81D42855900E000B1 /* NetworkTransport.swift */; }; - 9F7BA89922927A3700999B3B /* ResponsePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7BA89822927A3700999B3B /* ResponsePath.swift */; }; - 9F8622FA1EC2117C00C38162 /* FragmentConstructionAndConversionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8622F91EC2117C00C38162 /* FragmentConstructionAndConversionTests.swift */; }; - 9F86B68B1E6438D700B885FF /* GraphQLSelectionSetMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F86B68A1E6438D700B885FF /* GraphQLSelectionSetMapper.swift */; }; - 9F86B6901E65533D00B885FF /* GraphQLResponseGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F86B68F1E65533D00B885FF /* GraphQLResponseGenerator.swift */; }; - 9F8A958D1EC0FFAB00304A2D /* ApolloTestSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */; }; - 9F8E0BD325668552000D9FA5 /* DataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FADC84E1E6B865E00C677E6 /* DataLoader.swift */; }; - 9F8E0BE325668559000D9FA5 /* PossiblyDeferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F33D6A32566475600A1543F /* PossiblyDeferred.swift */; }; - 9F8F334C229044A200C0E83B /* Decoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8F334B229044A200C0E83B /* Decoding.swift */; }; - 9F91CF8F1F6C0DB2008DD0BE /* MutatingResultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F91CF8E1F6C0DB2008DD0BE /* MutatingResultsTests.swift */; }; - 9FA6F3681E65DF4700BF8D73 /* GraphQLResultAccumulator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6F3671E65DF4700BF8D73 /* GraphQLResultAccumulator.swift */; }; - 9FACA9BE1F42E67200AE2DBD /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9FBE0D4025407B64002ED0B1 /* AsyncResultObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBE0D3F25407B64002ED0B1 /* AsyncResultObserver.swift */; }; - 9FC2333D1E66BBF7001E4541 /* GraphQLDependencyTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC2333C1E66BBF7001E4541 /* GraphQLDependencyTracker.swift */; }; - 9FC750481D2A532C00458D91 /* Apollo.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FC750471D2A532C00458D91 /* Apollo.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9FC7504F1D2A532D00458D91 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - 9FC750611D2A59C300458D91 /* GraphQLOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC750601D2A59C300458D91 /* GraphQLOperation.swift */; }; - 9FC750631D2A59F600458D91 /* ApolloClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC750621D2A59F600458D91 /* ApolloClient.swift */; }; - 9FC9A9BD1E2C271C0023C4D5 /* RecordSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9BC1E2C271C0023C4D5 /* RecordSet.swift */; }; - 9FC9A9BF1E2C27FB0023C4D5 /* GraphQLResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9BE1E2C27FB0023C4D5 /* GraphQLResult.swift */; }; - 9FC9A9C81E2EFE6E0023C4D5 /* CacheKeyForFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9C71E2EFE6E0023C4D5 /* CacheKeyForFieldTests.swift */; }; - 9FC9A9CC1E2FD0760023C4D5 /* Record.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9CB1E2FD0760023C4D5 /* Record.swift */; }; - 9FCDFD291E33D0CE007519DC /* GraphQLQueryWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCDFD281E33D0CE007519DC /* GraphQLQueryWatcher.swift */; }; - 9FCE2CEE1E6BE2D900E34457 /* NormalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCE2CED1E6BE2D800E34457 /* NormalizedCache.swift */; }; - 9FCE2D091E6C254700E34457 /* StarWarsAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FCE2CFA1E6C213D00E34457 /* StarWarsAPI.framework */; }; - 9FD1519A255D7F30003BDAAA /* IssuesAndCommentsForRepository.json in Resources */ = {isa = PBXBuildFile; fileRef = 9FD15199255D7F30003BDAAA /* IssuesAndCommentsForRepository.json */; }; - 9FDE0731258F3AA100DC0CA5 /* SchemaLoadingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F1A96AF258F36B200A06EEB /* SchemaLoadingTests.swift */; }; - 9FDE0752258F3BC200DC0CA5 /* StarWarsAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FCE2CFA1E6C213D00E34457 /* StarWarsAPI.framework */; }; - 9FEB050D1DB5732300DA3B44 /* JSONSerializationFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEB050C1DB5732300DA3B44 /* JSONSerializationFormat.swift */; }; - 9FEC15B41E681DAD00D461B4 /* GroupedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEC15B31E681DAD00D461B4 /* GroupedSequence.swift */; }; - 9FF90A611DDDEB100034C3B6 /* GraphQLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF90A5B1DDDEB100034C3B6 /* GraphQLResponse.swift */; }; - 9FF90A651DDDEB100034C3B6 /* GraphQLExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF90A5C1DDDEB100034C3B6 /* GraphQLExecutor.swift */; }; - 9FF90A6F1DDDEB420034C3B6 /* GraphQLMapEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF90A6A1DDDEB420034C3B6 /* GraphQLMapEncodingTests.swift */; }; - 9FF90A711DDDEB420034C3B6 /* ReadFieldValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF90A6B1DDDEB420034C3B6 /* ReadFieldValueTests.swift */; }; - 9FF90A731DDDEB420034C3B6 /* ParseQueryResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF90A6C1DDDEB420034C3B6 /* ParseQueryResponseTests.swift */; }; - C3279FC72345234D00224790 /* TestCustomRequestBodyCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3279FC52345233000224790 /* TestCustomRequestBodyCreator.swift */; }; - C338DF1722DD9DE9006AF33E /* RequestBodyCreatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C338DF1622DD9DE9006AF33E /* RequestBodyCreatorTests.swift */; }; - C377CCA922D798BD00572E03 /* GraphQLFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C377CCA822D798BD00572E03 /* GraphQLFile.swift */; }; - C377CCAB22D7992E00572E03 /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C377CCAA22D7992E00572E03 /* MultipartFormData.swift */; }; - D87AC09F2564D60B0079FAA5 /* ApolloClientOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87AC09E2564D60B0079FAA5 /* ApolloClientOperationTests.swift */; }; - DE058609266978A100265760 /* Selection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE664ED326602AF60054DB4F /* Selection.swift */; }; - DE05860A266978A100265760 /* ResponseDict.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3C7B11260A6FC900D2F4FF /* ResponseDict.swift */; }; - DE05860B266978A100265760 /* SelectionSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3C7B10260A6FC900D2F4FF /* SelectionSet.swift */; }; - DE05860C266978A100265760 /* FragmentProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3C7B12260A6FC900D2F4FF /* FragmentProtocols.swift */; }; - DE05860D266978A100265760 /* ScalarTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3C7B15260A6FCA00D2F4FF /* ScalarTypes.swift */; }; - DE05860E266978A100265760 /* GraphQLOptional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B68F06E241C649E00E97318 /* GraphQLOptional.swift */; }; - DE058610266978A100265760 /* InputValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9C11E2D3CAF0023C4D5 /* InputValue.swift */; }; - DE058613266978A100265760 /* GraphQLSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3C7B13260A6FCA00D2F4FF /* GraphQLSchema.swift */; }; - DE058616266978A100265760 /* GraphQLEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3C7B14260A6FCA00D2F4FF /* GraphQLEnum.swift */; }; - DE05862D2669800000265760 /* Matchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BE071AE2368D34D00FA5952 /* Matchable.swift */; }; - DE05862F266980C200265760 /* GraphQLSelectionSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9C41E2D6CE70023C4D5 /* GraphQLSelectionSet.swift */; }; - DE0586332669948500265760 /* InputValue+Evaluation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0586322669948500265760 /* InputValue+Evaluation.swift */; }; - DE0586342669956A00265760 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC4B91F1D2A6F8D0046A641 /* JSON.swift */; }; - DE0586352669956D00265760 /* JSONStandardTypeConversions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F27D4631D40379500715680 /* JSONStandardTypeConversions.swift */; }; - DE0586362669957800265760 /* CacheReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE664ED92666DF150054DB4F /* CacheReference.swift */; }; - DE0586372669958F00265760 /* GraphQLError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC9A9D21E2FD48B0023C4D5 /* GraphQLError.swift */; }; - DE0586392669985000265760 /* Dictionary+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE0586382669985000265760 /* Dictionary+Helpers.swift */; }; - DE181A2C26C5C0CB000C0B9C /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE181A2B26C5C0CB000C0B9C /* WebSocket.swift */; }; - DE181A2E26C5C299000C0B9C /* SSLClientCertificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE181A2D26C5C299000C0B9C /* SSLClientCertificate.swift */; }; - DE181A3026C5C38E000C0B9C /* SSLSecurity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE181A2F26C5C38E000C0B9C /* SSLSecurity.swift */; }; - DE181A3226C5C401000C0B9C /* Compression.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE181A3126C5C401000C0B9C /* Compression.swift */; }; - DE181A3426C5D8D4000C0B9C /* CompressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE181A3326C5D8D4000C0B9C /* CompressionTests.swift */; }; - DE181A3626C5DE4F000C0B9C /* WebSocketStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE181A3526C5DE4F000C0B9C /* WebSocketStream.swift */; }; - DE3C7974260A646300D2F4FF /* dist in Resources */ = {isa = PBXBuildFile; fileRef = DE3C7973260A646300D2F4FF /* dist */; }; - DE56DC232683B2020090D6E4 /* DefaultInterceptorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE56DC222683B2020090D6E4 /* DefaultInterceptorProvider.swift */; }; - DE674D9D261CEEE4000E8FC8 /* c.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9B2061172591B3550020D1E0 /* c.txt */; }; - DE674D9E261CEEE4000E8FC8 /* b.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9B2061182591B3550020D1E0 /* b.txt */; }; - DE674D9F261CEEE4000E8FC8 /* a.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9B2061192591B3550020D1E0 /* a.txt */; }; - DE6B156A261505660068D642 /* GraphQLMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6B154A261505450068D642 /* GraphQLMap.swift */; }; - DE6B15AF26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE6B15AE26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift */; }; - DE6B15B126152BE10068D642 /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - DECD46D0262F64D000924527 /* StarWarsApolloSchemaDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DECD46CF262F64D000924527 /* StarWarsApolloSchemaDownloaderTests.swift */; }; - DECD46FB262F659500924527 /* ApolloCodegenLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7B6F47233C26D100F32205 /* ApolloCodegenLib.framework */; }; - DECD4736262F668500924527 /* UploadAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2DFBB624E1FA0D00ED3AE6 /* UploadAPI.framework */; }; - DECD47C3262F779800924527 /* ApolloUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B68353E2463481A00337AE6 /* ApolloUtils.framework */; }; - DECD490F262F81BF00924527 /* ApolloCodegenTestSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = DECD490D262F81BF00924527 /* ApolloCodegenTestSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DECD4921262F81CE00924527 /* CodegenTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BAEEC11234BBA9200808306 /* CodegenTestHelper.swift */; }; - DECD498F262F840700924527 /* ApolloCodegenTestSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DECD490B262F81BF00924527 /* ApolloCodegenTestSupport.framework */; }; - DECD4992262F841600924527 /* ApolloCodegenTestSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DECD490B262F81BF00924527 /* ApolloCodegenTestSupport.framework */; }; - DECD49C9262F88FE00924527 /* ApolloCodegenLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7B6F47233C26D100F32205 /* ApolloCodegenLib.framework */; }; - DECD49DB262F8AAA00924527 /* ApolloTestSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */; }; - DED45C2A2615319E0086EF63 /* DefaultInterceptorProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED45C292615319E0086EF63 /* DefaultInterceptorProviderTests.swift */; }; - DED45D73261675890086EF63 /* StarWarsServerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6ABC91EC0A9F7000017BE /* StarWarsServerTests.swift */; }; - DED45D852616759C0086EF63 /* TestConfigs.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED45D842616759C0086EF63 /* TestConfigs.swift */; }; - DED45D9626167F020086EF63 /* StarWarsServerCachingRoundtripTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6ABC81EC0A9F7000017BE /* StarWarsServerCachingRoundtripTests.swift */; }; - DED45DE9261B96B70086EF63 /* LoadQueryFromStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6ABC61EC0A9F7000017BE /* LoadQueryFromStoreTests.swift */; }; - DED45DEA261B96B70086EF63 /* WatchQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6ABCB1EC0A9F7000017BE /* WatchQueryTests.swift */; }; - DED45DEB261B96B70086EF63 /* SQLiteCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B60204E23FDFA9F00D0C8E0 /* SQLiteCacheTests.swift */; }; - DED45DEC261B96B70086EF63 /* CacheDependentInterceptorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BB4F5B12581AA50004F0BD6 /* CacheDependentInterceptorTests.swift */; }; - DED45DED261B96B70086EF63 /* StoreConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD03C2D25527CE6002227DC /* StoreConcurrencyTests.swift */; }; - DED45DEE261B96B70086EF63 /* FetchQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6ABC51EC0A9F7000017BE /* FetchQueryTests.swift */; }; - DED45DEF261B96B70086EF63 /* ReadWriteFromStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8622F71EC2004200C38162 /* ReadWriteFromStoreTests.swift */; }; - DED45E30261B972C0086EF63 /* CachePersistenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDAD423FDEC9B00ACD198 /* CachePersistenceTests.swift */; }; - DED45E6B261B9EAC0086EF63 /* SQLiteTestCacheProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDAEC23FDED9700ACD198 /* SQLiteTestCacheProvider.swift */; }; - DED45EC3261BA0ED0086EF63 /* WebSocketTransportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D90F1AF92479DEE5007A1534 /* WebSocketTransportTests.swift */; }; - DED45EC4261BA0ED0086EF63 /* SplitNetworkTransportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA8A23FDE92900ACD198 /* SplitNetworkTransportTests.swift */; }; - DED45EC7261BA0ED0086EF63 /* WebSocketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA8923FDE92900ACD198 /* WebSocketTests.swift */; }; - DED45EE4261BA1FB0086EF63 /* ApolloSQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7BDABF23FDEBB600ACD198 /* ApolloSQLite.framework */; }; - DED45EE5261BA1FB0086EF63 /* ApolloWebSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7BDA7D23FDE90400ACD198 /* ApolloWebSocket.framework */; }; - DED45EFE261CDA2A0086EF63 /* StarWarsSubscriptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA8823FDE92900ACD198 /* StarWarsSubscriptionTests.swift */; }; - DED45F17261CDA360086EF63 /* StarWarsWebSocketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA8C23FDE92900ACD198 /* StarWarsWebSocketTests.swift */; }; - DED45F30261CDB560086EF63 /* URLSessionClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4F4542244A2AD300C2CF7D /* URLSessionClientTests.swift */; }; - DED45F4A261CDBFC0086EF63 /* UploadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED45F49261CDBFC0086EF63 /* UploadTests.swift */; }; - DED45FD0261CE88C0086EF63 /* ApolloSQLite.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7BDABF23FDEBB600ACD198 /* ApolloSQLite.framework */; }; - DED45FE7261CE8C50086EF63 /* ApolloWebSocket.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B7BDA7D23FDE90400ACD198 /* ApolloWebSocket.framework */; }; - DED46000261CE9080086EF63 /* HTTPBinAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B4F4540244A2A9200C2CF7D /* HTTPBinAPI.swift */; }; - DED4600D261CE9260086EF63 /* TestFileHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B21FD762422C8CC00998B5C /* TestFileHelper.swift */; }; - DED4601A261CE9880086EF63 /* MockWebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7BDA8723FDE92900ACD198 /* MockWebSocket.swift */; }; - DED46035261CEA660086EF63 /* ApolloTestSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */; }; - DED46042261CEA8A0086EF63 /* TestServerURLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED45C172615308E0086EF63 /* TestServerURLs.swift */; }; - DED46051261CEAD20086EF63 /* StarWarsAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FCE2CFA1E6C213D00E34457 /* StarWarsAPI.framework */; }; - E6057F8B287D7E24007D84EC /* ResponsePathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6057F8A287D7E24007D84EC /* ResponsePathTests.swift */; }; - E616B6D126C3335600DB049E /* ExecutionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E616B6D026C3335600DB049E /* ExecutionTests.swift */; }; - E61DD76526D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61DD76426D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift */; }; - E63C03DF27BDDC3D00D675C6 /* SubscriptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63C03DD27BDDC3400D675C6 /* SubscriptionTests.swift */; }; - E63C03E227BDE00400D675C6 /* SubscriptionAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */; }; - E63C67A327C8AA2A00B1654E /* OperationMessageMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E658546527C6277600339378 /* OperationMessageMatchers.swift */; }; - E63F15CD27C96D6D006879ED /* WSProtocolTestsBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63F15CC27C96D6D006879ED /* WSProtocolTestsBase.swift */; }; - E657CDBA26FD01D4005834D6 /* ApolloSchemaInternalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E657CDB926FD01D4005834D6 /* ApolloSchemaInternalTests.swift */; }; - E658545B27C5C1EE00339378 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = E658545A27C5C1EE00339378 /* Nimble */; }; - E658545C27C5CA1C00339378 /* SubscriptionAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */; }; - E658545E27C6028100339378 /* MockWebSocketDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E658545D27C6028100339378 /* MockWebSocketDelegate.swift */; }; - E658546C27C77B8B00339378 /* GraphqlTransportWsProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E658546B27C77B8B00339378 /* GraphqlTransportWsProtocolTests.swift */; }; - E6630B8C26F0639B002D9E41 /* MockNetworkSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D79AB926EC05290094434A /* MockNetworkSession.swift */; }; - E6630B8E26F071F9002D9E41 /* SchemaRegistryApolloSchemaDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6630B8D26F071F9002D9E41 /* SchemaRegistryApolloSchemaDownloaderTests.swift */; }; - E6A19C6227BEDAE00099C6E3 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = E6A19C6127BEDAE00099C6E3 /* Nimble */; }; - E6A19C6727BF0E1C0099C6E3 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A19C6527BF0E1C0099C6E3 /* API.swift */; }; - E6A901D727BDAFA100931C9E /* SubscriptionAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = E6A901D627BDAFA100931C9E /* SubscriptionAPI.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E6A901DC27BDB01200931C9E /* Apollo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FC750441D2A532C00458D91 /* Apollo.framework */; }; - E6B9BDDB27C5693300CF911D /* GraphqlWsProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6B9BDDA27C5693300CF911D /* GraphqlWsProtocolTests.swift */; }; - E6C4267B26F16CB400904AD2 /* introspection_response.json in Resources */ = {isa = PBXBuildFile; fileRef = E6C4267A26F16CB400904AD2 /* introspection_response.json */; }; - E6D79AB826E9D59C0094434A /* URLDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D79AB626E97D0D0094434A /* URLDownloaderTests.swift */; }; - E86D8E05214B32FD0028EFE1 /* JSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86D8E03214B32DA0028EFE1 /* JSONTests.swift */; }; - F16D083C21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F16D083B21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift */; }; - F82E62E122BCD223000C311B /* AutomaticPersistedQueriesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F82E62E022BCD223000C311B /* AutomaticPersistedQueriesTests.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 9B2DFBC124E1FA1A00ED3AE6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9B2DFBCB24E201A000ED3AE6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B2DFBB524E1FA0D00ED3AE6; - remoteInfo = UploadAPI; - }; - 9B683548246348CB00337AE6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B68353D2463481A00337AE6; - remoteInfo = ApolloCore; - }; - 9B7BDAF723FDEE8400ACD198 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9B7BDAFB23FDEE9000ACD198 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9B8C3FBB248DAA0400707B13 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B68353D2463481A00337AE6; - remoteInfo = ApolloCore; - }; - 9BAEEC02234BB8FD00808306 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7B6F46233C26D100F32205; - remoteInfo = ApolloCodegenLib; - }; - 9F54C8BA255D760B0065AFD6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9F54C8DE255D76810065AFD6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9F8A95771EC0FC1200304A2D; - remoteInfo = ApolloTestSupport; - }; - 9F54C8E0255D76810065AFD6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FACA9B71F42E67200AE2DBD; - remoteInfo = GitHubAPI; - }; - 9F65B11F1EC106E80090B25F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9F8A958B1EC0FF9F00304A2D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9F8A95771EC0FC1200304A2D; - remoteInfo = ApolloTestSupport; - }; - 9FA5FBB51EC05CE900304A9D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9FACA9B91F42E67200AE2DBD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9FC750501D2A532D00458D91 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - 9FCE2D071E6C254000E34457 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FCE2CF91E6C213D00E34457; - remoteInfo = StarWarsAPI; - }; - 9FDE0741258F3B6100DC0CA5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FCE2CF91E6C213D00E34457; - remoteInfo = StarWarsAPI; - }; - DE05862726697B1D00265760 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DE058606266978A100265760; - remoteInfo = ApolloModels; - }; - DE6B15B226152BE10068D642 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; - DECD46F9262F659100924527 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7B6F46233C26D100F32205; - remoteInfo = ApolloCodegenLib; - }; - DECD4734262F668200924527 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B2DFBB524E1FA0D00ED3AE6; - remoteInfo = UploadAPI; - }; - DECD498D262F840100924527 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DECD490A262F81BF00924527; - remoteInfo = ApolloCodegenTestSupport; - }; - DECD4990262F841300924527 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DECD490A262F81BF00924527; - remoteInfo = ApolloCodegenTestSupport; - }; - DECD49C7262F88FA00924527 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7B6F46233C26D100F32205; - remoteInfo = ApolloCodegenLib; - }; - DECD49D9262F8AA500924527 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9F8A95771EC0FC1200304A2D; - remoteInfo = ApolloTestSupport; - }; - DED45E97261B9EFA0086EF63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7BDABE23FDEBB600ACD198; - remoteInfo = ApolloSQLite; - }; - DED45E99261B9F000086EF63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7BDA7C23FDE90400ACD198; - remoteInfo = ApolloWebSocket; - }; - DED45FCE261CE8890086EF63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7BDABE23FDEBB600ACD198; - remoteInfo = ApolloSQLite; - }; - DED45FD5261CE89C0086EF63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9B7BDA7C23FDE90400ACD198; - remoteInfo = ApolloWebSocket; - }; - DED46033261CEA610086EF63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9F8A95771EC0FC1200304A2D; - remoteInfo = ApolloTestSupport; - }; - DED4606A261CEDD10086EF63 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FCE2CF91E6C213D00E34457; - remoteInfo = StarWarsAPI; - }; - E63C03E027BDDFEF00D675C6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = E6A901D327BDAFA100931C9E; - remoteInfo = SubscriptionAPI; - }; - E6A901DE27BDB01200931C9E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9FC7503B1D2A532C00458D91 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9FC750431D2A532C00458D91; - remoteInfo = Apollo; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9B2DFBC324E1FA1A00ED3AE6 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 9B2DFBC024E1FA1A00ED3AE6 /* Apollo.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 19E9F6A826D5867E003AB80E /* OperationMessageIdCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationMessageIdCreator.swift; sourceTree = ""; }; - 19E9F6AA26D58A92003AB80E /* OperationMessageIdCreatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationMessageIdCreatorTests.swift; sourceTree = ""; }; - 2EE7FFCF276802E30035DC39 /* CacheKeyConstructionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheKeyConstructionTests.swift; sourceTree = ""; }; - 54DDB0911EA045870009DD99 /* InMemoryNormalizedCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InMemoryNormalizedCache.swift; sourceTree = ""; }; - 5AC6CA4222AAF7B200B7C94D /* GraphQLHTTPMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLHTTPMethod.swift; sourceTree = ""; }; - 5BB2C0222380836100774170 /* VersionNumberTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionNumberTests.swift; sourceTree = ""; }; - 90690D05224333DA00FC2E54 /* Apollo-Project-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Project-Debug.xcconfig"; sourceTree = ""; }; - 90690D06224333DA00FC2E54 /* Apollo-Target-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-Framework.xcconfig"; sourceTree = ""; }; - 90690D07224333DA00FC2E54 /* Apollo-Project-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Project-Release.xcconfig"; sourceTree = ""; }; - 90690D08224333DA00FC2E54 /* Apollo-Project-Performance-Testing.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Project-Performance-Testing.xcconfig"; sourceTree = ""; }; - 90690D0B2243345500FC2E54 /* Apollo-Target-Tests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-Tests.xcconfig"; sourceTree = ""; }; - 90690D142243363D00FC2E54 /* Apollo-Target-TestHost-iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-TestHost-iOS.xcconfig"; sourceTree = ""; }; - 90690D2122433C1900FC2E54 /* Apollo-Target-StarWarsAPI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-StarWarsAPI.xcconfig"; sourceTree = ""; }; - 90690D2222433C2800FC2E54 /* Apollo-Target-GitHubAPI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-GitHubAPI.xcconfig"; sourceTree = ""; }; - 90690D2422433C8000FC2E54 /* Apollo-Target-PerformanceTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-PerformanceTests.xcconfig"; sourceTree = ""; }; - 90690D2522433CAF00FC2E54 /* Apollo-Target-TestSupport.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-TestSupport.xcconfig"; sourceTree = ""; }; - 9B1CCDD82360F02C007C9032 /* Bundle+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Helpers.swift"; sourceTree = ""; }; - 9B2061172591B3550020D1E0 /* c.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = c.txt; sourceTree = ""; }; - 9B2061182591B3550020D1E0 /* b.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = b.txt; sourceTree = ""; }; - 9B2061192591B3550020D1E0 /* a.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = a.txt; sourceTree = ""; }; - 9B20614B2591B3700020D1E0 /* UploadMultipleFiles.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = UploadMultipleFiles.graphql; sourceTree = ""; }; - 9B20614C2591B3700020D1E0 /* operationIDs.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = operationIDs.json; sourceTree = ""; }; - 9B20614D2591B3700020D1E0 /* schema.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = schema.json; sourceTree = ""; }; - 9B20614E2591B3700020D1E0 /* UploadOneFile.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = UploadOneFile.graphql; sourceTree = ""; }; - 9B2061522591B3860020D1E0 /* Human.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = Human.graphql; sourceTree = ""; }; - 9B2061532591B3860020D1E0 /* HeroAndFriendsNames.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroAndFriendsNames.graphql; sourceTree = ""; }; - 9B2061542591B3860020D1E0 /* API.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = API.json; sourceTree = ""; }; - 9B2061552591B3860020D1E0 /* HeroFriendsOfFriends.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroFriendsOfFriends.graphql; sourceTree = ""; }; - 9B2061562591B3860020D1E0 /* HeroNameAndAppearsIn.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroNameAndAppearsIn.graphql; sourceTree = ""; }; - 9B2061572591B3860020D1E0 /* Starship.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = Starship.graphql; sourceTree = ""; }; - 9B2061582591B3860020D1E0 /* HeroAppearsIn.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroAppearsIn.graphql; sourceTree = ""; }; - 9B2061592591B3860020D1E0 /* HeroDetails.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroDetails.graphql; sourceTree = ""; }; - 9B20615A2591B3860020D1E0 /* SameHeroTwice.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = SameHeroTwice.graphql; sourceTree = ""; }; - 9B20615B2591B3860020D1E0 /* TwoHeroes.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = TwoHeroes.graphql; sourceTree = ""; }; - 9B20615C2591B3860020D1E0 /* HeroConditional.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroConditional.graphql; sourceTree = ""; }; - 9B20615D2591B3860020D1E0 /* Search.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = Search.graphql; sourceTree = ""; }; - 9B20615E2591B3860020D1E0 /* HeroName.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroName.graphql; sourceTree = ""; }; - 9B20615F2591B3860020D1E0 /* operationIDs.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = operationIDs.json; sourceTree = ""; }; - 9B2061602591B3860020D1E0 /* CharacterAndSubTypesFragments.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = CharacterAndSubTypesFragments.graphql; sourceTree = ""; }; - 9B2061612591B3860020D1E0 /* HeroTypeDependentAliasedField.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroTypeDependentAliasedField.graphql; sourceTree = ""; }; - 9B2061622591B3860020D1E0 /* schema.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = schema.json; sourceTree = ""; }; - 9B2061632591B3860020D1E0 /* SubscribeReview.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = SubscribeReview.graphql; sourceTree = ""; }; - 9B2061642591B3860020D1E0 /* HeroParentTypeDependentField.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = HeroParentTypeDependentField.graphql; sourceTree = ""; }; - 9B2061652591B3860020D1E0 /* CreateReviewForEpisode.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = CreateReviewForEpisode.graphql; sourceTree = ""; }; - 9B2061672591B3A50020D1E0 /* schema.docs.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = schema.docs.graphql; sourceTree = ""; }; - 9B2061692591B3A50020D1E0 /* IssuesAndCommentsForRepository.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = IssuesAndCommentsForRepository.graphql; sourceTree = ""; }; - 9B20616D2591B3A50020D1E0 /* RepoURL.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = RepoURL.graphql; sourceTree = ""; }; - 9B20616E2591B3A50020D1E0 /* Repository.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = Repository.graphql; sourceTree = ""; }; - 9B2061702591B3A50020D1E0 /* operationIDs.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = operationIDs.json; sourceTree = ""; }; - 9B21FD742422C29D00998B5C /* GraphQLFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLFileTests.swift; sourceTree = ""; }; - 9B21FD762422C8CC00998B5C /* TestFileHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestFileHelper.swift; sourceTree = ""; }; - 9B260BEA245A020300562176 /* ApolloInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloInterceptor.swift; sourceTree = ""; }; - 9B260BF0245A025400562176 /* HTTPRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPRequest.swift; sourceTree = ""; }; - 9B260BF2245A026F00562176 /* RequestChain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestChain.swift; sourceTree = ""; }; - 9B260BF4245A028D00562176 /* HTTPResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPResponse.swift; sourceTree = ""; }; - 9B260BF8245A030100562176 /* ResponseCodeInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseCodeInterceptor.swift; sourceTree = ""; }; - 9B260BFA245A031900562176 /* NetworkFetchInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkFetchInterceptor.swift; sourceTree = ""; }; - 9B260BFE245A054700562176 /* JSONRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONRequest.swift; sourceTree = ""; }; - 9B260C03245A090600562176 /* RequestChainNetworkTransport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestChainNetworkTransport.swift; sourceTree = ""; }; - 9B260C07245A437400562176 /* InterceptorProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterceptorProvider.swift; sourceTree = ""; }; - 9B260C09245A532500562176 /* JSONResponseParsingInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONResponseParsingInterceptor.swift; sourceTree = ""; }; - 9B2B66F32513FAFE00B53ABF /* CancellationHandlingInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancellationHandlingInterceptor.swift; sourceTree = ""; }; - 9B2DFBB624E1FA0D00ED3AE6 /* UploadAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UploadAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B2DFBC524E1FA3E00ED3AE6 /* UploadAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UploadAPI.h; sourceTree = ""; }; - 9B2DFBC624E1FA3E00ED3AE6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9B2DFBC824E1FA7E00ED3AE6 /* Apollo-Target-UploadAPI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-UploadAPI.xcconfig"; sourceTree = ""; }; - 9B2DFBCA24E2016800ED3AE6 /* UploadAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UploadAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B2DFBCE24E201DD00ED3AE6 /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; - 9B455CE22492D0A3002255A9 /* ApolloExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloExtension.swift; sourceTree = ""; }; - 9B455CE42492D0A3002255A9 /* Collection+Apollo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Collection+Apollo.swift"; sourceTree = ""; }; - 9B455CEA2492FB03002255A9 /* String+SHA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SHA.swift"; sourceTree = ""; }; - 9B4AA8AD239EFDC9003E1300 /* Apollo-Target-CodegenTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-CodegenTests.xcconfig"; sourceTree = ""; }; - 9B4F453E244A27B900C2CF7D /* URLSessionClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionClient.swift; sourceTree = ""; }; - 9B4F4540244A2A9200C2CF7D /* HTTPBinAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPBinAPI.swift; sourceTree = ""; }; - 9B4F4542244A2AD300C2CF7D /* URLSessionClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionClientTests.swift; sourceTree = ""; }; - 9B518C85235F8125004C426D /* CLIDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLIDownloader.swift; sourceTree = ""; }; - 9B518C88235F8AD4004C426D /* CLIDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLIDownloaderTests.swift; sourceTree = ""; }; - 9B518C8A235F8B05004C426D /* ApolloFilePathHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloFilePathHelper.swift; sourceTree = ""; }; - 9B554CC3247DC29A002F452A /* TaskData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskData.swift; sourceTree = ""; }; - 9B5A1EE3243284F300F066BB /* Package.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; tabWidth = 2; }; - 9B60204E23FDFA9F00D0C8E0 /* SQLiteCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteCacheTests.swift; sourceTree = ""; }; - 9B64F6752354D219002D1BB5 /* URL+QueryDict.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+QueryDict.swift"; sourceTree = ""; }; - 9B68353E2463481A00337AE6 /* ApolloUtils.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloUtils.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B68354A2463498D00337AE6 /* Apollo-Target-ApolloUtils.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Apollo-Target-ApolloUtils.xcconfig"; sourceTree = ""; }; - 9B68F0542416B33300E97318 /* LineByLineComparison.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineByLineComparison.swift; sourceTree = ""; }; - 9B68F06E241C649E00E97318 /* GraphQLOptional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLOptional.swift; sourceTree = ""; }; - 9B6CB23D238077B60007259D /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; - 9B708AAC2305884500604A11 /* ApolloClientProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloClientProtocol.swift; sourceTree = ""; }; - 9B74BCBE2333F4ED00508F84 /* run-bundled-codegen.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = "run-bundled-codegen.sh"; path = "scripts/run-bundled-codegen.sh"; sourceTree = SOURCE_ROOT; }; - 9B78C71B2326E859000C8C32 /* ErrorGenerationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorGenerationTests.swift; sourceTree = ""; }; - 9B7B6F47233C26D100F32205 /* ApolloCodegenLib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloCodegenLib.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B7B6F51233C26E400F32205 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9B7B6F55233C27A000F32205 /* Apollo-Target-ApolloCodegenLib.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Apollo-Target-ApolloCodegenLib.xcconfig"; sourceTree = ""; }; - 9B7B6F57233C287100F32205 /* ApolloCodegen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloCodegen.swift; sourceTree = ""; }; - 9B7B6F58233C287100F32205 /* ApolloCodegenOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloCodegenOptions.swift; sourceTree = ""; }; - 9B7B6F68233C2C0C00F32205 /* FileManager+Apollo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Apollo.swift"; sourceTree = ""; }; - 9B7BDA7D23FDE90400ACD198 /* ApolloWebSocket.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloWebSocket.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B7BDA8723FDE92900ACD198 /* MockWebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockWebSocket.swift; sourceTree = ""; }; - 9B7BDA8823FDE92900ACD198 /* StarWarsSubscriptionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsSubscriptionTests.swift; sourceTree = ""; }; - 9B7BDA8923FDE92900ACD198 /* WebSocketTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketTests.swift; sourceTree = ""; }; - 9B7BDA8A23FDE92900ACD198 /* SplitNetworkTransportTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitNetworkTransportTests.swift; sourceTree = ""; }; - 9B7BDA8C23FDE92900ACD198 /* StarWarsWebSocketTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsWebSocketTests.swift; sourceTree = ""; }; - 9B7BDA9423FDE94C00ACD198 /* WebSocketError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketError.swift; sourceTree = ""; }; - 9B7BDA9523FDE94C00ACD198 /* WebSocketTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketTask.swift; sourceTree = ""; }; - 9B7BDA9623FDE94C00ACD198 /* SplitNetworkTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitNetworkTransport.swift; sourceTree = ""; }; - 9B7BDA9723FDE94C00ACD198 /* OperationMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationMessage.swift; sourceTree = ""; }; - 9B7BDA9823FDE94C00ACD198 /* WebSocketClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketClient.swift; sourceTree = ""; }; - 9B7BDA9923FDE94C00ACD198 /* WebSocketTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebSocketTransport.swift; sourceTree = ""; }; - 9B7BDA9A23FDE94C00ACD198 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9B7BDAA323FDE98C00ACD198 /* ApolloWebSocket-Project-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "ApolloWebSocket-Project-Release.xcconfig"; sourceTree = ""; }; - 9B7BDAA423FDE98C00ACD198 /* ApolloWebSocket-Target-Framework.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "ApolloWebSocket-Target-Framework.xcconfig"; sourceTree = ""; }; - 9B7BDAA523FDE98C00ACD198 /* ApolloWebSocket-Project-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "ApolloWebSocket-Project-Debug.xcconfig"; sourceTree = ""; }; - 9B7BDABF23FDEBB600ACD198 /* ApolloSQLite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloSQLite.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9B7BDACD23FDEBE300ACD198 /* SQLiteSerialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteSerialization.swift; sourceTree = ""; }; - 9B7BDACE23FDEBE300ACD198 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9B7BDACF23FDEBE300ACD198 /* SQLiteNormalizedCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteNormalizedCache.swift; sourceTree = ""; }; - 9B7BDAD423FDEC9B00ACD198 /* CachePersistenceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachePersistenceTests.swift; sourceTree = ""; }; - 9B7BDAD823FDECB300ACD198 /* ApolloSQLite-Target-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "ApolloSQLite-Target-Framework.xcconfig"; sourceTree = ""; }; - 9B7BDAD923FDECB400ACD198 /* ApolloSQLite-Project-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "ApolloSQLite-Project-Debug.xcconfig"; sourceTree = ""; }; - 9B7BDADC23FDECB400ACD198 /* ApolloSQLite-Project-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "ApolloSQLite-Project-Release.xcconfig"; sourceTree = ""; }; - 9B7BDAEC23FDED9700ACD198 /* SQLiteTestCacheProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SQLiteTestCacheProvider.swift; sourceTree = ""; }; - 9B8110A723A1995D00688AC4 /* .keep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .keep; sourceTree = ""; }; - 9B8C3FB1248DA2EA00707B13 /* URL+Apollo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Apollo.swift"; sourceTree = ""; }; - 9B8C3FB4248DA3E000707B13 /* URLExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtensionsTests.swift; sourceTree = ""; }; - 9B95EDBF22CAA0AF00702BB2 /* GETTransformerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GETTransformerTests.swift; sourceTree = ""; }; - 9B96500824BE6201003C29C0 /* RequestChainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestChainTests.swift; sourceTree = ""; }; - 9B96500B24BE7239003C29C0 /* CacheReadInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheReadInterceptor.swift; sourceTree = ""; }; - 9B9BBAF224DB39D70021C30F /* UploadRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadRequest.swift; sourceTree = ""; }; - 9B9BBAF424DB4F890021C30F /* AutomaticPersistedQueryInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticPersistedQueryInterceptor.swift; sourceTree = ""; }; - 9B9BBB1624DB74720021C30F /* Apollo-Target-UploadAPI.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Apollo-Target-UploadAPI.xcconfig"; sourceTree = ""; }; - 9B9BBB1A24DB75E60021C30F /* UploadRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadRequestTests.swift; sourceTree = ""; }; - 9B9F16A626013DAB00FB2F31 /* SQLiteDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteDatabase.swift; sourceTree = ""; }; - 9B9F16B72601532500FB2F31 /* SQLiteDotSwiftDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteDotSwiftDatabase.swift; sourceTree = ""; }; - 9BA1244922D8A8EA00BF1D24 /* JSONSerialization+Sorting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSONSerialization+Sorting.swift"; sourceTree = ""; }; - 9BA3130D2302BEA5007B7FC5 /* DispatchQueue+Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Optional.swift"; sourceTree = ""; }; - 9BAEEBEB234663F200808306 /* ApolloSchemaDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloSchemaDownloader.swift; sourceTree = ""; }; - 9BAEEBED2346644600808306 /* ApolloSchemaDownloadConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloSchemaDownloadConfiguration.swift; sourceTree = ""; }; - 9BAEEBF023467E0A00808306 /* ApolloCLI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloCLI.swift; sourceTree = ""; }; - 9BAEEBF22346DDAD00808306 /* CodegenLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodegenLogger.swift; sourceTree = ""; }; - 9BAEEBF42346E90700808306 /* CLIExtractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLIExtractor.swift; sourceTree = ""; }; - 9BAEEBF62346F0A000808306 /* StaticString+Apollo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StaticString+Apollo.swift"; sourceTree = ""; }; - 9BAEEBFC234BB8FD00808306 /* ApolloCodegenTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ApolloCodegenTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 9BAEEC0C234BB95B00808306 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9BAEEC0D234BB95B00808306 /* FileManagerExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileManagerExtensionsTests.swift; sourceTree = ""; }; - 9BAEEC11234BBA9200808306 /* CodegenTestHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodegenTestHelper.swift; sourceTree = ""; }; - 9BAEEC14234C132600808306 /* CLIExtractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLIExtractorTests.swift; sourceTree = ""; }; - 9BAEEC16234C275600808306 /* ApolloSchemaPublicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloSchemaPublicTests.swift; sourceTree = ""; }; - 9BAEEC18234C297800808306 /* ApolloCodegenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloCodegenTests.swift; sourceTree = ""; }; - 9BB4F5B12581AA50004F0BD6 /* CacheDependentInterceptorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheDependentInterceptorTests.swift; sourceTree = ""; }; - 9BC139A224EDCA4400876D29 /* InterceptorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterceptorTests.swift; sourceTree = ""; }; - 9BC139A524EDCAD900876D29 /* BlindRetryingTestInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlindRetryingTestInterceptor.swift; sourceTree = ""; }; - 9BC139A724EDCE4F00876D29 /* RetryToCountThenSucceedInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryToCountThenSucceedInterceptor.swift; sourceTree = ""; }; - 9BC2D9D1233C6DC0007BD083 /* Basher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Basher.swift; sourceTree = ""; }; - 9BC742AB24CFB2FF0029282C /* ApolloErrorInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloErrorInterceptor.swift; sourceTree = ""; }; - 9BC742AD24CFB6450029282C /* CacheWriteInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheWriteInterceptor.swift; sourceTree = ""; }; - 9BCA8C0826618226004FF2F6 /* UntypedGraphQLRequestBodyCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UntypedGraphQLRequestBodyCreator.swift; sourceTree = ""; }; - 9BCF0CD923FC9CA50031D2A2 /* TestCacheProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCacheProvider.swift; sourceTree = ""; }; - 9BCF0CDA23FC9CA50031D2A2 /* ApolloTestSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApolloTestSupport.h; sourceTree = ""; }; - 9BCF0CDC23FC9CA50031D2A2 /* XCTAssertHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCTAssertHelpers.swift; sourceTree = ""; }; - 9BCF0CDD23FC9CA50031D2A2 /* MockURLSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockURLSession.swift; sourceTree = ""; }; - 9BCF0CDE23FC9CA50031D2A2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9BCF0CDF23FC9CA50031D2A2 /* MockNetworkTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockNetworkTransport.swift; sourceTree = ""; }; - 9BCF0CF123FC9F060031D2A2 /* StarWarsAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StarWarsAPI.h; sourceTree = ""; }; - 9BCF0CFC23FC9F060031D2A2 /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; - 9BCF0CFF23FC9F060031D2A2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9BDE43D022C6655200FD7C7F /* Cancellable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cancellable.swift; sourceTree = ""; }; - 9BDE43DE22C6708600FD7C7F /* GraphQLHTTPRequestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLHTTPRequestError.swift; sourceTree = ""; }; - 9BDF200C23FDC37600153E2B /* GitHubAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GitHubAPI.h; sourceTree = ""; }; - 9BDF201123FDC37600153E2B /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; - 9BDF201223FDC37600153E2B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9BE071AC2368D08700FA5952 /* Collection+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Helpers.swift"; sourceTree = ""; }; - 9BE071AE2368D34D00FA5952 /* Matchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Matchable.swift; sourceTree = ""; }; - 9BE74D3C23FB4A8E006D354F /* FileFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileFinder.swift; sourceTree = ""; }; - 9BEDC79D22E5D2CF00549BF6 /* RequestBodyCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBodyCreator.swift; sourceTree = ""; }; - 9BEEDC2724E351E5001D1294 /* MaxRetryInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaxRetryInterceptor.swift; sourceTree = ""; }; - 9BEEDC2A24E61995001D1294 /* TestURLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestURLs.swift; sourceTree = ""; }; - 9BF1A95022CA6E71005292C2 /* GraphQLGETTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLGETTransformer.swift; sourceTree = ""; }; - 9BF6C91725194D7B000D5B93 /* MultipartFormData+Testing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MultipartFormData+Testing.swift"; sourceTree = ""; }; - 9BF6C95225194EA5000D5B93 /* MultipartFormDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipartFormDataTests.swift; sourceTree = ""; }; - 9BF6C99B25195019000D5B93 /* String+IncludesForTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+IncludesForTesting.swift"; sourceTree = ""; }; - 9BFE8DA8265D5D8F000BBF81 /* URLDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLDownloader.swift; sourceTree = ""; }; - 9F1A9665258F34BB00A06EEB /* ApolloCodegenFrontend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloCodegenFrontend.swift; sourceTree = ""; }; - 9F1A9667258F34BB00A06EEB /* GraphQLSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLSchema.swift; sourceTree = ""; }; - 9F1A9668258F34BB00A06EEB /* CompilationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompilationResult.swift; sourceTree = ""; }; - 9F1A966A258F34BB00A06EEB /* JavaScriptBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JavaScriptBridge.swift; sourceTree = ""; }; - 9F1A96AF258F36B200A06EEB /* SchemaLoadingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchemaLoadingTests.swift; sourceTree = ""; }; - 9F21735A2568F3E200566121 /* PossiblyDeferredTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PossiblyDeferredTests.swift; sourceTree = ""; }; - 9F27D4631D40379500715680 /* JSONStandardTypeConversions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONStandardTypeConversions.swift; sourceTree = ""; }; - 9F295E301E27534800A24949 /* NormalizeQueryResults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NormalizeQueryResults.swift; sourceTree = ""; }; - 9F295E371E277B2A00A24949 /* GraphQLResultNormalizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLResultNormalizer.swift; sourceTree = ""; }; - 9F33D6A32566475600A1543F /* PossiblyDeferred.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PossiblyDeferred.swift; sourceTree = ""; }; - 9F3910262549741400AF54A6 /* MockGraphQLServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGraphQLServer.swift; sourceTree = ""; }; - 9F41CBEF25A3490600C02CB7 /* schema.graphqls */ = {isa = PBXFileReference; lastKnownFileType = text; path = schema.graphqls; sourceTree = ""; }; - 9F438D0B1E6C494C007BDC1A /* BatchedLoadTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatchedLoadTests.swift; sourceTree = ""; }; - 9F54C8B4255D760B0065AFD6 /* ApolloPerformanceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ApolloPerformanceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 9F54C8B6255D760B0065AFD6 /* ParsingPerformanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsingPerformanceTests.swift; sourceTree = ""; }; - 9F54C8B8255D760B0065AFD6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9F55347A1DE1DB2100E54264 /* ApolloStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloStore.swift; sourceTree = ""; }; - 9F578D8F1D8D2CB300C0EA36 /* HTTPURLResponse+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HTTPURLResponse+Helpers.swift"; sourceTree = ""; }; - 9F628E9425935BE600F94F9D /* GraphQLType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLType.swift; sourceTree = ""; }; - 9F628EB42593651B00F94F9D /* GraphQLValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLValue.swift; sourceTree = ""; }; - 9F62DF8D2590539A00E6E808 /* SchemaIntrospectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchemaIntrospectionTests.swift; sourceTree = ""; }; - 9F62DFAD2590557F00E6E808 /* DocumentParsingAndValidationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentParsingAndValidationTests.swift; sourceTree = ""; }; - 9F62DFBE2590560000E6E808 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; - 9F62DFCF2590710E00E6E808 /* GraphQLSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLSource.swift; sourceTree = ""; }; - 9F62E00F2590728000E6E808 /* CompilationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompilationTests.swift; sourceTree = ""; }; - 9F62E03E2590896400E6E808 /* GraphQLError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLError.swift; sourceTree = ""; }; - 9F68F9F025415827004F26D0 /* XCTestCase+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Helpers.swift"; sourceTree = ""; }; - 9F69FFA81D42855900E000B1 /* NetworkTransport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkTransport.swift; sourceTree = ""; }; - 9F7BA89822927A3700999B3B /* ResponsePath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponsePath.swift; sourceTree = ""; }; - 9F8622F71EC2004200C38162 /* ReadWriteFromStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadWriteFromStoreTests.swift; sourceTree = ""; }; - 9F8622F91EC2117C00C38162 /* FragmentConstructionAndConversionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FragmentConstructionAndConversionTests.swift; sourceTree = ""; }; - 9F86B68A1E6438D700B885FF /* GraphQLSelectionSetMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLSelectionSetMapper.swift; sourceTree = ""; }; - 9F86B68F1E65533D00B885FF /* GraphQLResponseGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLResponseGenerator.swift; sourceTree = ""; }; - 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloTestSupport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9F8F334B229044A200C0E83B /* Decoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decoding.swift; sourceTree = ""; }; - 9F91CF8E1F6C0DB2008DD0BE /* MutatingResultsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MutatingResultsTests.swift; sourceTree = ""; }; - 9FA6ABC51EC0A9F7000017BE /* FetchQueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchQueryTests.swift; sourceTree = ""; }; - 9FA6ABC61EC0A9F7000017BE /* LoadQueryFromStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadQueryFromStoreTests.swift; sourceTree = ""; }; - 9FA6ABC81EC0A9F7000017BE /* StarWarsServerCachingRoundtripTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsServerCachingRoundtripTests.swift; sourceTree = ""; }; - 9FA6ABC91EC0A9F7000017BE /* StarWarsServerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsServerTests.swift; sourceTree = ""; }; - 9FA6ABCB1EC0A9F7000017BE /* WatchQueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WatchQueryTests.swift; sourceTree = ""; }; - 9FA6F3671E65DF4700BF8D73 /* GraphQLResultAccumulator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLResultAccumulator.swift; sourceTree = ""; }; - 9FACA9C61F42E67200AE2DBD /* GitHubAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GitHubAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9FADC84E1E6B865E00C677E6 /* DataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoader.swift; sourceTree = ""; }; - 9FADC8531E6B86D900C677E6 /* DataLoaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataLoaderTests.swift; sourceTree = ""; }; - 9FBE0D3F25407B64002ED0B1 /* AsyncResultObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncResultObserver.swift; sourceTree = ""; }; - 9FC2333C1E66BBF7001E4541 /* GraphQLDependencyTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLDependencyTracker.swift; sourceTree = ""; }; - 9FC4B91F1D2A6F8D0046A641 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = ""; }; - 9FC750441D2A532C00458D91 /* Apollo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Apollo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9FC750471D2A532C00458D91 /* Apollo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Apollo.h; sourceTree = ""; }; - 9FC750491D2A532C00458D91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9FC7504E1D2A532D00458D91 /* ApolloTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ApolloTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 9FC750551D2A532D00458D91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9FC750601D2A59C300458D91 /* GraphQLOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLOperation.swift; sourceTree = ""; }; - 9FC750621D2A59F600458D91 /* ApolloClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloClient.swift; sourceTree = ""; }; - 9FC9A9BC1E2C271C0023C4D5 /* RecordSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecordSet.swift; sourceTree = ""; }; - 9FC9A9BE1E2C27FB0023C4D5 /* GraphQLResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLResult.swift; sourceTree = ""; }; - 9FC9A9C11E2D3CAF0023C4D5 /* InputValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputValue.swift; sourceTree = ""; }; - 9FC9A9C41E2D6CE70023C4D5 /* GraphQLSelectionSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLSelectionSet.swift; sourceTree = ""; }; - 9FC9A9C71E2EFE6E0023C4D5 /* CacheKeyForFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheKeyForFieldTests.swift; sourceTree = ""; }; - 9FC9A9CB1E2FD0760023C4D5 /* Record.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Record.swift; sourceTree = ""; }; - 9FC9A9D21E2FD48B0023C4D5 /* GraphQLError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLError.swift; sourceTree = ""; }; - 9FCDFD281E33D0CE007519DC /* GraphQLQueryWatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLQueryWatcher.swift; sourceTree = ""; }; - 9FCE2CED1E6BE2D800E34457 /* NormalizedCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NormalizedCache.swift; sourceTree = ""; }; - 9FCE2CFA1E6C213D00E34457 /* StarWarsAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StarWarsAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9FD03C2D25527CE6002227DC /* StoreConcurrencyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreConcurrencyTests.swift; sourceTree = ""; }; - 9FD15199255D7F30003BDAAA /* IssuesAndCommentsForRepository.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = IssuesAndCommentsForRepository.json; sourceTree = ""; }; - 9FEB050C1DB5732300DA3B44 /* JSONSerializationFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONSerializationFormat.swift; sourceTree = ""; }; - 9FEC15B31E681DAD00D461B4 /* GroupedSequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupedSequence.swift; sourceTree = ""; }; - 9FF90A5B1DDDEB100034C3B6 /* GraphQLResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLResponse.swift; sourceTree = ""; }; - 9FF90A5C1DDDEB100034C3B6 /* GraphQLExecutor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLExecutor.swift; sourceTree = ""; }; - 9FF90A6A1DDDEB420034C3B6 /* GraphQLMapEncodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLMapEncodingTests.swift; sourceTree = ""; }; - 9FF90A6B1DDDEB420034C3B6 /* ReadFieldValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadFieldValueTests.swift; sourceTree = ""; }; - 9FF90A6C1DDDEB420034C3B6 /* ParseQueryResponseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseQueryResponseTests.swift; sourceTree = ""; }; - C3279FC52345233000224790 /* TestCustomRequestBodyCreator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestCustomRequestBodyCreator.swift; sourceTree = ""; }; - C338DF1622DD9DE9006AF33E /* RequestBodyCreatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestBodyCreatorTests.swift; sourceTree = ""; }; - C377CCA822D798BD00572E03 /* GraphQLFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLFile.swift; sourceTree = ""; }; - C377CCAA22D7992E00572E03 /* MultipartFormData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipartFormData.swift; sourceTree = ""; }; - D87AC09E2564D60B0079FAA5 /* ApolloClientOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloClientOperationTests.swift; sourceTree = ""; }; - D90F1AF92479DEE5007A1534 /* WebSocketTransportTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketTransportTests.swift; sourceTree = ""; }; - DE058621266978A100265760 /* ApolloAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - DE0586222669793200265760 /* Apollo-Target-ApolloAPI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-ApolloAPI.xcconfig"; sourceTree = ""; }; - DE05862426697A8C00265760 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DE0586322669948500265760 /* InputValue+Evaluation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InputValue+Evaluation.swift"; sourceTree = ""; }; - DE0586382669985000265760 /* Dictionary+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Helpers.swift"; sourceTree = ""; }; - DE181A2B26C5C0CB000C0B9C /* WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocket.swift; sourceTree = ""; }; - DE181A2D26C5C299000C0B9C /* SSLClientCertificate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSLClientCertificate.swift; sourceTree = ""; }; - DE181A2F26C5C38E000C0B9C /* SSLSecurity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSLSecurity.swift; sourceTree = ""; }; - DE181A3126C5C401000C0B9C /* Compression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Compression.swift; sourceTree = ""; }; - DE181A3326C5D8D4000C0B9C /* CompressionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompressionTests.swift; sourceTree = ""; }; - DE181A3526C5DE4F000C0B9C /* WebSocketStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketStream.swift; sourceTree = ""; }; - DE3C7973260A646300D2F4FF /* dist */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dist; sourceTree = ""; }; - DE3C7B10260A6FC900D2F4FF /* SelectionSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionSet.swift; sourceTree = ""; }; - DE3C7B11260A6FC900D2F4FF /* ResponseDict.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseDict.swift; sourceTree = ""; }; - DE3C7B12260A6FC900D2F4FF /* FragmentProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FragmentProtocols.swift; sourceTree = ""; }; - DE3C7B13260A6FCA00D2F4FF /* GraphQLSchema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLSchema.swift; sourceTree = ""; }; - DE3C7B14260A6FCA00D2F4FF /* GraphQLEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLEnum.swift; sourceTree = ""; }; - DE3C7B15260A6FCA00D2F4FF /* ScalarTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScalarTypes.swift; sourceTree = ""; }; - DE56DC222683B2020090D6E4 /* DefaultInterceptorProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultInterceptorProvider.swift; sourceTree = ""; }; - DE664ED326602AF60054DB4F /* Selection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Selection.swift; sourceTree = ""; }; - DE664ED92666DF150054DB4F /* CacheReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheReference.swift; sourceTree = ""; }; - DE6B154A261505450068D642 /* GraphQLMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLMap.swift; sourceTree = ""; }; - DE6B15AC26152BE10068D642 /* ApolloServerIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ApolloServerIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - DE6B15AE26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultInterceptorProviderIntegrationTests.swift; sourceTree = ""; }; - DE6B15B026152BE10068D642 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DE6B15E826152CD80068D642 /* Apollo-Target-ServerIntegrationTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-ServerIntegrationTests.xcconfig"; sourceTree = ""; }; - DE6B15FA26152D210068D642 /* Workspace-Target-Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Target-Application.xcconfig"; sourceTree = ""; }; - DE6B15FB26152D210068D642 /* Workspace-Deployment-Targets.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Deployment-Targets.xcconfig"; sourceTree = ""; }; - DE6B15FC26152D210068D642 /* Workspace-Analysis.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Analysis.xcconfig"; sourceTree = ""; }; - DE6B15FD26152D210068D642 /* Project-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project-Release.xcconfig"; sourceTree = ""; }; - DE6B15FE26152D210068D642 /* Workspace-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Debug.xcconfig"; sourceTree = ""; }; - DE6B15FF26152D210068D642 /* Workspace-Universal-Test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Universal-Test.xcconfig"; sourceTree = ""; }; - DE6B160026152D210068D642 /* Workspace-Universal-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Universal-Framework.xcconfig"; sourceTree = ""; }; - DE6B160126152D210068D642 /* Workspace-Target-Test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Target-Test.xcconfig"; sourceTree = ""; }; - DE6B160226152D210068D642 /* Workspace-Code-Generation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Code-Generation.xcconfig"; sourceTree = ""; }; - DE6B160326152D210068D642 /* Workspace-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Release.xcconfig"; sourceTree = ""; }; - DE6B160426152D210068D642 /* Project-Version.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project-Version.xcconfig"; sourceTree = ""; }; - DE6B160526152D210068D642 /* Workspace-Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Warnings.xcconfig"; sourceTree = ""; }; - DE6B160626152D210068D642 /* Workspace-Target-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Target-Framework.xcconfig"; sourceTree = ""; }; - DE6B160726152D210068D642 /* Workspace-Search-Paths.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Search-Paths.xcconfig"; sourceTree = ""; }; - DE6B160826152D210068D642 /* Workspace-Universal-Target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Universal-Target.xcconfig"; sourceTree = ""; }; - DE6B160926152D210068D642 /* Workspace-Linking.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Linking.xcconfig"; sourceTree = ""; }; - DE6B160A26152D210068D642 /* Workspace-Language.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Language.xcconfig"; sourceTree = ""; }; - DE6B160B26152D210068D642 /* Project-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Project-Debug.xcconfig"; sourceTree = ""; }; - DE6B160C26152D210068D642 /* Workspace-Packaging.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Packaging.xcconfig"; sourceTree = ""; }; - DE6B160D26152D210068D642 /* Workspace-Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Shared.xcconfig"; sourceTree = ""; }; - DECD46CF262F64D000924527 /* StarWarsApolloSchemaDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarWarsApolloSchemaDownloaderTests.swift; sourceTree = ""; }; - DECD490B262F81BF00924527 /* ApolloCodegenTestSupport.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ApolloCodegenTestSupport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - DECD490D262F81BF00924527 /* ApolloCodegenTestSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApolloCodegenTestSupport.h; sourceTree = ""; }; - DECD490E262F81BF00924527 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DECD492F262F820500924527 /* Apollo-Target-CodegenTestSupport.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-CodegenTestSupport.xcconfig"; sourceTree = ""; }; - DECD4930262F824B00924527 /* Workspace-Target-TestSupport.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Target-TestSupport.xcconfig"; sourceTree = ""; }; - DECD493E262F82D600924527 /* Workspace-Target-Codegen.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Workspace-Target-Codegen.xcconfig"; sourceTree = ""; }; - DED45C172615308E0086EF63 /* TestServerURLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestServerURLs.swift; sourceTree = ""; }; - DED45C292615319E0086EF63 /* DefaultInterceptorProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultInterceptorProviderTests.swift; sourceTree = ""; }; - DED45C3B26165DD70086EF63 /* Apollo-IntegrationTestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Apollo-IntegrationTestPlan.xctestplan"; sourceTree = ""; }; - DED45D842616759C0086EF63 /* TestConfigs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestConfigs.swift; sourceTree = ""; }; - DED45DC7261682260086EF63 /* Apollo-UnitTestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Apollo-UnitTestPlan.xctestplan"; sourceTree = ""; }; - DED45F49261CDBFC0086EF63 /* UploadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadTests.swift; sourceTree = ""; }; - DED45FB1261CDE7D0086EF63 /* Apollo-PerformanceTestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Apollo-PerformanceTestPlan.xctestplan"; sourceTree = ""; }; - DED45FB2261CDE980086EF63 /* Apollo-CITestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Apollo-CITestPlan.xctestplan"; sourceTree = ""; }; - DED45FB3261CDEC60086EF63 /* Apollo-CodegenTestPlan.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Apollo-CodegenTestPlan.xctestplan"; sourceTree = ""; }; - E6057F8A287D7E24007D84EC /* ResponsePathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponsePathTests.swift; sourceTree = ""; }; - E616B6D026C3335600DB049E /* ExecutionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExecutionTests.swift; sourceTree = ""; }; - E61DD76426D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteDotSwiftDatabaseBehaviorTests.swift; sourceTree = ""; }; - E63C03D327BDB55900D675C6 /* subscription.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = subscription.graphql; sourceTree = ""; }; - E63C03D627BDBA8900D675C6 /* operation_ids.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = operation_ids.json; sourceTree = ""; }; - E63C03DB27BDD99100D675C6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E63C03DD27BDDC3400D675C6 /* SubscriptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionTests.swift; sourceTree = ""; }; - E63F15CC27C96D6D006879ED /* WSProtocolTestsBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WSProtocolTestsBase.swift; sourceTree = ""; }; - E657CDB926FD01D4005834D6 /* ApolloSchemaInternalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloSchemaInternalTests.swift; sourceTree = ""; }; - E658545D27C6028100339378 /* MockWebSocketDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWebSocketDelegate.swift; sourceTree = ""; }; - E658546527C6277600339378 /* OperationMessageMatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationMessageMatchers.swift; sourceTree = ""; }; - E658546B27C77B8B00339378 /* GraphqlTransportWsProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphqlTransportWsProtocolTests.swift; sourceTree = ""; }; - E661C2D427BDAC500078BEBD /* Apollo-Target-SubscriptionAPI.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apollo-Target-SubscriptionAPI.xcconfig"; sourceTree = ""; }; - E6630B8D26F071F9002D9E41 /* SchemaRegistryApolloSchemaDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SchemaRegistryApolloSchemaDownloaderTests.swift; sourceTree = ""; }; - E6A19C6527BF0E1C0099C6E3 /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; - E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SubscriptionAPI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E6A901D627BDAFA100931C9E /* SubscriptionAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubscriptionAPI.h; sourceTree = ""; }; - E6B9BDDA27C5693300CF911D /* GraphqlWsProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphqlWsProtocolTests.swift; sourceTree = ""; }; - E6C4267A26F16CB400904AD2 /* introspection_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = introspection_response.json; sourceTree = ""; }; - E6CE3DBA27BDB26E00B43E0A /* schema.graphqls */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = schema.graphqls; sourceTree = ""; }; - E6D79AB626E97D0D0094434A /* URLDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLDownloaderTests.swift; sourceTree = ""; }; - E6D79AB926EC05290094434A /* MockNetworkSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNetworkSession.swift; sourceTree = ""; }; - E86D8E03214B32DA0028EFE1 /* JSONTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONTests.swift; sourceTree = ""; }; - F16D083B21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryFromJSONBuildingTests.swift; sourceTree = ""; }; - F82E62E022BCD223000C311B /* AutomaticPersistedQueriesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutomaticPersistedQueriesTests.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 9B2DFBB324E1FA0D00ED3AE6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B2DFBBF24E1FA1A00ED3AE6 /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B68353B2463481A00337AE6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7B6F44233C26D100F32205 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - DECD47C3262F779800924527 /* ApolloUtils.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDA7A23FDE90400ACD198 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B7BDAFD23FDEE9300ACD198 /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDABC23FDEBB600ACD198 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B7BDAFA23FDEE8A00ACD198 /* Apollo.framework in Frameworks */, - 9B7BDAF623FDEE2600ACD198 /* SQLite in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9BAEEBF9234BB8FD00808306 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - DECD49DB262F8AAA00924527 /* ApolloTestSupport.framework in Frameworks */, - DECD4992262F841600924527 /* ApolloCodegenTestSupport.framework in Frameworks */, - 9FDE0752258F3BC200DC0CA5 /* StarWarsAPI.framework in Frameworks */, - 9BAEEC01234BB8FD00808306 /* ApolloCodegenLib.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F54C8B1255D760B0065AFD6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9F54C90F255D79C80065AFD6 /* ApolloTestSupport.framework in Frameworks */, - 9F54C910255D79C80065AFD6 /* GitHubAPI.framework in Frameworks */, - 9F54C8B9255D760B0065AFD6 /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F8A95741EC0FC1200304A2D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9F65B1211EC106F30090B25F /* Apollo.framework in Frameworks */, - DED45EE4261BA1FB0086EF63 /* ApolloSQLite.framework in Frameworks */, - DED45EE5261BA1FB0086EF63 /* ApolloWebSocket.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FACA9BD1F42E67200AE2DBD /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9FACA9BE1F42E67200AE2DBD /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FC7504B1D2A532D00458D91 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E658545C27C5CA1C00339378 /* SubscriptionAPI.framework in Frameworks */, - E658545B27C5C1EE00339378 /* Nimble in Frameworks */, - 9B2DFBCD24E201A800ED3AE6 /* UploadAPI.framework in Frameworks */, - 9FC7504F1D2A532D00458D91 /* Apollo.framework in Frameworks */, - 9F8A958D1EC0FFAB00304A2D /* ApolloTestSupport.framework in Frameworks */, - 9FCE2D091E6C254700E34457 /* StarWarsAPI.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FCE2CF61E6C213D00E34457 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9F438D071E6C2FD9007BDC1A /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE05861B266978A100265760 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE6B15A926152BE10068D642 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E63C03E227BDE00400D675C6 /* SubscriptionAPI.framework in Frameworks */, - DECD498F262F840700924527 /* ApolloCodegenTestSupport.framework in Frameworks */, - DECD4736262F668500924527 /* UploadAPI.framework in Frameworks */, - DECD46FB262F659500924527 /* ApolloCodegenLib.framework in Frameworks */, - DED46051261CEAD20086EF63 /* StarWarsAPI.framework in Frameworks */, - E6A19C6227BEDAE00099C6E3 /* Nimble in Frameworks */, - DED46035261CEA660086EF63 /* ApolloTestSupport.framework in Frameworks */, - DED45FE7261CE8C50086EF63 /* ApolloWebSocket.framework in Frameworks */, - DED45FD0261CE88C0086EF63 /* ApolloSQLite.framework in Frameworks */, - DE6B15B126152BE10068D642 /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DECD4908262F81BF00924527 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - DECD49C9262F88FE00924527 /* ApolloCodegenLib.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E6A901D127BDAFA100931C9E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E6A901DC27BDB01200931C9E /* Apollo.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 90690D04224333DA00FC2E54 /* Configuration */ = { - isa = PBXGroup; - children = ( - DE6B15F926152D210068D642 /* Shared */, - 90690D05224333DA00FC2E54 /* Apollo-Project-Debug.xcconfig */, - 90690D08224333DA00FC2E54 /* Apollo-Project-Performance-Testing.xcconfig */, - 90690D07224333DA00FC2E54 /* Apollo-Project-Release.xcconfig */, - 9B7B6F55233C27A000F32205 /* Apollo-Target-ApolloCodegenLib.xcconfig */, - 9B68354A2463498D00337AE6 /* Apollo-Target-ApolloUtils.xcconfig */, - DE0586222669793200265760 /* Apollo-Target-ApolloAPI.xcconfig */, - 9B4AA8AD239EFDC9003E1300 /* Apollo-Target-CodegenTests.xcconfig */, - 90690D06224333DA00FC2E54 /* Apollo-Target-Framework.xcconfig */, - 90690D2222433C2800FC2E54 /* Apollo-Target-GitHubAPI.xcconfig */, - 90690D2422433C8000FC2E54 /* Apollo-Target-PerformanceTests.xcconfig */, - 90690D2122433C1900FC2E54 /* Apollo-Target-StarWarsAPI.xcconfig */, - 90690D142243363D00FC2E54 /* Apollo-Target-TestHost-iOS.xcconfig */, - 90690D0B2243345500FC2E54 /* Apollo-Target-Tests.xcconfig */, - DE6B15E826152CD80068D642 /* Apollo-Target-ServerIntegrationTests.xcconfig */, - DECD492F262F820500924527 /* Apollo-Target-CodegenTestSupport.xcconfig */, - 90690D2522433CAF00FC2E54 /* Apollo-Target-TestSupport.xcconfig */, - 9B2DFBC824E1FA7E00ED3AE6 /* Apollo-Target-UploadAPI.xcconfig */, - E661C2D427BDAC500078BEBD /* Apollo-Target-SubscriptionAPI.xcconfig */, - 9B7BDAD923FDECB400ACD198 /* ApolloSQLite-Project-Debug.xcconfig */, - 9B7BDADC23FDECB400ACD198 /* ApolloSQLite-Project-Release.xcconfig */, - 9B7BDAD823FDECB300ACD198 /* ApolloSQLite-Target-Framework.xcconfig */, - 9B9BBB1624DB74720021C30F /* Apollo-Target-UploadAPI.xcconfig */, - 9B7BDAA523FDE98C00ACD198 /* ApolloWebSocket-Project-Debug.xcconfig */, - 9B7BDAA323FDE98C00ACD198 /* ApolloWebSocket-Project-Release.xcconfig */, - 9B7BDAA423FDE98C00ACD198 /* ApolloWebSocket-Target-Framework.xcconfig */, - ); - name = Configuration; - path = Configuration/Apollo; - sourceTree = ""; - }; - 9B0417812390320A00C9EC4E /* TestHelpers */ = { - isa = PBXGroup; - children = ( - 9BC139A524EDCAD900876D29 /* BlindRetryingTestInterceptor.swift */, - 9B2B66F32513FAFE00B53ABF /* CancellationHandlingInterceptor.swift */, - 9BF6C91725194D7B000D5B93 /* MultipartFormData+Testing.swift */, - 9BC139A724EDCE4F00876D29 /* RetryToCountThenSucceedInterceptor.swift */, - 9BF6C99B25195019000D5B93 /* String+IncludesForTesting.swift */, - C3279FC52345233000224790 /* TestCustomRequestBodyCreator.swift */, - 9B64F6752354D219002D1BB5 /* URL+QueryDict.swift */, - E658546527C6277600339378 /* OperationMessageMatchers.swift */, - ); - name = TestHelpers; - sourceTree = ""; - }; - 9B2061162591B3550020D1E0 /* Resources */ = { - isa = PBXGroup; - children = ( - 9B2061192591B3550020D1E0 /* a.txt */, - 9B2061182591B3550020D1E0 /* b.txt */, - 9B2061172591B3550020D1E0 /* c.txt */, - ); - path = Resources; - sourceTree = ""; - }; - 9B20614A2591B3700020D1E0 /* graphql */ = { - isa = PBXGroup; - children = ( - 9B20614C2591B3700020D1E0 /* operationIDs.json */, - 9B20614D2591B3700020D1E0 /* schema.json */, - 9B20614B2591B3700020D1E0 /* UploadMultipleFiles.graphql */, - 9B20614E2591B3700020D1E0 /* UploadOneFile.graphql */, - ); - path = graphql; - sourceTree = ""; - }; - 9B20614F2591B3860020D1E0 /* graphql */ = { - isa = PBXGroup; - children = ( - 9B2061542591B3860020D1E0 /* API.json */, - 9B2061602591B3860020D1E0 /* CharacterAndSubTypesFragments.graphql */, - 9B2061652591B3860020D1E0 /* CreateReviewForEpisode.graphql */, - 9B2061532591B3860020D1E0 /* HeroAndFriendsNames.graphql */, - 9B2061582591B3860020D1E0 /* HeroAppearsIn.graphql */, - 9B20615C2591B3860020D1E0 /* HeroConditional.graphql */, - 9B2061592591B3860020D1E0 /* HeroDetails.graphql */, - 9B2061552591B3860020D1E0 /* HeroFriendsOfFriends.graphql */, - 9B20615E2591B3860020D1E0 /* HeroName.graphql */, - 9B2061562591B3860020D1E0 /* HeroNameAndAppearsIn.graphql */, - 9B2061642591B3860020D1E0 /* HeroParentTypeDependentField.graphql */, - 9B2061612591B3860020D1E0 /* HeroTypeDependentAliasedField.graphql */, - 9B20615F2591B3860020D1E0 /* operationIDs.json */, - 9B20615A2591B3860020D1E0 /* SameHeroTwice.graphql */, - 9B2061622591B3860020D1E0 /* schema.json */, - 9F41CBEF25A3490600C02CB7 /* schema.graphqls */, - 9B20615D2591B3860020D1E0 /* Search.graphql */, - 9B2061572591B3860020D1E0 /* Starship.graphql */, - 9B2061632591B3860020D1E0 /* SubscribeReview.graphql */, - 9B2061502591B3860020D1E0 /* TestFolder */, - 9B20615B2591B3860020D1E0 /* TwoHeroes.graphql */, - ); - path = graphql; - sourceTree = ""; - }; - 9B2061502591B3860020D1E0 /* TestFolder */ = { - isa = PBXGroup; - children = ( - 9B2061512591B3860020D1E0 /* TestFolder2 */, - ); - path = TestFolder; - sourceTree = ""; - }; - 9B2061512591B3860020D1E0 /* TestFolder2 */ = { - isa = PBXGroup; - children = ( - 9B2061522591B3860020D1E0 /* Human.graphql */, - ); - path = TestFolder2; - sourceTree = ""; - }; - 9B2061662591B3A50020D1E0 /* graphql */ = { - isa = PBXGroup; - children = ( - 9B2061702591B3A50020D1E0 /* operationIDs.json */, - 9B2061682591B3A50020D1E0 /* Queries */, - 9B2061672591B3A50020D1E0 /* schema.docs.graphql */, - ); - path = graphql; - sourceTree = ""; - }; - 9B2061682591B3A50020D1E0 /* Queries */ = { - isa = PBXGroup; - children = ( - 9B2061692591B3A50020D1E0 /* IssuesAndCommentsForRepository.graphql */, - 9B20616A2591B3A50020D1E0 /* TestFolder */, - 9B20616E2591B3A50020D1E0 /* Repository.graphql */, - ); - path = Queries; - sourceTree = ""; - }; - 9B20616A2591B3A50020D1E0 /* TestFolder */ = { - isa = PBXGroup; - children = ( - 9B20616B2591B3A50020D1E0 /* TestFolder2 */, - ); - path = TestFolder; - sourceTree = ""; - }; - 9B20616B2591B3A50020D1E0 /* TestFolder2 */ = { - isa = PBXGroup; - children = ( - 9B20616C2591B3A50020D1E0 /* TestFolder3 */, - ); - path = TestFolder2; - sourceTree = ""; - }; - 9B20616C2591B3A50020D1E0 /* TestFolder3 */ = { - isa = PBXGroup; - children = ( - 9B20616D2591B3A50020D1E0 /* RepoURL.graphql */, - ); - path = TestFolder3; - sourceTree = ""; - }; - 9B260BE9245A01B900562176 /* Interceptor */ = { - isa = PBXGroup; - children = ( - 9BC742AF24D09F880029282C /* DefaultInterceptors */, - 9B260BEA245A020300562176 /* ApolloInterceptor.swift */, - 9BC742AB24CFB2FF0029282C /* ApolloErrorInterceptor.swift */, - 9B260C07245A437400562176 /* InterceptorProvider.swift */, - ); - name = Interceptor; - sourceTree = ""; - }; - 9B260C02245A07C200562176 /* RequestChain */ = { - isa = PBXGroup; - children = ( - 9B260BF0245A025400562176 /* HTTPRequest.swift */, - 9B260BFE245A054700562176 /* JSONRequest.swift */, - 9B9BBAF224DB39D70021C30F /* UploadRequest.swift */, - 9B260BF4245A028D00562176 /* HTTPResponse.swift */, - 9B260BF2245A026F00562176 /* RequestChain.swift */, - 9B260C03245A090600562176 /* RequestChainNetworkTransport.swift */, - ); - name = RequestChain; - sourceTree = ""; - }; - 9B2DFBC424E1FA3E00ED3AE6 /* UploadAPI */ = { - isa = PBXGroup; - children = ( - 9B2DFBCE24E201DD00ED3AE6 /* API.swift */, - 9B2DFBC524E1FA3E00ED3AE6 /* UploadAPI.h */, - 9B20614A2591B3700020D1E0 /* graphql */, - 9B2DFBC624E1FA3E00ED3AE6 /* Info.plist */, - ); - name = UploadAPI; - path = Sources/UploadAPI; - sourceTree = SOURCE_ROOT; - }; - 9B455CE82492D0A7002255A9 /* Extensions */ = { - isa = PBXGroup; - children = ( - 9B455CE22492D0A3002255A9 /* ApolloExtension.swift */, - 9B455CE42492D0A3002255A9 /* Collection+Apollo.swift */, - 9B455CEA2492FB03002255A9 /* String+SHA.swift */, - ); - name = Extensions; - sourceTree = ""; - }; - 9B6835472463486200337AE6 /* ApolloUtils */ = { - isa = PBXGroup; - children = ( - 9B6CB23D238077B60007259D /* Atomic.swift */, - 9B455CE82492D0A7002255A9 /* Extensions */, - ); - name = ApolloUtils; - path = Sources/ApolloUtils; - sourceTree = ""; - }; - 9B7B6F50233C26E400F32205 /* ApolloCodegenLib */ = { - isa = PBXGroup; - children = ( - 9FE1E54C2588C5E000AA967E /* Frontend */, - 9BCB585D240758B2002F766E /* Extensions */, - 9BD681332405F6BB000874CB /* Codegen */, - 9BD681322405F69C000874CB /* CLI */, - 9BD681342405F6D1000874CB /* SchemaDownload */, - 9B518C8A235F8B05004C426D /* ApolloFilePathHelper.swift */, - 9BAEEBF22346DDAD00808306 /* CodegenLogger.swift */, - 9BE74D3C23FB4A8E006D354F /* FileFinder.swift */, - 9B7B6F51233C26E400F32205 /* Info.plist */, - 9BFE8DA8265D5D8F000BBF81 /* URLDownloader.swift */, - 9BCA8C0826618226004FF2F6 /* UntypedGraphQLRequestBodyCreator.swift */, - ); - name = ApolloCodegenLib; - path = Sources/ApolloCodegenLib; - sourceTree = ""; - }; - 9B7BDA9323FDE94C00ACD198 /* ApolloWebSocket */ = { - isa = PBXGroup; - children = ( - E676C11F26CB05F90091215A /* DefaultImplementation */, - 9B7BDA9823FDE94C00ACD198 /* WebSocketClient.swift */, - 19E9F6A826D5867E003AB80E /* OperationMessageIdCreator.swift */, - 9B7BDA9723FDE94C00ACD198 /* OperationMessage.swift */, - 9B7BDA9623FDE94C00ACD198 /* SplitNetworkTransport.swift */, - 9B7BDA9423FDE94C00ACD198 /* WebSocketError.swift */, - 9B7BDA9523FDE94C00ACD198 /* WebSocketTask.swift */, - 9B7BDA9923FDE94C00ACD198 /* WebSocketTransport.swift */, - 9B7BDA9A23FDE94C00ACD198 /* Info.plist */, - ); - name = ApolloWebSocket; - path = Sources/ApolloWebSocket; - sourceTree = SOURCE_ROOT; - }; - 9B7BDACC23FDEBE300ACD198 /* ApolloSQLite */ = { - isa = PBXGroup; - children = ( - 9B7BDACF23FDEBE300ACD198 /* SQLiteNormalizedCache.swift */, - 9B7BDACD23FDEBE300ACD198 /* SQLiteSerialization.swift */, - 9B7BDACE23FDEBE300ACD198 /* Info.plist */, - 9B9F16A626013DAB00FB2F31 /* SQLiteDatabase.swift */, - 9B9F16B72601532500FB2F31 /* SQLiteDotSwiftDatabase.swift */, - ); - name = ApolloSQLite; - path = Sources/ApolloSQLite; - sourceTree = ""; - }; - 9B7BDAF923FDEE8A00ACD198 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; - 9B8110A623A1994000688AC4 /* SourcePackages */ = { - isa = PBXGroup; - children = ( - 9B8110A723A1995D00688AC4 /* .keep */, - ); - path = SourcePackages; - sourceTree = ""; - }; - 9BAEEC0A234BB95B00808306 /* ApolloCodegenTests */ = { - isa = PBXGroup; - children = ( - 9F1A96AE258F367100A06EEB /* Frontend */, - 9B8110A623A1994000688AC4 /* SourcePackages */, - E6BE04ED26F11B3500CF858D /* Resources */, - E657CDB926FD01D4005834D6 /* ApolloSchemaInternalTests.swift */, - 9BAEEC16234C275600808306 /* ApolloSchemaPublicTests.swift */, - 9BAEEC18234C297800808306 /* ApolloCodegenTests.swift */, - 9B518C88235F8AD4004C426D /* CLIDownloaderTests.swift */, - 9BAEEC14234C132600808306 /* CLIExtractorTests.swift */, - 9BAEEC0D234BB95B00808306 /* FileManagerExtensionsTests.swift */, - 9B68F0542416B33300E97318 /* LineByLineComparison.swift */, - 9B8C3FB4248DA3E000707B13 /* URLExtensionsTests.swift */, - 9BAEEC0C234BB95B00808306 /* Info.plist */, - E6D79AB626E97D0D0094434A /* URLDownloaderTests.swift */, - ); - path = ApolloCodegenTests; - sourceTree = ""; - }; - 9BC742AF24D09F880029282C /* DefaultInterceptors */ = { - isa = PBXGroup; - children = ( - DE56DC222683B2020090D6E4 /* DefaultInterceptorProvider.swift */, - 9BEEDC2724E351E5001D1294 /* MaxRetryInterceptor.swift */, - 9B96500B24BE7239003C29C0 /* CacheReadInterceptor.swift */, - 9B260BFA245A031900562176 /* NetworkFetchInterceptor.swift */, - 9B260BF8245A030100562176 /* ResponseCodeInterceptor.swift */, - 9B260C09245A532500562176 /* JSONResponseParsingInterceptor.swift */, - 9B9BBAF424DB4F890021C30F /* AutomaticPersistedQueryInterceptor.swift */, - 9BC742AD24CFB6450029282C /* CacheWriteInterceptor.swift */, - ); - name = DefaultInterceptors; - sourceTree = ""; - }; - 9BCB585D240758B2002F766E /* Extensions */ = { - isa = PBXGroup; - children = ( - 9B7B6F68233C2C0C00F32205 /* FileManager+Apollo.swift */, - 9BAEEBF62346F0A000808306 /* StaticString+Apollo.swift */, - 9B8C3FB1248DA2EA00707B13 /* URL+Apollo.swift */, - ); - name = Extensions; - sourceTree = ""; - }; - 9BCF0CD823FC9CA50031D2A2 /* ApolloTestSupport */ = { - isa = PBXGroup; - children = ( - 9BCF0CDA23FC9CA50031D2A2 /* ApolloTestSupport.h */, - 9BCF0CDE23FC9CA50031D2A2 /* Info.plist */, - 9BE071AE2368D34D00FA5952 /* Matchable.swift */, - 9BCF0CDD23FC9CA50031D2A2 /* MockURLSession.swift */, - 9BCF0CDF23FC9CA50031D2A2 /* MockNetworkTransport.swift */, - 9B7BDA8723FDE92900ACD198 /* MockWebSocket.swift */, - 9F3910262549741400AF54A6 /* MockGraphQLServer.swift */, - 9B21FD762422C8CC00998B5C /* TestFileHelper.swift */, - 9BCF0CD923FC9CA50031D2A2 /* TestCacheProvider.swift */, - 9B7BDAEC23FDED9700ACD198 /* SQLiteTestCacheProvider.swift */, - 9BEEDC2A24E61995001D1294 /* TestURLs.swift */, - 9BCF0CDC23FC9CA50031D2A2 /* XCTAssertHelpers.swift */, - 9FBE0D3F25407B64002ED0B1 /* AsyncResultObserver.swift */, - 9F68F9F025415827004F26D0 /* XCTestCase+Helpers.swift */, - 9B2061162591B3550020D1E0 /* Resources */, - E658545D27C6028100339378 /* MockWebSocketDelegate.swift */, - ); - name = ApolloTestSupport; - path = Sources/ApolloTestSupport; - sourceTree = SOURCE_ROOT; - }; - 9BCF0CE923FC9F060031D2A2 /* StarWarsAPI */ = { - isa = PBXGroup; - children = ( - 9BCF0CFC23FC9F060031D2A2 /* API.swift */, - 9BCF0CF123FC9F060031D2A2 /* StarWarsAPI.h */, - 9B20614F2591B3860020D1E0 /* graphql */, - 9BCF0CFF23FC9F060031D2A2 /* Info.plist */, - ); - name = StarWarsAPI; - path = Sources/StarWarsAPI; - sourceTree = SOURCE_ROOT; - }; - 9BD681322405F69C000874CB /* CLI */ = { - isa = PBXGroup; - children = ( - 9BAEEBF023467E0A00808306 /* ApolloCLI.swift */, - 9BC2D9D1233C6DC0007BD083 /* Basher.swift */, - 9BAEEBF42346E90700808306 /* CLIExtractor.swift */, - 9B518C85235F8125004C426D /* CLIDownloader.swift */, - ); - name = CLI; - sourceTree = ""; - }; - 9BD681332405F6BB000874CB /* Codegen */ = { - isa = PBXGroup; - children = ( - 9B7B6F57233C287100F32205 /* ApolloCodegen.swift */, - 9B7B6F58233C287100F32205 /* ApolloCodegenOptions.swift */, - ); - name = Codegen; - sourceTree = ""; - }; - 9BD681342405F6D1000874CB /* SchemaDownload */ = { - isa = PBXGroup; - children = ( - 9BAEEBEB234663F200808306 /* ApolloSchemaDownloader.swift */, - 9BAEEBED2346644600808306 /* ApolloSchemaDownloadConfiguration.swift */, - ); - name = SchemaDownload; - sourceTree = ""; - }; - 9BDE43D222C6658D00FD7C7F /* Protocols */ = { - isa = PBXGroup; - children = ( - 9BDE43D022C6655200FD7C7F /* Cancellable.swift */, - ); - name = Protocols; - sourceTree = ""; - }; - 9BDF200723FDC37600153E2B /* GitHubAPI */ = { - isa = PBXGroup; - children = ( - 9BDF200C23FDC37600153E2B /* GitHubAPI.h */, - 9BDF201123FDC37600153E2B /* API.swift */, - 9B2061662591B3A50020D1E0 /* graphql */, - 9BDF201223FDC37600153E2B /* Info.plist */, - ); - name = GitHubAPI; - path = Sources/GitHubAPI; - sourceTree = SOURCE_ROOT; - }; - 9F1A96AE258F367100A06EEB /* Frontend */ = { - isa = PBXGroup; - children = ( - 9F1A96AF258F36B200A06EEB /* SchemaLoadingTests.swift */, - 9F62DF8D2590539A00E6E808 /* SchemaIntrospectionTests.swift */, - 9F62DFAD2590557F00E6E808 /* DocumentParsingAndValidationTests.swift */, - 9F62E00F2590728000E6E808 /* CompilationTests.swift */, - 9F62DFBE2590560000E6E808 /* Helpers.swift */, - ); - path = Frontend; - sourceTree = ""; - }; - 9F27D4601D40363A00715680 /* Execution */ = { - isa = PBXGroup; - children = ( - 9F8F334B229044A200C0E83B /* Decoding.swift */, - 9FC2333C1E66BBF7001E4541 /* GraphQLDependencyTracker.swift */, - 9FF90A5C1DDDEB100034C3B6 /* GraphQLExecutor.swift */, - DE6B154A261505450068D642 /* GraphQLMap.swift */, - 9F86B68F1E65533D00B885FF /* GraphQLResponseGenerator.swift */, - 9FA6F3671E65DF4700BF8D73 /* GraphQLResultAccumulator.swift */, - 9F295E371E277B2A00A24949 /* GraphQLResultNormalizer.swift */, - 9FC9A9C41E2D6CE70023C4D5 /* GraphQLSelectionSet.swift */, - 9F86B68A1E6438D700B885FF /* GraphQLSelectionSetMapper.swift */, - DE664ED92666DF150054DB4F /* CacheReference.swift */, - 9F7BA89822927A3700999B3B /* ResponsePath.swift */, - DE0586322669948500265760 /* InputValue+Evaluation.swift */, - ); - name = Execution; - sourceTree = ""; - }; - 9F54C8B5255D760B0065AFD6 /* ApolloPerformanceTests */ = { - isa = PBXGroup; - children = ( - 9FD151B9255D7FAB003BDAAA /* Responses */, - 9F54C8B6255D760B0065AFD6 /* ParsingPerformanceTests.swift */, - 9F54C8B8255D760B0065AFD6 /* Info.plist */, - ); - path = ApolloPerformanceTests; - sourceTree = ""; - }; - 9FC4B9231D2BE4F00046A641 /* JSON */ = { - isa = PBXGroup; - children = ( - 9FC4B91F1D2A6F8D0046A641 /* JSON.swift */, - 9F27D4631D40379500715680 /* JSONStandardTypeConversions.swift */, - 9FEB050C1DB5732300DA3B44 /* JSONSerializationFormat.swift */, - 9BA1244922D8A8EA00BF1D24 /* JSONSerialization+Sorting.swift */, - ); - name = JSON; - sourceTree = ""; - }; - 9FC7503A1D2A532C00458D91 = { - isa = PBXGroup; - children = ( - 9B5A1EE3243284F300F066BB /* Package.swift */, - DE05862326697A8C00265760 /* ApolloAPI */, - 9B6835472463486200337AE6 /* ApolloUtils */, - 9FC750461D2A532C00458D91 /* Apollo */, - 9B7B6F50233C26E400F32205 /* ApolloCodegenLib */, - 9B7BDACC23FDEBE300ACD198 /* ApolloSQLite */, - 9B7BDA9323FDE94C00ACD198 /* ApolloWebSocket */, - 9FCE2CF41E6C20E000E34457 /* Tests */, - 9BDF200723FDC37600153E2B /* GitHubAPI */, - 9BCF0CE923FC9F060031D2A2 /* StarWarsAPI */, - 9B2DFBC424E1FA3E00ED3AE6 /* UploadAPI */, - E6A901D527BDAFA100931C9E /* SubscriptionAPI */, - DECD490C262F81BF00924527 /* ApolloCodegenTestSupport */, - 9B7BDAF923FDEE8A00ACD198 /* Frameworks */, - 90690D04224333DA00FC2E54 /* Configuration */, - 9FC750451D2A532C00458D91 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 9FC750451D2A532C00458D91 /* Products */ = { - isa = PBXGroup; - children = ( - 9FC750441D2A532C00458D91 /* Apollo.framework */, - 9FC7504E1D2A532D00458D91 /* ApolloTests.xctest */, - 9FCE2CFA1E6C213D00E34457 /* StarWarsAPI.framework */, - 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */, - 9FACA9C61F42E67200AE2DBD /* GitHubAPI.framework */, - 9B7B6F47233C26D100F32205 /* ApolloCodegenLib.framework */, - 9BAEEBFC234BB8FD00808306 /* ApolloCodegenTests.xctest */, - 9B7BDA7D23FDE90400ACD198 /* ApolloWebSocket.framework */, - 9B7BDABF23FDEBB600ACD198 /* ApolloSQLite.framework */, - 9B68353E2463481A00337AE6 /* ApolloUtils.framework */, - 9B2DFBB624E1FA0D00ED3AE6 /* UploadAPI.framework */, - 9B2DFBCA24E2016800ED3AE6 /* UploadAPI.framework */, - 9F54C8B4255D760B0065AFD6 /* ApolloPerformanceTests.xctest */, - DE6B15AC26152BE10068D642 /* ApolloServerIntegrationTests.xctest */, - DECD490B262F81BF00924527 /* ApolloCodegenTestSupport.framework */, - DE058621266978A100265760 /* ApolloAPI.framework */, - E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */, - ); - name = Products; - sourceTree = ""; - }; - 9FC750461D2A532C00458D91 /* Apollo */ = { - isa = PBXGroup; - children = ( - 9FC750621D2A59F600458D91 /* ApolloClient.swift */, - 9B708AAC2305884500604A11 /* ApolloClientProtocol.swift */, - 9FC750601D2A59C300458D91 /* GraphQLOperation.swift */, - 9FCDFD281E33D0CE007519DC /* GraphQLQueryWatcher.swift */, - 9FC9A9BE1E2C27FB0023C4D5 /* GraphQLResult.swift */, - 9FC9A9D21E2FD48B0023C4D5 /* GraphQLError.swift */, - 9F27D4601D40363A00715680 /* Execution */, - 9FC4B9231D2BE4F00046A641 /* JSON */, - 9FC9A9CE1E2FD0CC0023C4D5 /* Network */, - 9BDE43D222C6658D00FD7C7F /* Protocols */, - 9FC9A9CA1E2FD05C0023C4D5 /* Store */, - 9FE3F3961DADBD0D0072078F /* Supporting Files */, - 9FCDFD211E33A09F007519DC /* Utilities */, - ); - name = Apollo; - path = Sources/Apollo; - sourceTree = ""; - }; - 9FC750521D2A532D00458D91 /* ApolloTests */ = { - isa = PBXGroup; - children = ( - DED45DE8261B969F0086EF63 /* Cache */, - 9B0417812390320A00C9EC4E /* TestHelpers */, - DED45E9B261BA0CA0086EF63 /* WebSocket */, - D87AC09E2564D60B0079FAA5 /* ApolloClientOperationTests.swift */, - F82E62E022BCD223000C311B /* AutomaticPersistedQueriesTests.swift */, - 9F438D0B1E6C494C007BDC1A /* BatchedLoadTests.swift */, - 9FC9A9C71E2EFE6E0023C4D5 /* CacheKeyForFieldTests.swift */, - 9FADC8531E6B86D900C677E6 /* DataLoaderTests.swift */, - DED45C292615319E0086EF63 /* DefaultInterceptorProviderTests.swift */, - 9B78C71B2326E859000C8C32 /* ErrorGenerationTests.swift */, - E616B6D026C3335600DB049E /* ExecutionTests.swift */, - 9F8622F91EC2117C00C38162 /* FragmentConstructionAndConversionTests.swift */, - 9B95EDBF22CAA0AF00702BB2 /* GETTransformerTests.swift */, - 9B21FD742422C29D00998B5C /* GraphQLFileTests.swift */, - 9FF90A6A1DDDEB420034C3B6 /* GraphQLMapEncodingTests.swift */, - 9FC750551D2A532D00458D91 /* Info.plist */, - 9BC139A224EDCA4400876D29 /* InterceptorTests.swift */, - E86D8E03214B32DA0028EFE1 /* JSONTests.swift */, - 9BF6C95225194EA5000D5B93 /* MultipartFormDataTests.swift */, - 9F91CF8E1F6C0DB2008DD0BE /* MutatingResultsTests.swift */, - 9F295E301E27534800A24949 /* NormalizeQueryResults.swift */, - 9FF90A6C1DDDEB420034C3B6 /* ParseQueryResponseTests.swift */, - 9F21735A2568F3E200566121 /* PossiblyDeferredTests.swift */, - F16D083B21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift */, - 9FF90A6B1DDDEB420034C3B6 /* ReadFieldValueTests.swift */, - C338DF1622DD9DE9006AF33E /* RequestBodyCreatorTests.swift */, - 9B96500824BE6201003C29C0 /* RequestChainTests.swift */, - E61DD76426D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift */, - 9B9BBB1A24DB75E60021C30F /* UploadRequestTests.swift */, - 5BB2C0222380836100774170 /* VersionNumberTests.swift */, - E6057F8A287D7E24007D84EC /* ResponsePathTests.swift */, - ); - path = ApolloTests; - sourceTree = ""; - }; - 9FC9A9CA1E2FD05C0023C4D5 /* Store */ = { - isa = PBXGroup; - children = ( - 9F55347A1DE1DB2100E54264 /* ApolloStore.swift */, - 9FADC84E1E6B865E00C677E6 /* DataLoader.swift */, - 54DDB0911EA045870009DD99 /* InMemoryNormalizedCache.swift */, - 9FCE2CED1E6BE2D800E34457 /* NormalizedCache.swift */, - 9FC9A9CB1E2FD0760023C4D5 /* Record.swift */, - 9FC9A9BC1E2C271C0023C4D5 /* RecordSet.swift */, - ); - name = Store; - sourceTree = ""; - }; - 9FC9A9CE1E2FD0CC0023C4D5 /* Network */ = { - isa = PBXGroup; - children = ( - 9B260C02245A07C200562176 /* RequestChain */, - 9B260BE9245A01B900562176 /* Interceptor */, - C377CCA822D798BD00572E03 /* GraphQLFile.swift */, - 9BF1A95022CA6E71005292C2 /* GraphQLGETTransformer.swift */, - 5AC6CA4222AAF7B200B7C94D /* GraphQLHTTPMethod.swift */, - 9BDE43DE22C6708600FD7C7F /* GraphQLHTTPRequestError.swift */, - 9FF90A5B1DDDEB100034C3B6 /* GraphQLResponse.swift */, - C377CCAA22D7992E00572E03 /* MultipartFormData.swift */, - 9F69FFA81D42855900E000B1 /* NetworkTransport.swift */, - 9BEDC79D22E5D2CF00549BF6 /* RequestBodyCreator.swift */, - 9B4F453E244A27B900C2CF7D /* URLSessionClient.swift */, - 9B554CC3247DC29A002F452A /* TaskData.swift */, - ); - name = Network; - sourceTree = ""; - }; - 9FCDFD211E33A09F007519DC /* Utilities */ = { - isa = PBXGroup; - children = ( - 9B1CCDD82360F02C007C9032 /* Bundle+Helpers.swift */, - 9BE071AC2368D08700FA5952 /* Collection+Helpers.swift */, - 9BA3130D2302BEA5007B7FC5 /* DispatchQueue+Optional.swift */, - 9FEC15B31E681DAD00D461B4 /* GroupedSequence.swift */, - 9F578D8F1D8D2CB300C0EA36 /* HTTPURLResponse+Helpers.swift */, - 9F33D6A32566475600A1543F /* PossiblyDeferred.swift */, - DE0586382669985000265760 /* Dictionary+Helpers.swift */, - ); - name = Utilities; - sourceTree = ""; - }; - 9FCE2CF41E6C20E000E34457 /* Tests */ = { - isa = PBXGroup; - children = ( - DE4B66B726260EBE00AE90A9 /* TestPlans */, - 9FC750521D2A532D00458D91 /* ApolloTests */, - 9F54C8B5255D760B0065AFD6 /* ApolloPerformanceTests */, - 9BAEEC0A234BB95B00808306 /* ApolloCodegenTests */, - DE6B15AD26152BE10068D642 /* ApolloServerIntegrationTests */, - 9BCF0CD823FC9CA50031D2A2 /* ApolloTestSupport */, - ); - path = Tests; - sourceTree = ""; - }; - 9FD151B9255D7FAB003BDAAA /* Responses */ = { - isa = PBXGroup; - children = ( - 9FD15199255D7F30003BDAAA /* IssuesAndCommentsForRepository.json */, - ); - path = Responses; - sourceTree = ""; - }; - 9FE1E54C2588C5E000AA967E /* Frontend */ = { - isa = PBXGroup; - children = ( - 9F1A9665258F34BB00A06EEB /* ApolloCodegenFrontend.swift */, - 9F62DFCF2590710E00E6E808 /* GraphQLSource.swift */, - 9F1A9667258F34BB00A06EEB /* GraphQLSchema.swift */, - 9F628E9425935BE600F94F9D /* GraphQLType.swift */, - 9F628EB42593651B00F94F9D /* GraphQLValue.swift */, - 9F62E03E2590896400E6E808 /* GraphQLError.swift */, - 9F1A9668258F34BB00A06EEB /* CompilationResult.swift */, - 9F1A966A258F34BB00A06EEB /* JavaScriptBridge.swift */, - DE3C7973260A646300D2F4FF /* dist */, - ); - path = Frontend; - sourceTree = ""; - }; - 9FE3F3961DADBD0D0072078F /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 9FC750471D2A532C00458D91 /* Apollo.h */, - 9FC750491D2A532C00458D91 /* Info.plist */, - 9B74BCBE2333F4ED00508F84 /* run-bundled-codegen.sh */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - DE05862326697A8C00265760 /* ApolloAPI */ = { - isa = PBXGroup; - children = ( - 9FC9A9C11E2D3CAF0023C4D5 /* InputValue.swift */, - DE3C7B15260A6FCA00D2F4FF /* ScalarTypes.swift */, - DE3C7B0F260A6F7F00D2F4FF /* CodegenV1 */, - DE05862426697A8C00265760 /* Info.plist */, - ); - name = ApolloAPI; - path = Sources/ApolloAPI; - sourceTree = ""; - }; - DE3C7B0F260A6F7F00D2F4FF /* CodegenV1 */ = { - isa = PBXGroup; - children = ( - 9B68F06E241C649E00E97318 /* GraphQLOptional.swift */, - DE3C7B12260A6FC900D2F4FF /* FragmentProtocols.swift */, - DE3C7B14260A6FCA00D2F4FF /* GraphQLEnum.swift */, - DE3C7B13260A6FCA00D2F4FF /* GraphQLSchema.swift */, - DE3C7B11260A6FC900D2F4FF /* ResponseDict.swift */, - DE3C7B10260A6FC900D2F4FF /* SelectionSet.swift */, - DE664ED326602AF60054DB4F /* Selection.swift */, - ); - path = CodegenV1; - sourceTree = ""; - }; - DE4B66B726260EBE00AE90A9 /* TestPlans */ = { - isa = PBXGroup; - children = ( - DED45DC7261682260086EF63 /* Apollo-UnitTestPlan.xctestplan */, - DED45C3B26165DD70086EF63 /* Apollo-IntegrationTestPlan.xctestplan */, - DED45FB1261CDE7D0086EF63 /* Apollo-PerformanceTestPlan.xctestplan */, - DED45FB2261CDE980086EF63 /* Apollo-CITestPlan.xctestplan */, - DED45FB3261CDEC60086EF63 /* Apollo-CodegenTestPlan.xctestplan */, - ); - path = TestPlans; - sourceTree = ""; - }; - DE6B15AD26152BE10068D642 /* ApolloServerIntegrationTests */ = { - isa = PBXGroup; - children = ( - DED45D62261675620086EF63 /* TestHelpers */, - DE6B15AE26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift */, - 9FA6ABC91EC0A9F7000017BE /* StarWarsServerTests.swift */, - 9FA6ABC81EC0A9F7000017BE /* StarWarsServerCachingRoundtripTests.swift */, - 9B7BDA8823FDE92900ACD198 /* StarWarsSubscriptionTests.swift */, - 9B7BDA8C23FDE92900ACD198 /* StarWarsWebSocketTests.swift */, - 9B4F4542244A2AD300C2CF7D /* URLSessionClientTests.swift */, - DE6B15B026152BE10068D642 /* Info.plist */, - DED45F49261CDBFC0086EF63 /* UploadTests.swift */, - DECD46CF262F64D000924527 /* StarWarsApolloSchemaDownloaderTests.swift */, - E6630B8D26F071F9002D9E41 /* SchemaRegistryApolloSchemaDownloaderTests.swift */, - E63C03DD27BDDC3400D675C6 /* SubscriptionTests.swift */, - ); - path = ApolloServerIntegrationTests; - sourceTree = ""; - }; - DE6B15F926152D210068D642 /* Shared */ = { - isa = PBXGroup; - children = ( - DE6B15FA26152D210068D642 /* Workspace-Target-Application.xcconfig */, - DE6B15FB26152D210068D642 /* Workspace-Deployment-Targets.xcconfig */, - DE6B15FC26152D210068D642 /* Workspace-Analysis.xcconfig */, - DE6B15FD26152D210068D642 /* Project-Release.xcconfig */, - DE6B15FE26152D210068D642 /* Workspace-Debug.xcconfig */, - DE6B160826152D210068D642 /* Workspace-Universal-Target.xcconfig */, - DE6B15FF26152D210068D642 /* Workspace-Universal-Test.xcconfig */, - DE6B160026152D210068D642 /* Workspace-Universal-Framework.xcconfig */, - DECD4930262F824B00924527 /* Workspace-Target-TestSupport.xcconfig */, - DE6B160126152D210068D642 /* Workspace-Target-Test.xcconfig */, - DECD493E262F82D600924527 /* Workspace-Target-Codegen.xcconfig */, - DE6B160226152D210068D642 /* Workspace-Code-Generation.xcconfig */, - DE6B160326152D210068D642 /* Workspace-Release.xcconfig */, - DE6B160426152D210068D642 /* Project-Version.xcconfig */, - DE6B160526152D210068D642 /* Workspace-Warnings.xcconfig */, - DE6B160626152D210068D642 /* Workspace-Target-Framework.xcconfig */, - DE6B160726152D210068D642 /* Workspace-Search-Paths.xcconfig */, - DE6B160926152D210068D642 /* Workspace-Linking.xcconfig */, - DE6B160A26152D210068D642 /* Workspace-Language.xcconfig */, - DE6B160B26152D210068D642 /* Project-Debug.xcconfig */, - DE6B160C26152D210068D642 /* Workspace-Packaging.xcconfig */, - DE6B160D26152D210068D642 /* Workspace-Shared.xcconfig */, - ); - name = Shared; - path = Configuration/Shared; - sourceTree = SOURCE_ROOT; - }; - DECD490C262F81BF00924527 /* ApolloCodegenTestSupport */ = { - isa = PBXGroup; - children = ( - DECD490D262F81BF00924527 /* ApolloCodegenTestSupport.h */, - 9BAEEC11234BBA9200808306 /* CodegenTestHelper.swift */, - E6D79AB926EC05290094434A /* MockNetworkSession.swift */, - DECD490E262F81BF00924527 /* Info.plist */, - ); - name = ApolloCodegenTestSupport; - path = Sources/ApolloCodegenTestSupport; - sourceTree = ""; - }; - DED45D62261675620086EF63 /* TestHelpers */ = { - isa = PBXGroup; - children = ( - 9B4F4540244A2A9200C2CF7D /* HTTPBinAPI.swift */, - DED45C172615308E0086EF63 /* TestServerURLs.swift */, - DED45D842616759C0086EF63 /* TestConfigs.swift */, - ); - path = TestHelpers; - sourceTree = ""; - }; - DED45DE8261B969F0086EF63 /* Cache */ = { - isa = PBXGroup; - children = ( - DED45E2F261B971F0086EF63 /* SQLite */, - 9BB4F5B12581AA50004F0BD6 /* CacheDependentInterceptorTests.swift */, - 9FA6ABC51EC0A9F7000017BE /* FetchQueryTests.swift */, - 9FA6ABC61EC0A9F7000017BE /* LoadQueryFromStoreTests.swift */, - 9F8622F71EC2004200C38162 /* ReadWriteFromStoreTests.swift */, - 9FD03C2D25527CE6002227DC /* StoreConcurrencyTests.swift */, - 9FA6ABCB1EC0A9F7000017BE /* WatchQueryTests.swift */, - 2EE7FFCF276802E30035DC39 /* CacheKeyConstructionTests.swift */, - ); - path = Cache; - sourceTree = ""; - }; - DED45E2F261B971F0086EF63 /* SQLite */ = { - isa = PBXGroup; - children = ( - 9B60204E23FDFA9F00D0C8E0 /* SQLiteCacheTests.swift */, - 9B7BDAD423FDEC9B00ACD198 /* CachePersistenceTests.swift */, - ); - path = SQLite; - sourceTree = ""; - }; - DED45E9B261BA0CA0086EF63 /* WebSocket */ = { - isa = PBXGroup; - children = ( - 9B7BDA8923FDE92900ACD198 /* WebSocketTests.swift */, - 9B7BDA8A23FDE92900ACD198 /* SplitNetworkTransportTests.swift */, - D90F1AF92479DEE5007A1534 /* WebSocketTransportTests.swift */, - DE181A3326C5D8D4000C0B9C /* CompressionTests.swift */, - 19E9F6AA26D58A92003AB80E /* OperationMessageIdCreatorTests.swift */, - E6B9BDDA27C5693300CF911D /* GraphqlWsProtocolTests.swift */, - E658546B27C77B8B00339378 /* GraphqlTransportWsProtocolTests.swift */, - E63F15CC27C96D6D006879ED /* WSProtocolTestsBase.swift */, - ); - path = WebSocket; - sourceTree = ""; - }; - E676C11F26CB05F90091215A /* DefaultImplementation */ = { - isa = PBXGroup; - children = ( - DE181A3126C5C401000C0B9C /* Compression.swift */, - DE181A2B26C5C0CB000C0B9C /* WebSocket.swift */, - DE181A3526C5DE4F000C0B9C /* WebSocketStream.swift */, - DE181A2D26C5C299000C0B9C /* SSLClientCertificate.swift */, - DE181A2F26C5C38E000C0B9C /* SSLSecurity.swift */, - ); - path = DefaultImplementation; - sourceTree = ""; - }; - E6A901D527BDAFA100931C9E /* SubscriptionAPI */ = { - isa = PBXGroup; - children = ( - E6CE3DB927BDB26E00B43E0A /* graphql */, - E6A19C6527BF0E1C0099C6E3 /* API.swift */, - E63C03DB27BDD99100D675C6 /* Info.plist */, - E6A901D627BDAFA100931C9E /* SubscriptionAPI.h */, - ); - name = SubscriptionAPI; - path = Sources/SubscriptionAPI; - sourceTree = SOURCE_ROOT; - }; - E6BE04ED26F11B3500CF858D /* Resources */ = { - isa = PBXGroup; - children = ( - E6C4267A26F16CB400904AD2 /* introspection_response.json */, - ); - path = Resources; - sourceTree = ""; - }; - E6CE3DB927BDB26E00B43E0A /* graphql */ = { - isa = PBXGroup; - children = ( - E63C03D627BDBA8900D675C6 /* operation_ids.json */, - E6CE3DBA27BDB26E00B43E0A /* schema.graphqls */, - E63C03D327BDB55900D675C6 /* subscription.graphql */, - ); - path = graphql; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 9B2DFBB124E1FA0D00ED3AE6 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B2DFBC724E1FA4800ED3AE6 /* UploadAPI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B6835392463481A00337AE6 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7B6F42233C26D100F32205 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDA7823FDE90400ACD198 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDABA23FDEBB600ACD198 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F8A95751EC0FC1200304A2D /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BCF0CE623FC9D7B0031D2A2 /* ApolloTestSupport.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FACA9BF1F42E67200AE2DBD /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BDF201323FDC37600153E2B /* GitHubAPI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FC750411D2A532C00458D91 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 9FC750481D2A532C00458D91 /* Apollo.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FCE2CF71E6C213D00E34457 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BCF0D0123FC9F060031D2A2 /* StarWarsAPI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE058607266978A100265760 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DECD4906262F81BF00924527 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - DECD490F262F81BF00924527 /* ApolloCodegenTestSupport.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E6A901CF27BDAFA100931C9E /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - E6A901D727BDAFA100931C9E /* SubscriptionAPI.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 9B2DFBB524E1FA0D00ED3AE6 /* UploadAPI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9B2DFBBE24E1FA0D00ED3AE6 /* Build configuration list for PBXNativeTarget "UploadAPI" */; - buildPhases = ( - 9B2DFBB124E1FA0D00ED3AE6 /* Headers */, - 9B2DFBB224E1FA0D00ED3AE6 /* Sources */, - 9B2DFBB324E1FA0D00ED3AE6 /* Frameworks */, - 9B2DFBB424E1FA0D00ED3AE6 /* Resources */, - 9B2DFBC324E1FA1A00ED3AE6 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 9B2DFBC224E1FA1A00ED3AE6 /* PBXTargetDependency */, - ); - name = UploadAPI; - productName = UploadAPI; - productReference = 9B2DFBB624E1FA0D00ED3AE6 /* UploadAPI.framework */; - productType = "com.apple.product-type.framework"; - }; - 9B68353D2463481A00337AE6 /* ApolloUtils */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9B6835462463481A00337AE6 /* Build configuration list for PBXNativeTarget "ApolloUtils" */; - buildPhases = ( - 9B6835392463481A00337AE6 /* Headers */, - 9B68353A2463481A00337AE6 /* Sources */, - 9B68353B2463481A00337AE6 /* Frameworks */, - 9B68353C2463481A00337AE6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ApolloUtils; - productName = ApolloCore; - productReference = 9B68353E2463481A00337AE6 /* ApolloUtils.framework */; - productType = "com.apple.product-type.framework"; - }; - 9B7B6F46233C26D100F32205 /* ApolloCodegenLib */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9B7B6F4F233C26D200F32205 /* Build configuration list for PBXNativeTarget "ApolloCodegenLib" */; - buildPhases = ( - 9B7B6F42233C26D100F32205 /* Headers */, - 9B7B6F43233C26D100F32205 /* Sources */, - 9B7B6F44233C26D100F32205 /* Frameworks */, - 9B7B6F45233C26D100F32205 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9B683549246348CB00337AE6 /* PBXTargetDependency */, - ); - name = ApolloCodegenLib; - packageProductDependencies = ( - ); - productName = ApolloCodegenLib; - productReference = 9B7B6F47233C26D100F32205 /* ApolloCodegenLib.framework */; - productType = "com.apple.product-type.framework"; - }; - 9B7BDA7C23FDE90400ACD198 /* ApolloWebSocket */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9B7BDA8223FDE90400ACD198 /* Build configuration list for PBXNativeTarget "ApolloWebSocket" */; - buildPhases = ( - 9B7BDA7823FDE90400ACD198 /* Headers */, - 9B7BDA7923FDE90400ACD198 /* Sources */, - 9B7BDA7A23FDE90400ACD198 /* Frameworks */, - 9B7BDA7B23FDE90400ACD198 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9B7BDAFC23FDEE9000ACD198 /* PBXTargetDependency */, - ); - name = ApolloWebSocket; - packageProductDependencies = ( - ); - productName = ApolloWebSocket; - productReference = 9B7BDA7D23FDE90400ACD198 /* ApolloWebSocket.framework */; - productType = "com.apple.product-type.framework"; - }; - 9B7BDABE23FDEBB600ACD198 /* ApolloSQLite */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9B7BDAC823FDEBB600ACD198 /* Build configuration list for PBXNativeTarget "ApolloSQLite" */; - buildPhases = ( - 9B7BDABA23FDEBB600ACD198 /* Headers */, - 9B7BDABB23FDEBB600ACD198 /* Sources */, - 9B7BDABC23FDEBB600ACD198 /* Frameworks */, - 9B7BDABD23FDEBB600ACD198 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9B7BDB1723FDF10300ACD198 /* PBXTargetDependency */, - 9B7BDAF823FDEE8400ACD198 /* PBXTargetDependency */, - ); - name = ApolloSQLite; - packageProductDependencies = ( - 9B7BDAF523FDEE2600ACD198 /* SQLite */, - ); - productName = ApolloSQLite; - productReference = 9B7BDABF23FDEBB600ACD198 /* ApolloSQLite.framework */; - productType = "com.apple.product-type.framework"; - }; - 9BAEEBFB234BB8FD00808306 /* ApolloCodegenTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9BAEEC07234BB8FD00808306 /* Build configuration list for PBXNativeTarget "ApolloCodegenTests" */; - buildPhases = ( - 9BAEEBF8234BB8FD00808306 /* Sources */, - 9BAEEBF9234BB8FD00808306 /* Frameworks */, - 9BAEEBFA234BB8FD00808306 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - DECD49DA262F8AA500924527 /* PBXTargetDependency */, - DECD4991262F841300924527 /* PBXTargetDependency */, - 9FDE0742258F3B6100DC0CA5 /* PBXTargetDependency */, - 9BAEEC03234BB8FD00808306 /* PBXTargetDependency */, - ); - name = ApolloCodegenTests; - productName = ApolloCodegenTests; - productReference = 9BAEEBFC234BB8FD00808306 /* ApolloCodegenTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 9F54C8B3255D760B0065AFD6 /* ApolloPerformanceTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9F54C8BC255D760B0065AFD6 /* Build configuration list for PBXNativeTarget "ApolloPerformanceTests" */; - buildPhases = ( - 9F54C8B0255D760B0065AFD6 /* Sources */, - 9F54C8B1255D760B0065AFD6 /* Frameworks */, - 9F54C8B2255D760B0065AFD6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9F54C8DF255D76810065AFD6 /* PBXTargetDependency */, - 9F54C8E1255D76810065AFD6 /* PBXTargetDependency */, - 9F54C8BB255D760B0065AFD6 /* PBXTargetDependency */, - ); - name = ApolloPerformanceTests; - productName = ApolloPerformanceTests; - productReference = 9F54C8B4255D760B0065AFD6 /* ApolloPerformanceTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 9F8A95771EC0FC1200304A2D /* ApolloTestSupport */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9F8A95801EC0FC1200304A2D /* Build configuration list for PBXNativeTarget "ApolloTestSupport" */; - buildPhases = ( - 9F8A95731EC0FC1200304A2D /* Sources */, - 9F8A95741EC0FC1200304A2D /* Frameworks */, - 9F8A95751EC0FC1200304A2D /* Headers */, - DE674D9C261CEEDA000E8FC8 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9F65B1201EC106E80090B25F /* PBXTargetDependency */, - DED45E98261B9EFA0086EF63 /* PBXTargetDependency */, - DED45E96261B9EE30086EF63 /* PBXTargetDependency */, - DED45E9A261B9F000086EF63 /* PBXTargetDependency */, - ); - name = ApolloTestSupport; - packageProductDependencies = ( - ); - productName = ApolloTestSupport; - productReference = 9F8A95781EC0FC1200304A2D /* ApolloTestSupport.framework */; - productType = "com.apple.product-type.framework"; - }; - 9FACA9B71F42E67200AE2DBD /* GitHubAPI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9FACA9C21F42E67200AE2DBD /* Build configuration list for PBXNativeTarget "GitHubAPI" */; - buildPhases = ( - 9FACA9BA1F42E67200AE2DBD /* Generate Apollo Client API */, - 9FACA9BB1F42E67200AE2DBD /* Sources */, - 9FACA9BD1F42E67200AE2DBD /* Frameworks */, - 9FACA9BF1F42E67200AE2DBD /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - 9FACA9B81F42E67200AE2DBD /* PBXTargetDependency */, - ); - name = GitHubAPI; - productName = StarWarsAPI; - productReference = 9FACA9C61F42E67200AE2DBD /* GitHubAPI.framework */; - productType = "com.apple.product-type.framework"; - }; - 9FC750431D2A532C00458D91 /* Apollo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9FC750581D2A532D00458D91 /* Build configuration list for PBXNativeTarget "Apollo" */; - buildPhases = ( - 90690D322243442F00FC2E54 /* Ensure no build settings are in the Xcode project */, - 9FC7503F1D2A532C00458D91 /* Sources */, - 9FC750411D2A532C00458D91 /* Headers */, - 9FC750421D2A532C00458D91 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - DE05862826697B1D00265760 /* PBXTargetDependency */, - 9B8C3FBC248DAA0400707B13 /* PBXTargetDependency */, - ); - name = Apollo; - packageProductDependencies = ( - ); - productName = Apollo; - productReference = 9FC750441D2A532C00458D91 /* Apollo.framework */; - productType = "com.apple.product-type.framework"; - }; - 9FC7504D1D2A532D00458D91 /* ApolloTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9FC7505B1D2A532D00458D91 /* Build configuration list for PBXNativeTarget "ApolloTests" */; - buildPhases = ( - 9FC7504A1D2A532D00458D91 /* Sources */, - 9FC7504B1D2A532D00458D91 /* Frameworks */, - C304EBD522DDC87800748F72 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9B2DFBCC24E201A000ED3AE6 /* PBXTargetDependency */, - 9FC750511D2A532D00458D91 /* PBXTargetDependency */, - 9F8A958C1EC0FF9F00304A2D /* PBXTargetDependency */, - 9FCE2D081E6C254000E34457 /* PBXTargetDependency */, - ); - name = ApolloTests; - packageProductDependencies = ( - E658545A27C5C1EE00339378 /* Nimble */, - ); - productName = ApolloTests; - productReference = 9FC7504E1D2A532D00458D91 /* ApolloTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 9FCE2CF91E6C213D00E34457 /* StarWarsAPI */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9FCE2D031E6C213D00E34457 /* Build configuration list for PBXNativeTarget "StarWarsAPI" */; - buildPhases = ( - 9FCE2D061E6C251100E34457 /* Generate Apollo Client API */, - 9FCE2CF51E6C213D00E34457 /* Sources */, - 9FCE2CF61E6C213D00E34457 /* Frameworks */, - 9FCE2CF71E6C213D00E34457 /* Headers */, - 9F62DF3F258F45BF00E6E808 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 9FA5FBB61EC05CE900304A9D /* PBXTargetDependency */, - ); - name = StarWarsAPI; - productName = StarWarsAPI; - productReference = 9FCE2CFA1E6C213D00E34457 /* StarWarsAPI.framework */; - productType = "com.apple.product-type.framework"; - }; - DE058606266978A100265760 /* ApolloAPI */ = { - isa = PBXNativeTarget; - buildConfigurationList = DE05861D266978A100265760 /* Build configuration list for PBXNativeTarget "ApolloAPI" */; - buildPhases = ( - DE058607266978A100265760 /* Headers */, - DE058608266978A100265760 /* Sources */, - DE05861B266978A100265760 /* Frameworks */, - DE05861C266978A100265760 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ApolloAPI; - productName = ApolloCore; - productReference = DE058621266978A100265760 /* ApolloAPI.framework */; - productType = "com.apple.product-type.framework"; - }; - DE6B15AB26152BE10068D642 /* ApolloServerIntegrationTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = DE6B15B726152BE10068D642 /* Build configuration list for PBXNativeTarget "ApolloServerIntegrationTests" */; - buildPhases = ( - DE6B15A826152BE10068D642 /* Sources */, - DE6B15A926152BE10068D642 /* Frameworks */, - DE6B15AA26152BE10068D642 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - E63C03E127BDDFEF00D675C6 /* PBXTargetDependency */, - DECD498E262F840100924527 /* PBXTargetDependency */, - DECD4735262F668200924527 /* PBXTargetDependency */, - DECD46FA262F659100924527 /* PBXTargetDependency */, - DED46034261CEA610086EF63 /* PBXTargetDependency */, - DED45FCF261CE8890086EF63 /* PBXTargetDependency */, - DED45FD6261CE89C0086EF63 /* PBXTargetDependency */, - DE6B15B326152BE10068D642 /* PBXTargetDependency */, - DED4606B261CEDD10086EF63 /* PBXTargetDependency */, - ); - name = ApolloServerIntegrationTests; - packageProductDependencies = ( - E6A19C6127BEDAE00099C6E3 /* Nimble */, - ); - productName = ApolloServerIntegrationTests; - productReference = DE6B15AC26152BE10068D642 /* ApolloServerIntegrationTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - DECD490A262F81BF00924527 /* ApolloCodegenTestSupport */ = { - isa = PBXNativeTarget; - buildConfigurationList = DECD4910262F81BF00924527 /* Build configuration list for PBXNativeTarget "ApolloCodegenTestSupport" */; - buildPhases = ( - DECD4906262F81BF00924527 /* Headers */, - DECD4907262F81BF00924527 /* Sources */, - DECD4908262F81BF00924527 /* Frameworks */, - DECD4909262F81BF00924527 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - DECD49C8262F88FA00924527 /* PBXTargetDependency */, - ); - name = ApolloCodegenTestSupport; - productName = ApolloCodegenTestSupport; - productReference = DECD490B262F81BF00924527 /* ApolloCodegenTestSupport.framework */; - productType = "com.apple.product-type.framework"; - }; - E6A901D327BDAFA100931C9E /* SubscriptionAPI */ = { - isa = PBXNativeTarget; - buildConfigurationList = E6A901D827BDAFA100931C9E /* Build configuration list for PBXNativeTarget "SubscriptionAPI" */; - buildPhases = ( - E6A901CF27BDAFA100931C9E /* Headers */, - E6A901D027BDAFA100931C9E /* Sources */, - E6A901D127BDAFA100931C9E /* Frameworks */, - E6A901D227BDAFA100931C9E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - E6A901DF27BDB01200931C9E /* PBXTargetDependency */, - ); - name = SubscriptionAPI; - productName = SubscriptionAPI; - productReference = E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 9FC7503B1D2A532C00458D91 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1240; - LastUpgradeCheck = 1230; - ORGANIZATIONNAME = "Apollo GraphQL"; - TargetAttributes = { - 9B2DFBB524E1FA0D00ED3AE6 = { - CreatedOnToolsVersion = 11.6; - LastSwiftMigration = 1160; - }; - 9B68353D2463481A00337AE6 = { - CreatedOnToolsVersion = 11.4.1; - }; - 9B7B6F46233C26D100F32205 = { - CreatedOnToolsVersion = 11.0; - LastSwiftMigration = 1100; - }; - 9B7BDA7C23FDE90400ACD198 = { - CreatedOnToolsVersion = 11.3.1; - }; - 9B7BDABE23FDEBB600ACD198 = { - CreatedOnToolsVersion = 11.3.1; - }; - 9BAEEBFB234BB8FD00808306 = { - CreatedOnToolsVersion = 11.0; - }; - 9F54C8B3255D760B0065AFD6 = { - CreatedOnToolsVersion = 12.1.1; - }; - 9F8A95771EC0FC1200304A2D = { - CreatedOnToolsVersion = 8.3.2; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - 9FACA9B71F42E67200AE2DBD = { - ProvisioningStyle = Manual; - }; - 9FC750431D2A532C00458D91 = { - CreatedOnToolsVersion = 8.0; - DevelopmentTeamName = "Martijn Walraven"; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - 9FC7504D1D2A532D00458D91 = { - CreatedOnToolsVersion = 8.0; - DevelopmentTeamName = "Martijn Walraven"; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - 9FCE2CF91E6C213D00E34457 = { - CreatedOnToolsVersion = 8.2.1; - LastSwiftMigration = 1020; - ProvisioningStyle = Manual; - }; - DE6B15AB26152BE10068D642 = { - CreatedOnToolsVersion = 12.4; - }; - DECD490A262F81BF00924527 = { - CreatedOnToolsVersion = 12.4; - }; - E6A901D327BDAFA100931C9E = { - CreatedOnToolsVersion = 13.2.1; - LastSwiftMigration = 1320; - }; - }; - }; - buildConfigurationList = 9FC7503E1D2A532C00458D91 /* Build configuration list for PBXProject "Apollo" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 9FC7503A1D2A532C00458D91; - packageReferences = ( - 9B7BDAF423FDEE2600ACD198 /* XCRemoteSwiftPackageReference "SQLite.swift" */, - E6A19C6027BEDAE00099C6E3 /* XCRemoteSwiftPackageReference "Nimble" */, - ); - productRefGroup = 9FC750451D2A532C00458D91 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 9FC750431D2A532C00458D91 /* Apollo */, - DE058606266978A100265760 /* ApolloAPI */, - 9B68353D2463481A00337AE6 /* ApolloUtils */, - 9B7BDABE23FDEBB600ACD198 /* ApolloSQLite */, - 9B7BDA7C23FDE90400ACD198 /* ApolloWebSocket */, - 9FC7504D1D2A532D00458D91 /* ApolloTests */, - 9F54C8B3255D760B0065AFD6 /* ApolloPerformanceTests */, - DE6B15AB26152BE10068D642 /* ApolloServerIntegrationTests */, - 9F8A95771EC0FC1200304A2D /* ApolloTestSupport */, - 9FCE2CF91E6C213D00E34457 /* StarWarsAPI */, - 9FACA9B71F42E67200AE2DBD /* GitHubAPI */, - 9B2DFBB524E1FA0D00ED3AE6 /* UploadAPI */, - E6A901D327BDAFA100931C9E /* SubscriptionAPI */, - 9B7B6F46233C26D100F32205 /* ApolloCodegenLib */, - 9BAEEBFB234BB8FD00808306 /* ApolloCodegenTests */, - DECD490A262F81BF00924527 /* ApolloCodegenTestSupport */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 9B2DFBB424E1FA0D00ED3AE6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B68353C2463481A00337AE6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7B6F45233C26D100F32205 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DE3C7974260A646300D2F4FF /* dist in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDA7B23FDE90400ACD198 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDABD23FDEBB600ACD198 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9BAEEBFA234BB8FD00808306 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E6C4267B26F16CB400904AD2 /* introspection_response.json in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F54C8B2255D760B0065AFD6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9FD1519A255D7F30003BDAAA /* IssuesAndCommentsForRepository.json in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F62DF3F258F45BF00E6E808 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9F41CBF025A3490600C02CB7 /* schema.graphqls in Resources */, - 9F41CC0025A3491E00C02CB7 /* schema.json in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FC750421D2A532C00458D91 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - C304EBD522DDC87800748F72 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE05861C266978A100265760 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE674D9C261CEEDA000E8FC8 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DE674D9F261CEEE4000E8FC8 /* a.txt in Resources */, - DE674D9E261CEEE4000E8FC8 /* b.txt in Resources */, - DE674D9D261CEEE4000E8FC8 /* c.txt in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE6B15AA26152BE10068D642 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DECD4909262F81BF00924527 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E6A901D227BDAFA100931C9E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 90690D322243442F00FC2E54 /* Ensure no build settings are in the Xcode project */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Ensure no build settings are in the Xcode project"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$SRCROOT\"/scripts/ensure-no-build-settings-in-pbxproj.sh \"${PROJECT_FILE_PATH}\"\n"; - }; - 9FACA9BA1F42E67200AE2DBD /* Generate Apollo Client API */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Generate Apollo Client API"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "cd \"${SRCROOT}/SwiftScripts\"\nxcrun -sdk macosx swift run --build-path \"./.build-GitHub\" Codegen -t \"GitHub\"\n"; - }; - 9FCE2D061E6C251100E34457 /* Generate Apollo Client API */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Generate Apollo Client API"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "cd \"${SRCROOT}/SwiftScripts\"\nxcrun -sdk macosx swift run --build-path \"./.build-StarWars\" Codegen -t \"StarWars\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 9B2DFBB224E1FA0D00ED3AE6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B2DFBCF24E201DD00ED3AE6 /* API.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B68353A2463481A00337AE6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B455CE52492D0A3002255A9 /* ApolloExtension.swift in Sources */, - 9B455CEB2492FB03002255A9 /* String+SHA.swift in Sources */, - 9B455CDF2492D05E002255A9 /* Atomic.swift in Sources */, - 9B455CE72492D0A3002255A9 /* Collection+Apollo.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7B6F43233C26D100F32205 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BAEEBEE2346644600808306 /* ApolloSchemaDownloadConfiguration.swift in Sources */, - 9BC2D9D3233C6EF0007BD083 /* Basher.swift in Sources */, - 9B8C3FB3248DA2FE00707B13 /* URL+Apollo.swift in Sources */, - 9BAEEBEF2346644B00808306 /* ApolloSchemaDownloader.swift in Sources */, - 9F1A966F258F34BB00A06EEB /* JavaScriptBridge.swift in Sources */, - 9BAEEBF72346F0A000808306 /* StaticString+Apollo.swift in Sources */, - 9BCA8C0926618226004FF2F6 /* UntypedGraphQLRequestBodyCreator.swift in Sources */, - 9F62DFD02590710E00E6E808 /* GraphQLSource.swift in Sources */, - 9BAEEBF32346DDAD00808306 /* CodegenLogger.swift in Sources */, - 9F628EB52593651B00F94F9D /* GraphQLValue.swift in Sources */, - 9B518C8C235F8B5F004C426D /* ApolloFilePathHelper.swift in Sources */, - 9F628E9525935BE600F94F9D /* GraphQLType.swift in Sources */, - 9B518C87235F819E004C426D /* CLIDownloader.swift in Sources */, - 9BFE8DA9265D5D8F000BBF81 /* URLDownloader.swift in Sources */, - 9F1A966D258F34BB00A06EEB /* CompilationResult.swift in Sources */, - 9BAEEBF123467E0A00808306 /* ApolloCLI.swift in Sources */, - 9B7B6F69233C2C0C00F32205 /* FileManager+Apollo.swift in Sources */, - 9F1A966C258F34BB00A06EEB /* GraphQLSchema.swift in Sources */, - 9BE74D3D23FB4A8E006D354F /* FileFinder.swift in Sources */, - 9B7B6F59233C287200F32205 /* ApolloCodegen.swift in Sources */, - 9F62E03F2590896400E6E808 /* GraphQLError.swift in Sources */, - 9B7B6F5A233C287200F32205 /* ApolloCodegenOptions.swift in Sources */, - 9F1A966B258F34BB00A06EEB /* ApolloCodegenFrontend.swift in Sources */, - 9BAEEBF52346E90700808306 /* CLIExtractor.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDA7923FDE90400ACD198 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B7BDA9F23FDE94C00ACD198 /* WebSocketClient.swift in Sources */, - DE181A2C26C5C0CB000C0B9C /* WebSocket.swift in Sources */, - DE181A2E26C5C299000C0B9C /* SSLClientCertificate.swift in Sources */, - 9B7BDAA023FDE94C00ACD198 /* WebSocketTransport.swift in Sources */, - 9B7BDA9C23FDE94C00ACD198 /* WebSocketTask.swift in Sources */, - DE181A3026C5C38E000C0B9C /* SSLSecurity.swift in Sources */, - 9B7BDA9B23FDE94C00ACD198 /* WebSocketError.swift in Sources */, - 9B7BDA9D23FDE94C00ACD198 /* SplitNetworkTransport.swift in Sources */, - 9B7BDA9E23FDE94C00ACD198 /* OperationMessage.swift in Sources */, - 19E9F6B526D6BF25003AB80E /* OperationMessageIdCreator.swift in Sources */, - DE181A3626C5DE4F000C0B9C /* WebSocketStream.swift in Sources */, - DE181A3226C5C401000C0B9C /* Compression.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9B7BDABB23FDEBB600ACD198 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9B7BDAD023FDEBE300ACD198 /* SQLiteSerialization.swift in Sources */, - 9B7BDAD223FDEBE300ACD198 /* SQLiteNormalizedCache.swift in Sources */, - 9B9F16B82601532500FB2F31 /* SQLiteDotSwiftDatabase.swift in Sources */, - 9B9F16A726013DAB00FB2F31 /* SQLiteDatabase.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9BAEEBF8234BB8FD00808306 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BAEEC10234BB95B00808306 /* FileManagerExtensionsTests.swift in Sources */, - 9BAEEC17234C275600808306 /* ApolloSchemaPublicTests.swift in Sources */, - 9F62DFAE2590557F00E6E808 /* DocumentParsingAndValidationTests.swift in Sources */, - 9F62E0102590728000E6E808 /* CompilationTests.swift in Sources */, - 9F62DFBF2590560000E6E808 /* Helpers.swift in Sources */, - 9B8C3FB5248DA3E000707B13 /* URLExtensionsTests.swift in Sources */, - 9B518C8D235F8B9E004C426D /* CLIDownloaderTests.swift in Sources */, - 9FDE0731258F3AA100DC0CA5 /* SchemaLoadingTests.swift in Sources */, - E657CDBA26FD01D4005834D6 /* ApolloSchemaInternalTests.swift in Sources */, - E6D79AB826E9D59C0094434A /* URLDownloaderTests.swift in Sources */, - 9F62DF8E2590539A00E6E808 /* SchemaIntrospectionTests.swift in Sources */, - 9B68F0552416B33300E97318 /* LineByLineComparison.swift in Sources */, - 9BAEEC15234C132600808306 /* CLIExtractorTests.swift in Sources */, - 9BAEEC19234C297800808306 /* ApolloCodegenTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F54C8B0255D760B0065AFD6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9F54C8B7255D760B0065AFD6 /* ParsingPerformanceTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9F8A95731EC0FC1200304A2D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DED4601A261CE9880086EF63 /* MockWebSocket.swift in Sources */, - 9BCF0CE423FC9CA50031D2A2 /* MockURLSession.swift in Sources */, - 9FBE0D4025407B64002ED0B1 /* AsyncResultObserver.swift in Sources */, - 9F3910272549741400AF54A6 /* MockGraphQLServer.swift in Sources */, - DED45E6B261B9EAC0086EF63 /* SQLiteTestCacheProvider.swift in Sources */, - 9BEEDC2B24E61995001D1294 /* TestURLs.swift in Sources */, - DED4600D261CE9260086EF63 /* TestFileHelper.swift in Sources */, - 9BCF0CE023FC9CA50031D2A2 /* TestCacheProvider.swift in Sources */, - 9BCF0CE323FC9CA50031D2A2 /* XCTAssertHelpers.swift in Sources */, - E658545E27C6028100339378 /* MockWebSocketDelegate.swift in Sources */, - 9F68F9F125415827004F26D0 /* XCTestCase+Helpers.swift in Sources */, - 9BCF0CE523FC9CA50031D2A2 /* MockNetworkTransport.swift in Sources */, - DE05862D2669800000265760 /* Matchable.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FACA9BB1F42E67200AE2DBD /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BDF201423FDC37600153E2B /* API.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FC7503F1D2A532C00458D91 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - C377CCAB22D7992E00572E03 /* MultipartFormData.swift in Sources */, - 9B260C08245A437400562176 /* InterceptorProvider.swift in Sources */, - 9B9BBAF324DB39D70021C30F /* UploadRequest.swift in Sources */, - 9FCE2CEE1E6BE2D900E34457 /* NormalizedCache.swift in Sources */, - 9B260C0A245A532500562176 /* JSONResponseParsingInterceptor.swift in Sources */, - 9B96500C24BE7239003C29C0 /* CacheReadInterceptor.swift in Sources */, - 9F8F334C229044A200C0E83B /* Decoding.swift in Sources */, - DE0586392669985000265760 /* Dictionary+Helpers.swift in Sources */, - 9F295E381E277B2A00A24949 /* GraphQLResultNormalizer.swift in Sources */, - 9F8E0BE325668559000D9FA5 /* PossiblyDeferred.swift in Sources */, - 9F86B68B1E6438D700B885FF /* GraphQLSelectionSetMapper.swift in Sources */, - 9F55347B1DE1DB2100E54264 /* ApolloStore.swift in Sources */, - 9BDE43D122C6655300FD7C7F /* Cancellable.swift in Sources */, - 9F69FFA91D42855900E000B1 /* NetworkTransport.swift in Sources */, - 9F8E0BD325668552000D9FA5 /* DataLoader.swift in Sources */, - 9FCDFD291E33D0CE007519DC /* GraphQLQueryWatcher.swift in Sources */, - DE56DC232683B2020090D6E4 /* DefaultInterceptorProvider.swift in Sources */, - 9FC2333D1E66BBF7001E4541 /* GraphQLDependencyTracker.swift in Sources */, - 9FC9A9BF1E2C27FB0023C4D5 /* GraphQLResult.swift in Sources */, - 9FEB050D1DB5732300DA3B44 /* JSONSerializationFormat.swift in Sources */, - 9B260BEB245A020300562176 /* ApolloInterceptor.swift in Sources */, - 54DDB0921EA045870009DD99 /* InMemoryNormalizedCache.swift in Sources */, - DE6B156A261505660068D642 /* GraphQLMap.swift in Sources */, - 9B554CC4247DC29A002F452A /* TaskData.swift in Sources */, - 9B9BBAF524DB4F890021C30F /* AutomaticPersistedQueryInterceptor.swift in Sources */, - DE05862F266980C200265760 /* GraphQLSelectionSet.swift in Sources */, - 9BA1244A22D8A8EA00BF1D24 /* JSONSerialization+Sorting.swift in Sources */, - 9B260BF1245A025400562176 /* HTTPRequest.swift in Sources */, - 9B708AAD2305884500604A11 /* ApolloClientProtocol.swift in Sources */, - C377CCA922D798BD00572E03 /* GraphQLFile.swift in Sources */, - 9BEEDC2824E351E5001D1294 /* MaxRetryInterceptor.swift in Sources */, - 9FC9A9CC1E2FD0760023C4D5 /* Record.swift in Sources */, - 9B260BFB245A031900562176 /* NetworkFetchInterceptor.swift in Sources */, - 9FEC15B41E681DAD00D461B4 /* GroupedSequence.swift in Sources */, - 9F578D901D8D2CB300C0EA36 /* HTTPURLResponse+Helpers.swift in Sources */, - 9B260C04245A090600562176 /* RequestChainNetworkTransport.swift in Sources */, - 9F7BA89922927A3700999B3B /* ResponsePath.swift in Sources */, - 9FC9A9BD1E2C271C0023C4D5 /* RecordSet.swift in Sources */, - 9BF1A95122CA6E71005292C2 /* GraphQLGETTransformer.swift in Sources */, - 9B260BFF245A054700562176 /* JSONRequest.swift in Sources */, - 9B260BF9245A030100562176 /* ResponseCodeInterceptor.swift in Sources */, - 9B260BF3245A026F00562176 /* RequestChain.swift in Sources */, - 9FF90A611DDDEB100034C3B6 /* GraphQLResponse.swift in Sources */, - 9BEDC79E22E5D2CF00549BF6 /* RequestBodyCreator.swift in Sources */, - 9BE071AD2368D08700FA5952 /* Collection+Helpers.swift in Sources */, - 9FA6F3681E65DF4700BF8D73 /* GraphQLResultAccumulator.swift in Sources */, - 9FF90A651DDDEB100034C3B6 /* GraphQLExecutor.swift in Sources */, - DE0586362669957800265760 /* CacheReference.swift in Sources */, - 9FC750611D2A59C300458D91 /* GraphQLOperation.swift in Sources */, - 9BDE43DF22C6708600FD7C7F /* GraphQLHTTPRequestError.swift in Sources */, - 9B1CCDD92360F02C007C9032 /* Bundle+Helpers.swift in Sources */, - 9B260BF5245A028D00562176 /* HTTPResponse.swift in Sources */, - 5AC6CA4322AAF7B200B7C94D /* GraphQLHTTPMethod.swift in Sources */, - DE0586342669956A00265760 /* JSON.swift in Sources */, - DE0586352669956D00265760 /* JSONStandardTypeConversions.swift in Sources */, - 9BC742AE24CFB6450029282C /* CacheWriteInterceptor.swift in Sources */, - 9B4F453F244A27B900C2CF7D /* URLSessionClient.swift in Sources */, - DE0586332669948500265760 /* InputValue+Evaluation.swift in Sources */, - DE0586372669958F00265760 /* GraphQLError.swift in Sources */, - 9BC742AC24CFB2FF0029282C /* ApolloErrorInterceptor.swift in Sources */, - 9FC750631D2A59F600458D91 /* ApolloClient.swift in Sources */, - 9BA3130E2302BEA5007B7FC5 /* DispatchQueue+Optional.swift in Sources */, - 9F86B6901E65533D00B885FF /* GraphQLResponseGenerator.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FC7504A1D2A532D00458D91 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5BB2C0232380836100774170 /* VersionNumberTests.swift in Sources */, - DED45EC3261BA0ED0086EF63 /* WebSocketTransportTests.swift in Sources */, - 9B78C71E2326E86E000C8C32 /* ErrorGenerationTests.swift in Sources */, - DED45EC7261BA0ED0086EF63 /* WebSocketTests.swift in Sources */, - 9FC9A9C81E2EFE6E0023C4D5 /* CacheKeyForFieldTests.swift in Sources */, - 9BF6C99C25195019000D5B93 /* String+IncludesForTesting.swift in Sources */, - DED45DEF261B96B70086EF63 /* ReadWriteFromStoreTests.swift in Sources */, - 9F91CF8F1F6C0DB2008DD0BE /* MutatingResultsTests.swift in Sources */, - E616B6D126C3335600DB049E /* ExecutionTests.swift in Sources */, - 9B9BBB1C24DB760B0021C30F /* UploadRequestTests.swift in Sources */, - E61DD76526D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift in Sources */, - 9BC139A424EDCA6C00876D29 /* InterceptorTests.swift in Sources */, - F82E62E122BCD223000C311B /* AutomaticPersistedQueriesTests.swift in Sources */, - 9BC139A824EDCE4F00876D29 /* RetryToCountThenSucceedInterceptor.swift in Sources */, - 9F533AB31E6C4A4200CBE097 /* BatchedLoadTests.swift in Sources */, - DED45DEE261B96B70086EF63 /* FetchQueryTests.swift in Sources */, - C3279FC72345234D00224790 /* TestCustomRequestBodyCreator.swift in Sources */, - E658546C27C77B8B00339378 /* GraphqlTransportWsProtocolTests.swift in Sources */, - DED45DED261B96B70086EF63 /* StoreConcurrencyTests.swift in Sources */, - 9B95EDC022CAA0B000702BB2 /* GETTransformerTests.swift in Sources */, - 9FF90A6F1DDDEB420034C3B6 /* GraphQLMapEncodingTests.swift in Sources */, - D87AC09F2564D60B0079FAA5 /* ApolloClientOperationTests.swift in Sources */, - 9B64F6762354D219002D1BB5 /* URL+QueryDict.swift in Sources */, - 9B2B66F42513FAFE00B53ABF /* CancellationHandlingInterceptor.swift in Sources */, - 9BC139A624EDCAD900876D29 /* BlindRetryingTestInterceptor.swift in Sources */, - E6057F8B287D7E24007D84EC /* ResponsePathTests.swift in Sources */, - 9B96500A24BE62B7003C29C0 /* RequestChainTests.swift in Sources */, - DED45DEA261B96B70086EF63 /* WatchQueryTests.swift in Sources */, - DED45E30261B972C0086EF63 /* CachePersistenceTests.swift in Sources */, - DED45EC4261BA0ED0086EF63 /* SplitNetworkTransportTests.swift in Sources */, - 9B21FD752422C29D00998B5C /* GraphQLFileTests.swift in Sources */, - E86D8E05214B32FD0028EFE1 /* JSONTests.swift in Sources */, - 2EE7FFD0276802E30035DC39 /* CacheKeyConstructionTests.swift in Sources */, - 9F8622FA1EC2117C00C38162 /* FragmentConstructionAndConversionTests.swift in Sources */, - E6B9BDDB27C5693300CF911D /* GraphqlWsProtocolTests.swift in Sources */, - DED45C2A2615319E0086EF63 /* DefaultInterceptorProviderTests.swift in Sources */, - 9F21730E2567E6F000566121 /* DataLoaderTests.swift in Sources */, - DED45DEC261B96B70086EF63 /* CacheDependentInterceptorTests.swift in Sources */, - DED45DEB261B96B70086EF63 /* SQLiteCacheTests.swift in Sources */, - C338DF1722DD9DE9006AF33E /* RequestBodyCreatorTests.swift in Sources */, - F16D083C21EF6F7300C458B8 /* QueryFromJSONBuildingTests.swift in Sources */, - 9BF6C97025194ED7000D5B93 /* MultipartFormDataTests.swift in Sources */, - 9FF90A711DDDEB420034C3B6 /* ReadFieldValueTests.swift in Sources */, - E63C67A327C8AA2A00B1654E /* OperationMessageMatchers.swift in Sources */, - 9F295E311E27534800A24949 /* NormalizeQueryResults.swift in Sources */, - 9FF90A731DDDEB420034C3B6 /* ParseQueryResponseTests.swift in Sources */, - DED45DE9261B96B70086EF63 /* LoadQueryFromStoreTests.swift in Sources */, - E63F15CD27C96D6D006879ED /* WSProtocolTestsBase.swift in Sources */, - 9BF6C94325194DE2000D5B93 /* MultipartFormData+Testing.swift in Sources */, - DE181A3426C5D8D4000C0B9C /* CompressionTests.swift in Sources */, - 19E9F6AC26D58A9A003AB80E /* OperationMessageIdCreatorTests.swift in Sources */, - 9F21735B2568F3E200566121 /* PossiblyDeferredTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 9FCE2CF51E6C213D00E34457 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9BCF0D0223FC9F060031D2A2 /* API.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE058608266978A100265760 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DE058609266978A100265760 /* Selection.swift in Sources */, - DE05860A266978A100265760 /* ResponseDict.swift in Sources */, - DE05860B266978A100265760 /* SelectionSet.swift in Sources */, - DE05860C266978A100265760 /* FragmentProtocols.swift in Sources */, - DE05860D266978A100265760 /* ScalarTypes.swift in Sources */, - DE05860E266978A100265760 /* GraphQLOptional.swift in Sources */, - DE058610266978A100265760 /* InputValue.swift in Sources */, - DE058613266978A100265760 /* GraphQLSchema.swift in Sources */, - DE058616266978A100265760 /* GraphQLEnum.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DE6B15A826152BE10068D642 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DED46042261CEA8A0086EF63 /* TestServerURLs.swift in Sources */, - DED45EFE261CDA2A0086EF63 /* StarWarsSubscriptionTests.swift in Sources */, - DED45D852616759C0086EF63 /* TestConfigs.swift in Sources */, - DED45D9626167F020086EF63 /* StarWarsServerCachingRoundtripTests.swift in Sources */, - DECD46D0262F64D000924527 /* StarWarsApolloSchemaDownloaderTests.swift in Sources */, - E63C03DF27BDDC3D00D675C6 /* SubscriptionTests.swift in Sources */, - DE6B15AF26152BE10068D642 /* DefaultInterceptorProviderIntegrationTests.swift in Sources */, - DED46000261CE9080086EF63 /* HTTPBinAPI.swift in Sources */, - DED45F4A261CDBFC0086EF63 /* UploadTests.swift in Sources */, - E6630B8E26F071F9002D9E41 /* SchemaRegistryApolloSchemaDownloaderTests.swift in Sources */, - DED45F17261CDA360086EF63 /* StarWarsWebSocketTests.swift in Sources */, - DED45D73261675890086EF63 /* StarWarsServerTests.swift in Sources */, - DED45F30261CDB560086EF63 /* URLSessionClientTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - DECD4907262F81BF00924527 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - DECD4921262F81CE00924527 /* CodegenTestHelper.swift in Sources */, - E6630B8C26F0639B002D9E41 /* MockNetworkSession.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E6A901D027BDAFA100931C9E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E6A19C6727BF0E1C0099C6E3 /* API.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 9B2DFBC224E1FA1A00ED3AE6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9B2DFBC124E1FA1A00ED3AE6 /* PBXContainerItemProxy */; - }; - 9B2DFBCC24E201A000ED3AE6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B2DFBB524E1FA0D00ED3AE6 /* UploadAPI */; - targetProxy = 9B2DFBCB24E201A000ED3AE6 /* PBXContainerItemProxy */; - }; - 9B683549246348CB00337AE6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B68353D2463481A00337AE6 /* ApolloUtils */; - targetProxy = 9B683548246348CB00337AE6 /* PBXContainerItemProxy */; - }; - 9B7BDAF823FDEE8400ACD198 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9B7BDAF723FDEE8400ACD198 /* PBXContainerItemProxy */; - }; - 9B7BDAFC23FDEE9000ACD198 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9B7BDAFB23FDEE9000ACD198 /* PBXContainerItemProxy */; - }; - 9B7BDB1723FDF10300ACD198 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = 9B7BDB1623FDF10300ACD198 /* SQLite */; - }; - 9B8C3FBC248DAA0400707B13 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B68353D2463481A00337AE6 /* ApolloUtils */; - targetProxy = 9B8C3FBB248DAA0400707B13 /* PBXContainerItemProxy */; - }; - 9BAEEC03234BB8FD00808306 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7B6F46233C26D100F32205 /* ApolloCodegenLib */; - targetProxy = 9BAEEC02234BB8FD00808306 /* PBXContainerItemProxy */; - }; - 9F54C8BB255D760B0065AFD6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9F54C8BA255D760B0065AFD6 /* PBXContainerItemProxy */; - }; - 9F54C8DF255D76810065AFD6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9F8A95771EC0FC1200304A2D /* ApolloTestSupport */; - targetProxy = 9F54C8DE255D76810065AFD6 /* PBXContainerItemProxy */; - }; - 9F54C8E1255D76810065AFD6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FACA9B71F42E67200AE2DBD /* GitHubAPI */; - targetProxy = 9F54C8E0255D76810065AFD6 /* PBXContainerItemProxy */; - }; - 9F65B1201EC106E80090B25F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9F65B11F1EC106E80090B25F /* PBXContainerItemProxy */; - }; - 9F8A958C1EC0FF9F00304A2D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9F8A95771EC0FC1200304A2D /* ApolloTestSupport */; - targetProxy = 9F8A958B1EC0FF9F00304A2D /* PBXContainerItemProxy */; - }; - 9FA5FBB61EC05CE900304A9D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9FA5FBB51EC05CE900304A9D /* PBXContainerItemProxy */; - }; - 9FACA9B81F42E67200AE2DBD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9FACA9B91F42E67200AE2DBD /* PBXContainerItemProxy */; - }; - 9FC750511D2A532D00458D91 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = 9FC750501D2A532D00458D91 /* PBXContainerItemProxy */; - }; - 9FCE2D081E6C254000E34457 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FCE2CF91E6C213D00E34457 /* StarWarsAPI */; - targetProxy = 9FCE2D071E6C254000E34457 /* PBXContainerItemProxy */; - }; - 9FDE0742258F3B6100DC0CA5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FCE2CF91E6C213D00E34457 /* StarWarsAPI */; - targetProxy = 9FDE0741258F3B6100DC0CA5 /* PBXContainerItemProxy */; - }; - DE05862826697B1D00265760 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DE058606266978A100265760 /* ApolloAPI */; - targetProxy = DE05862726697B1D00265760 /* PBXContainerItemProxy */; - }; - DE6B15B326152BE10068D642 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = DE6B15B226152BE10068D642 /* PBXContainerItemProxy */; - }; - DECD46FA262F659100924527 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7B6F46233C26D100F32205 /* ApolloCodegenLib */; - targetProxy = DECD46F9262F659100924527 /* PBXContainerItemProxy */; - }; - DECD4735262F668200924527 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B2DFBB524E1FA0D00ED3AE6 /* UploadAPI */; - targetProxy = DECD4734262F668200924527 /* PBXContainerItemProxy */; - }; - DECD498E262F840100924527 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DECD490A262F81BF00924527 /* ApolloCodegenTestSupport */; - targetProxy = DECD498D262F840100924527 /* PBXContainerItemProxy */; - }; - DECD4991262F841300924527 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DECD490A262F81BF00924527 /* ApolloCodegenTestSupport */; - targetProxy = DECD4990262F841300924527 /* PBXContainerItemProxy */; - }; - DECD49C8262F88FA00924527 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7B6F46233C26D100F32205 /* ApolloCodegenLib */; - targetProxy = DECD49C7262F88FA00924527 /* PBXContainerItemProxy */; - }; - DECD49DA262F8AA500924527 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9F8A95771EC0FC1200304A2D /* ApolloTestSupport */; - targetProxy = DECD49D9262F8AA500924527 /* PBXContainerItemProxy */; - }; - DED45E96261B9EE30086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = DED45E95261B9EE30086EF63 /* SQLite */; - }; - DED45E98261B9EFA0086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7BDABE23FDEBB600ACD198 /* ApolloSQLite */; - targetProxy = DED45E97261B9EFA0086EF63 /* PBXContainerItemProxy */; - }; - DED45E9A261B9F000086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7BDA7C23FDE90400ACD198 /* ApolloWebSocket */; - targetProxy = DED45E99261B9F000086EF63 /* PBXContainerItemProxy */; - }; - DED45FCF261CE8890086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7BDABE23FDEBB600ACD198 /* ApolloSQLite */; - targetProxy = DED45FCE261CE8890086EF63 /* PBXContainerItemProxy */; - }; - DED45FD6261CE89C0086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9B7BDA7C23FDE90400ACD198 /* ApolloWebSocket */; - targetProxy = DED45FD5261CE89C0086EF63 /* PBXContainerItemProxy */; - }; - DED46034261CEA610086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9F8A95771EC0FC1200304A2D /* ApolloTestSupport */; - targetProxy = DED46033261CEA610086EF63 /* PBXContainerItemProxy */; - }; - DED4606B261CEDD10086EF63 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FCE2CF91E6C213D00E34457 /* StarWarsAPI */; - targetProxy = DED4606A261CEDD10086EF63 /* PBXContainerItemProxy */; - }; - E63C03E127BDDFEF00D675C6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = E6A901D327BDAFA100931C9E /* SubscriptionAPI */; - targetProxy = E63C03E027BDDFEF00D675C6 /* PBXContainerItemProxy */; - }; - E6A901DF27BDB01200931C9E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9FC750431D2A532C00458D91 /* Apollo */; - targetProxy = E6A901DE27BDB01200931C9E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 9B2DFBBB24E1FA0D00ED3AE6 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B2DFBC824E1FA7E00ED3AE6 /* Apollo-Target-UploadAPI.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9B2DFBBC24E1FA0D00ED3AE6 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B2DFBC824E1FA7E00ED3AE6 /* Apollo-Target-UploadAPI.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9B2DFBBD24E1FA0D00ED3AE6 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B2DFBC824E1FA7E00ED3AE6 /* Apollo-Target-UploadAPI.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9B6835432463481A00337AE6 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B68354A2463498D00337AE6 /* Apollo-Target-ApolloUtils.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9B6835442463481A00337AE6 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B68354A2463498D00337AE6 /* Apollo-Target-ApolloUtils.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9B6835452463481A00337AE6 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B68354A2463498D00337AE6 /* Apollo-Target-ApolloUtils.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9B7B6F4C233C26D100F32205 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7B6F55233C27A000F32205 /* Apollo-Target-ApolloCodegenLib.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9B7B6F4D233C26D100F32205 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7B6F55233C27A000F32205 /* Apollo-Target-ApolloCodegenLib.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9B7B6F4E233C26D100F32205 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7B6F55233C27A000F32205 /* Apollo-Target-ApolloCodegenLib.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9B7BDA8323FDE90400ACD198 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7BDAA423FDE98C00ACD198 /* ApolloWebSocket-Target-Framework.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9B7BDA8423FDE90400ACD198 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7BDAA423FDE98C00ACD198 /* ApolloWebSocket-Target-Framework.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9B7BDA8523FDE90400ACD198 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7BDAA423FDE98C00ACD198 /* ApolloWebSocket-Target-Framework.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9B7BDAC923FDEBB600ACD198 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7BDAD823FDECB300ACD198 /* ApolloSQLite-Target-Framework.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9B7BDACA23FDEBB600ACD198 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7BDAD823FDECB300ACD198 /* ApolloSQLite-Target-Framework.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9B7BDACB23FDEBB600ACD198 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B7BDAD823FDECB300ACD198 /* ApolloSQLite-Target-Framework.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9BAEEC04234BB8FD00808306 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B4AA8AD239EFDC9003E1300 /* Apollo-Target-CodegenTests.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9BAEEC05234BB8FD00808306 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B4AA8AD239EFDC9003E1300 /* Apollo-Target-CodegenTests.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9BAEEC06234BB8FD00808306 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9B4AA8AD239EFDC9003E1300 /* Apollo-Target-CodegenTests.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9F54C8BD255D760B0065AFD6 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2422433C8000FC2E54 /* Apollo-Target-PerformanceTests.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9F54C8BE255D760B0065AFD6 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2422433C8000FC2E54 /* Apollo-Target-PerformanceTests.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9F54C8BF255D760B0065AFD6 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2422433C8000FC2E54 /* Apollo-Target-PerformanceTests.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9F8A957D1EC0FC1200304A2D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2522433CAF00FC2E54 /* Apollo-Target-TestSupport.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9F8A957E1EC0FC1200304A2D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2522433CAF00FC2E54 /* Apollo-Target-TestSupport.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9F8A957F1EC0FC1200304A2D /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2522433CAF00FC2E54 /* Apollo-Target-TestSupport.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9FACA9C31F42E67200AE2DBD /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2222433C2800FC2E54 /* Apollo-Target-GitHubAPI.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9FACA9C41F42E67200AE2DBD /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2222433C2800FC2E54 /* Apollo-Target-GitHubAPI.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9FACA9C51F42E67200AE2DBD /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2222433C2800FC2E54 /* Apollo-Target-GitHubAPI.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9FC750561D2A532D00458D91 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D05224333DA00FC2E54 /* Apollo-Project-Debug.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9FC750571D2A532D00458D91 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D07224333DA00FC2E54 /* Apollo-Project-Release.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9FC750591D2A532D00458D91 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D06224333DA00FC2E54 /* Apollo-Target-Framework.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9FC7505A1D2A532D00458D91 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D06224333DA00FC2E54 /* Apollo-Target-Framework.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9FC7505C1D2A532D00458D91 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D0B2243345500FC2E54 /* Apollo-Target-Tests.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9FC7505D1D2A532D00458D91 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D0B2243345500FC2E54 /* Apollo-Target-Tests.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9FCE2D041E6C213D00E34457 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2122433C1900FC2E54 /* Apollo-Target-StarWarsAPI.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 9FCE2D051E6C213D00E34457 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2122433C1900FC2E54 /* Apollo-Target-StarWarsAPI.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 9FEFCFCD1E6C65CE0061834C /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D08224333DA00FC2E54 /* Apollo-Project-Performance-Testing.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9FEFCFCE1E6C65CE0061834C /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D06224333DA00FC2E54 /* Apollo-Target-Framework.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9FEFCFD01E6C65CE0061834C /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D0B2243345500FC2E54 /* Apollo-Target-Tests.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - 9FEFCFD61E6C65CE0061834C /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 90690D2122433C1900FC2E54 /* Apollo-Target-StarWarsAPI.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - DE05861E266978A100265760 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DE0586222669793200265760 /* Apollo-Target-ApolloAPI.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - DE05861F266978A100265760 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DE0586222669793200265760 /* Apollo-Target-ApolloAPI.xcconfig */; - buildSettings = { - }; - name = Release; - }; - DE058620266978A100265760 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DE0586222669793200265760 /* Apollo-Target-ApolloAPI.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - DE6B15B426152BE10068D642 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DE6B15E826152CD80068D642 /* Apollo-Target-ServerIntegrationTests.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - DE6B15B526152BE10068D642 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DE6B15E826152CD80068D642 /* Apollo-Target-ServerIntegrationTests.xcconfig */; - buildSettings = { - }; - name = Release; - }; - DE6B15B626152BE10068D642 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DE6B15E826152CD80068D642 /* Apollo-Target-ServerIntegrationTests.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - DECD4911262F81BF00924527 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DECD492F262F820500924527 /* Apollo-Target-CodegenTestSupport.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - DECD4912262F81BF00924527 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DECD492F262F820500924527 /* Apollo-Target-CodegenTestSupport.xcconfig */; - buildSettings = { - }; - name = Release; - }; - DECD4913262F81BF00924527 /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DECD492F262F820500924527 /* Apollo-Target-CodegenTestSupport.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; - E6A901D927BDAFA100931C9E /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E661C2D427BDAC500078BEBD /* Apollo-Target-SubscriptionAPI.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - E6A901DA27BDAFA100931C9E /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E661C2D427BDAC500078BEBD /* Apollo-Target-SubscriptionAPI.xcconfig */; - buildSettings = { - }; - name = Release; - }; - E6A901DB27BDAFA100931C9E /* PerformanceTesting */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E661C2D427BDAC500078BEBD /* Apollo-Target-SubscriptionAPI.xcconfig */; - buildSettings = { - }; - name = PerformanceTesting; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 9B2DFBBE24E1FA0D00ED3AE6 /* Build configuration list for PBXNativeTarget "UploadAPI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9B2DFBBB24E1FA0D00ED3AE6 /* Debug */, - 9B2DFBBC24E1FA0D00ED3AE6 /* Release */, - 9B2DFBBD24E1FA0D00ED3AE6 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9B6835462463481A00337AE6 /* Build configuration list for PBXNativeTarget "ApolloUtils" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9B6835432463481A00337AE6 /* Debug */, - 9B6835442463481A00337AE6 /* Release */, - 9B6835452463481A00337AE6 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9B7B6F4F233C26D200F32205 /* Build configuration list for PBXNativeTarget "ApolloCodegenLib" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9B7B6F4C233C26D100F32205 /* Debug */, - 9B7B6F4D233C26D100F32205 /* Release */, - 9B7B6F4E233C26D100F32205 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9B7BDA8223FDE90400ACD198 /* Build configuration list for PBXNativeTarget "ApolloWebSocket" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9B7BDA8323FDE90400ACD198 /* Debug */, - 9B7BDA8423FDE90400ACD198 /* Release */, - 9B7BDA8523FDE90400ACD198 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9B7BDAC823FDEBB600ACD198 /* Build configuration list for PBXNativeTarget "ApolloSQLite" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9B7BDAC923FDEBB600ACD198 /* Debug */, - 9B7BDACA23FDEBB600ACD198 /* Release */, - 9B7BDACB23FDEBB600ACD198 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9BAEEC07234BB8FD00808306 /* Build configuration list for PBXNativeTarget "ApolloCodegenTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9BAEEC04234BB8FD00808306 /* Debug */, - 9BAEEC05234BB8FD00808306 /* Release */, - 9BAEEC06234BB8FD00808306 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9F54C8BC255D760B0065AFD6 /* Build configuration list for PBXNativeTarget "ApolloPerformanceTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9F54C8BD255D760B0065AFD6 /* Debug */, - 9F54C8BE255D760B0065AFD6 /* Release */, - 9F54C8BF255D760B0065AFD6 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9F8A95801EC0FC1200304A2D /* Build configuration list for PBXNativeTarget "ApolloTestSupport" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9F8A957D1EC0FC1200304A2D /* Debug */, - 9F8A957E1EC0FC1200304A2D /* Release */, - 9F8A957F1EC0FC1200304A2D /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9FACA9C21F42E67200AE2DBD /* Build configuration list for PBXNativeTarget "GitHubAPI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9FACA9C31F42E67200AE2DBD /* Debug */, - 9FACA9C41F42E67200AE2DBD /* Release */, - 9FACA9C51F42E67200AE2DBD /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9FC7503E1D2A532C00458D91 /* Build configuration list for PBXProject "Apollo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9FC750561D2A532D00458D91 /* Debug */, - 9FC750571D2A532D00458D91 /* Release */, - 9FEFCFCD1E6C65CE0061834C /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9FC750581D2A532D00458D91 /* Build configuration list for PBXNativeTarget "Apollo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9FC750591D2A532D00458D91 /* Debug */, - 9FC7505A1D2A532D00458D91 /* Release */, - 9FEFCFCE1E6C65CE0061834C /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9FC7505B1D2A532D00458D91 /* Build configuration list for PBXNativeTarget "ApolloTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9FC7505C1D2A532D00458D91 /* Debug */, - 9FC7505D1D2A532D00458D91 /* Release */, - 9FEFCFD01E6C65CE0061834C /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 9FCE2D031E6C213D00E34457 /* Build configuration list for PBXNativeTarget "StarWarsAPI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9FCE2D041E6C213D00E34457 /* Debug */, - 9FCE2D051E6C213D00E34457 /* Release */, - 9FEFCFD61E6C65CE0061834C /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DE05861D266978A100265760 /* Build configuration list for PBXNativeTarget "ApolloAPI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DE05861E266978A100265760 /* Debug */, - DE05861F266978A100265760 /* Release */, - DE058620266978A100265760 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DE6B15B726152BE10068D642 /* Build configuration list for PBXNativeTarget "ApolloServerIntegrationTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DE6B15B426152BE10068D642 /* Debug */, - DE6B15B526152BE10068D642 /* Release */, - DE6B15B626152BE10068D642 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DECD4910262F81BF00924527 /* Build configuration list for PBXNativeTarget "ApolloCodegenTestSupport" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DECD4911262F81BF00924527 /* Debug */, - DECD4912262F81BF00924527 /* Release */, - DECD4913262F81BF00924527 /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E6A901D827BDAFA100931C9E /* Build configuration list for PBXNativeTarget "SubscriptionAPI" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E6A901D927BDAFA100931C9E /* Debug */, - E6A901DA27BDAFA100931C9E /* Release */, - E6A901DB27BDAFA100931C9E /* PerformanceTesting */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 9B7BDAF423FDEE2600ACD198 /* XCRemoteSwiftPackageReference "SQLite.swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/stephencelis/SQLite.swift.git"; - requirement = { - kind = upToNextMinorVersion; - minimumVersion = 0.13.1; - }; - }; - E6A19C6027BEDAE00099C6E3 /* XCRemoteSwiftPackageReference "Nimble" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Quick/Nimble"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 9.2.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 9B7BDAF523FDEE2600ACD198 /* SQLite */ = { - isa = XCSwiftPackageProductDependency; - package = 9B7BDAF423FDEE2600ACD198 /* XCRemoteSwiftPackageReference "SQLite.swift" */; - productName = SQLite; - }; - 9B7BDB1623FDF10300ACD198 /* SQLite */ = { - isa = XCSwiftPackageProductDependency; - package = 9B7BDAF423FDEE2600ACD198 /* XCRemoteSwiftPackageReference "SQLite.swift" */; - productName = SQLite; - }; - DED45E95261B9EE30086EF63 /* SQLite */ = { - isa = XCSwiftPackageProductDependency; - package = 9B7BDAF423FDEE2600ACD198 /* XCRemoteSwiftPackageReference "SQLite.swift" */; - productName = SQLite; - }; - E658545A27C5C1EE00339378 /* Nimble */ = { - isa = XCSwiftPackageProductDependency; - package = E6A19C6027BEDAE00099C6E3 /* XCRemoteSwiftPackageReference "Nimble" */; - productName = Nimble; - }; - E6A19C6127BEDAE00099C6E3 /* Nimble */ = { - isa = XCSwiftPackageProductDependency; - package = E6A19C6027BEDAE00099C6E3 /* XCRemoteSwiftPackageReference "Nimble" */; - productName = Nimble; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 9FC7503B1D2A532C00458D91 /* Project object */; -} diff --git a/Apollo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Apollo.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a625..0000000000 --- a/Apollo.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Apollo.xcodeproj/project.xcworkspace/xcshareddata/Apollo.xcscmblueprint b/Apollo.xcodeproj/project.xcworkspace/xcshareddata/Apollo.xcscmblueprint deleted file mode 100644 index 4468a2aee6..0000000000 --- a/Apollo.xcodeproj/project.xcworkspace/xcshareddata/Apollo.xcscmblueprint +++ /dev/null @@ -1,30 +0,0 @@ -{ - "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "11467B891B05E74285D0FDA7F262E859A9337C82", - "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { - - }, - "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { - "FF5E57E11CB20B5623A697D8A51544D5E81FBD84" : 9223372036854775807, - "11467B891B05E74285D0FDA7F262E859A9337C82" : 9223372036854775807 - }, - "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "3C9A0C1C-4254-4350-9916-D2A90026CA42", - "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { - "FF5E57E11CB20B5623A697D8A51544D5E81FBD84" : "", - "11467B891B05E74285D0FDA7F262E859A9337C82" : "apollo-ios\/" - }, - "DVTSourceControlWorkspaceBlueprintNameKey" : "Apollo", - "DVTSourceControlWorkspaceBlueprintVersion" : 204, - "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Apollo.xcodeproj", - "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ - { - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/apollostack\/apollo-ios", - "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "11467B891B05E74285D0FDA7F262E859A9337C82" - }, - { - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/apollostack\/apollo-ios-quickstart.git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", - "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "FF5E57E11CB20B5623A697D8A51544D5E81FBD84" - } - ] -} \ No newline at end of file diff --git a/Apollo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Apollo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index eddb11890a..0000000000 --- a/Apollo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,43 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "CwlCatchException", - "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git", - "state": { - "branch": null, - "revision": "35f9e770f54ce62dd8526470f14c6e137cef3eea", - "version": "2.1.1" - } - }, - { - "package": "CwlPreconditionTesting", - "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git", - "state": { - "branch": null, - "revision": "c21f7bab5ca8eee0a9998bbd17ca1d0eb45d4688", - "version": "2.1.0" - } - }, - { - "package": "Nimble", - "repositoryURL": "https://github.com/Quick/Nimble", - "state": { - "branch": null, - "revision": "c93f16c25af5770f0d3e6af27c9634640946b068", - "version": "9.2.1" - } - }, - { - "package": "SQLite.swift", - "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git", - "state": { - "branch": null, - "revision": "60a65015f6402b7c34b9a924f755ca0a73afeeaa", - "version": "0.13.1" - } - } - ] - }, - "version": 1 -} diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/50A052D5-C270-4C3E-823B-FCBB6C3E6539.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/50A052D5-C270-4C3E-823B-FCBB6C3E6539.plist deleted file mode 100644 index 66cd6a0ec4..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/50A052D5-C270-4C3E-823B-FCBB6C3E6539.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - classNames - - ParsingPerformanceTests - - testParseResult() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.068066 - baselineIntegrationDisplayName - Local Baseline - - - testParseResultFast() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.016656 - baselineIntegrationDisplayName - Local Baseline - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/7A4A2454-7A24-425D-84C2-116320B87F1E.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/7A4A2454-7A24-425D-84C2-116320B87F1E.plist deleted file mode 100644 index 0943718296..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/7A4A2454-7A24-425D-84C2-116320B87F1E.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - classNames - - ParsingPerformanceTests - - testParseResult() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.075663 - baselineIntegrationDisplayName - 17 Nov 2020 at 14:11:59 - - - testParseResultFast() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.016628 - baselineIntegrationDisplayName - 17 Nov 2020 at 14:11:59 - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/FA3A7E89-3F08-4E7F-890A-B0903F68A94C.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/FA3A7E89-3F08-4E7F-890A-B0903F68A94C.plist deleted file mode 100644 index 3404104db4..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/FA3A7E89-3F08-4E7F-890A-B0903F68A94C.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - classNames - - ParsingPerformanceTests - - testParseResult() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.095090 - baselineIntegrationDisplayName - 17 Nov 2020 at 13:47:48 - - - testParseResultFast() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.017559 - baselineIntegrationDisplayName - 17 Nov 2020 at 13:47:48 - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/Info.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/Info.plist deleted file mode 100644 index 978dbc92b6..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9F54C8B3255D760B0065AFD6.xcbaseline/Info.plist +++ /dev/null @@ -1,88 +0,0 @@ - - - - - runDestinationsByUUID - - 50A052D5-C270-4C3E-823B-FCBB6C3E6539 - - localComputer - - busSpeedInMHz - 400 - cpuCount - 1 - cpuKind - 6-Core Intel Core i7 - cpuSpeedInMHz - 2600 - logicalCPUCoresPerPackage - 12 - modelCode - MacBookPro16,1 - physicalCPUCoresPerPackage - 6 - platformIdentifier - com.apple.platform.macosx - - targetArchitecture - x86_64 - - 7A4A2454-7A24-425D-84C2-116320B87F1E - - localComputer - - busSpeedInMHz - 100 - cpuCount - 1 - cpuKind - Quad-Core Intel Core i7 - cpuSpeedInMHz - 2700 - logicalCPUCoresPerPackage - 8 - modelCode - MacBookPro13,3 - physicalCPUCoresPerPackage - 4 - platformIdentifier - com.apple.platform.macosx - - targetArchitecture - x86_64 - targetDevice - - modelCode - iPhone12,3 - platformIdentifier - com.apple.platform.iphonesimulator - - - FA3A7E89-3F08-4E7F-890A-B0903F68A94C - - localComputer - - busSpeedInMHz - 100 - cpuCount - 1 - cpuKind - Quad-Core Intel Core i7 - cpuSpeedInMHz - 2700 - logicalCPUCoresPerPackage - 8 - modelCode - MacBookPro13,3 - physicalCPUCoresPerPackage - 4 - platformIdentifier - com.apple.platform.macosx - - targetArchitecture - x86_64 - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/09B0B19E-F5A6-42CF-AD3D-082A3B8B31B3.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/09B0B19E-F5A6-42CF-AD3D-082A3B8B31B3.plist deleted file mode 100644 index dac628f3f6..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/09B0B19E-F5A6-42CF-AD3D-082A3B8B31B3.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - classNames - - ParsingTests - - testLargeResponse() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.88797 - baselineIntegrationDisplayName - Local Baseline - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/22F19570-674E-47F1-A426-4EFB879DC0E3.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/22F19570-674E-47F1-A426-4EFB879DC0E3.plist deleted file mode 100644 index 8a9640db1e..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/22F19570-674E-47F1-A426-4EFB879DC0E3.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - classNames - - ParsingTests - - testLargeResponse() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 1.1037 - baselineIntegrationDisplayName - Local Baseline - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/Info.plist b/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/Info.plist deleted file mode 100644 index b1d57c292e..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcbaselines/9FC631321E6AE2080062707E.xcbaseline/Info.plist +++ /dev/null @@ -1,52 +0,0 @@ - - - - - runDestinationsByUUID - - 09B0B19E-F5A6-42CF-AD3D-082A3B8B31B3 - - targetArchitecture - arm64e - targetDevice - - modelCode - iPhone11,2 - platformIdentifier - com.apple.platform.iphoneos - - - 22F19570-674E-47F1-A426-4EFB879DC0E3 - - localComputer - - busSpeedInMHz - 100 - cpuCount - 1 - cpuKind - Intel Core i7 - cpuSpeedInMHz - 2700 - logicalCPUCoresPerPackage - 8 - modelCode - MacBookPro13,3 - physicalCPUCoresPerPackage - 4 - platformIdentifier - com.apple.platform.macosx - - targetArchitecture - x86_64 - targetDevice - - modelCode - iPhone11,2 - platformIdentifier - com.apple.platform.iphonesimulator - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/Apollo.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/Apollo.xcscheme deleted file mode 100644 index 8c7abff2a2..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/Apollo.xcscheme +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloAPI.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloAPI.xcscheme deleted file mode 100644 index 43b365cbc0..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloAPI.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme deleted file mode 100644 index a85ab02ab2..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloCodegenLib.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloPerformanceTests.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloPerformanceTests.xcscheme deleted file mode 100644 index c72a6f6415..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloPerformanceTests.xcscheme +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloSQLite.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloSQLite.xcscheme deleted file mode 100644 index fc7b7c0765..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloSQLite.xcscheme +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloServerIntegrationTests.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloServerIntegrationTests.xcscheme deleted file mode 100644 index 4e2089697f..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloServerIntegrationTests.xcscheme +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloUtils.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloUtils.xcscheme deleted file mode 100644 index 97780a9180..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloUtils.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloWebSocket.xcscheme b/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloWebSocket.xcscheme deleted file mode 100644 index ef6225b929..0000000000 --- a/Apollo.xcodeproj/xcshareddata/xcschemes/ApolloWebSocket.xcscheme +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ApolloTestSupport.podspec b/ApolloTestSupport.podspec new file mode 100644 index 0000000000..ac22c314fe --- /dev/null +++ b/ApolloTestSupport.podspec @@ -0,0 +1,20 @@ +Pod::Spec.new do |s| + version = `scripts/get-version.sh` + s.name = 'ApolloTestSupport' + s.version = version + s.author = 'Apollo GraphQL' + s.homepage = 'https://github.com/apollographql/apollo-ios' + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.summary = "TODO" + s.source = { :git => 'https://github.com/apollographql/apollo-ios.git', :tag => s.version } + s.requires_arc = true + s.swift_version = '5.6' + s.ios.deployment_target = '12.0' + s.osx.deployment_target = '10.14' + s.tvos.deployment_target = '12.0' + s.watchos.deployment_target = '5.0' + + s.source_files = 'Sources/ApolloTestSupport/*.swift' + s.dependency 'Apollo', '= ' + version + +end diff --git a/CHANGELOG.md b/CHANGELOG.md index da9ed44543..ef5f929d29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,681 @@ -# Change log +# Change Log + +## v1.9.3 + +### Fixed + +- **Fix injecting of context for UploadRequest:** Any request context passed into an upload request was not being added to the HTTP request and would not be available to the interceptor chain. See PR ([#302](https://github.com/apollographql/apollo-ios-dev/pull/302)). _Thanks to [@RobertDresler](https://github.com/RobertDresler) for the contribution._ +- **Added support for SPM Package.resolved format version 3 ([#3355](https://github.com/apollographql/apollo-ios/issues/3355)):** When using Xcode 15.3 the codegen CLI would fail the `generate` command with an error stating the Package.resolve file version is unsupported. Version 3 is now accepted as a valid file format for the codegen version checker. See PR ([#304](https://github.com/apollographql/apollo-ios-dev/pull/304)). +- **PrivacyInfo.xcprivacy file is invalid for Apollo and ApolloApi ([#3359](https://github.com/apollographql/apollo-ios/issues/3359)):** We received reports that when submitting to the App Store the submission would fail with an error stating that the privacy manifests were invalid. We identified the error and updated the privacy files. See PR ([#309](https://github.com/apollographql/apollo-ios-dev/pull/309)). _Thanks to [@azilbershtein](https://github.com/azilbershtein) for raising the issue._ + +### Improvement + +- **Provide a direct means to observe changes in ApolloStore:** `ApolloStore` now exposes it's subscriber mechanism publicly. This means you can now observe and receive notifications about changes to the store. See PR ([#300](https://github.com/apollographql/apollo-ios-dev/pull/300)). _Thanks to [@jamesonwilliams](https://github.com/jamesonwilliams) for the contribution._ +- **Remove redundant iteration in EntitySelectionTree merging algorithm:** The conditions for merging selections were revisited and we identified, and removed, a redundant iteration. This is a significant performance improvement as it removes an entire additional iteration through all the conditional scopes in the tree. See PR ([#308](https://github.com/apollographql/apollo-ios-dev/pull/308)). + +## v1.9.2 + +### Fixed + +- **Backwards Compatibility issues in 1.9.1:** 1.9.1 introduced a minor breaking change for some users who were creating a custom implementaiton of `ApolloClientProtocol`. Sorry about that! This patch release fixed the compatiblity. See PR [#290](https://github.com/apollographql/apollo-ios-dev/pull/290). _Thanks to [@michaelloo](https://github.com/michaelloo) for raising the issue._ + +### Improvement + +- **Session and task descriptions parameters added to `URLSessionClient` ([#286](https://github.com/apollographql/apollo-ios-dev/pull/286)):** The `URLSessionClient` now allows you to set a `sessionDescription` on the session and `taskDescription` on each task. These are helpful when debugging, especially when analyzing HTTP traffic with Instruments. _Thanks to [@hishma](https://github.com/hishma) for the contribution._ + +## v1.9.1 + +### Fixed + +- **`SelectionSet` generated initializers don't compile with `self` parameter ([#3330](https://github.com/apollographql/apollo-ios/issues/3330)):** Selection set initializers now use a local property name when the external property name is a Swift reserved word; see PR [#257](https://github.com/apollographql/apollo-ios-dev/pull/257). _Thanks to [@grantjbutler](https://github.com/grantjbutler) for raising the issue._ +- **asXXXXXXX property on a union never returning `nil` if selection set empty ([#3326](https://github.com/apollographql/apollo-ios/issues/3326)):** - The codegen logic to determine whether a selection set is composite or not has been improved to handle the case when `__typename` was the only field in the selection set; see PR [#261](https://github.com/apollographql/apollo-ios-dev/pull/261). _Thanks to [@vincentisambart](https://github.com/vincentisambart) for raising the issue._ + +### Improvement + +- **Feature/ContextIdentifier for the mutate queries ([#281](https://github.com/apollographql/apollo-ios-dev/pull/281)):** Mutation operations can now be given a context identifier to be used later in the request. _Thanks to [@VladimirK-ah](https://github.com/VladimirK-ah) for the contribution._ + +## v1.9.0 + +### Improvement + +- **New import directive for operations:** GraphQL operations now support a directive to control custom module import statements in the generated file. Any operation that includes the directive `@import(module:)`, on the defintion line, with a supplied `String` as the module name will have that module used in a Swift `import` statement at the top of the operation file and any referenced fragments. _Thank you to [@hemel](https://github.com/hemel) for the contribution ([#236](https://github.com/apollographql/apollo-ios-dev/pull/236) / [#245](https://github.com/apollographql/apollo-ios-dev/pull/245))._ + +### Fixed + +- **The `fragmentDefinition` remains in all generated fragments when `operationDocumentFormat` does not include `.definition` ([#3282](https://github.com/apollographql/apollo-ios/issues/3282)):** Code generation will now only generate definitions in fragment files if the `operationDocumentFormat` config contains the `.definition` value ([#218](https://github.com/apollographql/apollo-ios-dev/pull/218)). _Thank you to [@jimisaacs](https://github.com/jimisaacs) for raising the issue._ +- **Custom scalar file header comment ([#3323](https://github.com/apollographql/apollo-ios/issues/3323)):** The header comment for generated custom scalar files was incorrectly changed to state that the output "should not be edited" but the file content could still be edited and would not be overwritten. The header comment has been changed back to state that the contents will be preserved during subsequent codegen executions. _Thank you to [@matsudamper](https://github.com/matsudamper) for raising the issue and the contribution to fix it ([#243](https://github.com/apollographql/apollo-ios-dev/pull/243))._ + +### Changed + +- **WebSocket disconnection errors are no longer printed to stdout ([#3325](https://github.com/apollographql/apollo-ios/issues/3325)):** See PR ([#253](https://github.com/apollographql/apollo-ios-dev/pull/253)) _Thank you to [@sgade](https://github.com/sgade) for raising the issue._ + +## v1.8.0 + +### Fixed +- **Duplicate `@defer` directive error ([#235](https://github.com/apollographql/apollo-ios-dev/pull/235)):** When executing codegen against Apollo Router and a schema that supports the `@defer` directive it would fail with an error stating the directive is duplicated. + +### Improvement + +- **Added `InputObject`` casing strategy ([#137](https://github.com/apollographql/apollo-ios-dev/pull/137)):** We've added a new casing strategy option for InputObjects which mimics the behaviour of the enum case conversion strategy. _Thank you to [@alexifrim](https://github.com/alexifrim) for raising this in issue [#3257](https://github.com/apollographql/apollo-ios/issues/3257)._ +- **Added `GraphQLResult` conversion extension ([#139](https://github.com/apollographql/apollo-ios-dev/pull/139)):** `GraphQLResult` response data can now be easily converted into a JSON dictionary. This is useful for taking server response data and serializing it into a JSON dictionary which can then be used in a test suite. +- **Codegen performance improvements ([#152](https://github.com/apollographql/apollo-ios-dev/pull/152)):** There has been a bunch of refactoring work to prepare for future codegen features but we've also managed to squeeze out some performance improvements. + +## v1.7.1 + +### Fixed + +- **Fixed inconsistent ordering of fragments in generated operation definitions ([#130](https://github.com/apollographql/apollo-ios-dev/pull/130)):** In order to make the ordering of fragments consistent, they are now alphabetized. This is a change to the data that gets sent over the wire when making a network request for an operation with fragments. **[Persisted Queries](https://www.apollographql.com/docs/ios/fetching/persisted-queries) users should re-register their queries when upgrading to this version.** _Thank you to [@scottasoutherland](https://github.com/scottasoutherland) for reporting the issue._ + +### Improvement + +- **Add initializer for `SelectionSet` that takes a `[String: Any]` JSON object ([#102](https://github.com/apollographql/apollo-ios-dev/pull/102)):** _Thank you to [@Cookiezby](https://github.com/Cookiezby) for the contribution._ + + +## v1.7.0 + +**`ApolloCodegenLib` Now Uses Swift Concurrency** +To improve the performance of the code generation, the `ApolloCodegenLib` now uses `async/await`. Code generation is now parallelized and should complete much faster for users with a large number of GraphQL files. +This means that the entry point function, `ApolloCodegen.build(with configuration:)` is now an `async` function. For users using the `ApolloCodegenLib` directly, you will need to make your call sites into this function use `async/await`. In most cases, this requires minimal code changes. Please see the [1.7.0 migration guide](https://www.apollographql.com/docs/ios/migrations/1.7) for information on how to upgrade. + +See PR [#57](https://github.com/apollographql/apollo-ios-dev/pull/57). + +### Fixed + +- **Fixed a bug with ApolloAPI.Object clashing with custom objects name Object ([#94](https://github.com/apollographql/apollo-ios-dev/pull/94)):** _Thank you to [215eight](https://github.com/215eight) for reporting the issue._ + +## v1.6.1 + +### Fixed + +- **Fix bug with AnyHashable coercion ([#68](https://github.com/apollographql/apollo-ios-dev/pull/68)):** This is an additional fix for the crashes on iOS 14.4.1. + +## v1.6.0 + +The Apollo iOS ecosystem is changing in the 1.6.0 release in order to provide a better development experience for users. For most users nothing will change, while some users will see a minor difference. The biggest change is that the `ApolloCodegenLib` is now in a separate repo/package that will need to be included as its own dependency from [apollo-ios-codegen](https://github.com/apollographql/apollo-ios-codegen) if you are doing your code generation through Swift. If you are using the codegen CLI then no changes are necessary. + +For a detailed breakdown of the changes please see this [GitHub Issue](https://github.com/apollographql/apollo-ios/issues/3240). + +### Fixed + +- **Fixed crashes in iOS 14.4 and below ([#61](https://github.com/apollographql/apollo-ios-dev/pull/61)):** _Thank you to [matijakregarGH](https://github.com/matijakregarGH) for reporting the issue._ + +## v1.5.2 + +The purpose of this release is to provide a deprecation message to users of `ApolloCodegenLib` who are scripting their code generation in advance of an upcoming change to our libraries and repo structure. Beginning with the upcoming 1.6.0 release the code generation libraries will be their own SPM package in their own repo which will require you to add a new dependency to you project in order for your code generation scripting to compile. More information can be found in our [announcement](https://github.com/apollographql/apollo-ios/issues/3240) of this change. + +**If you would like to avoid this deprecation warning in your builds feel free to stay on 1.5.1 or earlier, this warning will be gone in the 1.6.0 release** + +PR containing deprecation warning for reference: [#3243](https://github.com/apollographql/apollo-ios/pull/3243). + +## v1.5.1 + +### Improvement + +- **Added `OutputOptions` property to codegen for marking generated classes as `final` ([#3189](https://github.com/apollographql/apollo-ios/pull/3189)):** _Thank you to [@Mordil](https://github.com/Mordil) for the contribution._ + +### Fixed + +- **Codegen `itemsToGenerate` option for `.all` not generating an operation manifest ([#3215](https://github.com/apollographql/apollo-ios/pull/3215)):** _Thank you to [@TizianoCoroneo](https://github.com/TizianoCoroneo) for finding and fixing the issue._ +- **Codegen operation manifest inadvertantly being generated twice ([#3225](https://github.com/apollographql/apollo-ios/pull/3225)):** _Thank you to [@jimisaacs](https://github.com/jimisaacs) for finding and fixing the issue._ + +## v1.5.0 + +### New + +- **Added the ability pass a custom `RequestContext` to networking APIs ([#3198](https://github.com/apollographql/apollo-ios/pull/3198)):** _Thank you to [@danieltiger](https://github.com/danieltiger) for the contribution._ + - **Minor Breaking Change:** The `requestContext` parameter is optional with a default value of `nil`. This means there are no breaking changes to the APIs for making networking calls. However, the `requestContext` parameter was also added to the `ApolloClientProtocol`. For custom implementations of this protocol (usually used for unit testing), you will need to add the `requestContext` parameter to your function signatures. + +### Fixed + +- **Null values are no longer stripped from the underlying data used by generated `SelectionSet` models ([apollo-ios-dev/#25](https://github.com/apollographql/apollo-ios-dev/pull/25)):** + - When these models were manually inserted into the cache, the null fields, which were stripped, were not written to the cache. This caused unintended cache misses when fetching those values back out of the cache. + - This fixes [#3092](https://github.com/apollographql/apollo-ios/issues/3092). _Thank you to [@ +aleksanderlorenc-lw](https://github.com/aleksanderlorenc-lw) for raising this issue._ + +## v1.4.0 + +### New + +- **Added the ability to set a casing strategy for field names in code generation ([#2738](https://github.com/apollographql/apollo-ios/issues/2738)):** See PR ([#3171](https://github.com/apollographql/apollo-ios/pull/3171)). _Thank you to [@Spatel91111](https://github.com/Spatel91111) for the feature request._ + +### Improvement + +- **Updated the way persisted queries are configured for code and manifest generation:** See PR ([#3175](https://github.com/apollographql/apollo-ios/pull/3175)) +- **Updated docs for `other` schema module type to provide more clarity ([#3164](https://github.com/apollographql/apollo-ios/issues/3164)):** See PR ([#3170](https://github.com/apollographql/apollo-ios/pull/3170)) _Thank you to [@Mordil](https://github.com/Mordil) for suggesting this update._ + +## v1.3.3 + +### Fixed +- **Fix two issues with generated models:** See PR ([#3168](https://github.com/apollographql/apollo-ios/pull/3168)). _Thank you to [@iAmericanBoy](https://github.com/iAmericanBoy) for finding these issues and providing a reproduction case._ +- **Fix computation of operation identifiers for persisted queries:** See PR ([#3163](https://github.com/apollographql/apollo-ios/pull/3163)). _Thank you to [@WolframPRO](https://github.com/WolframPRO) for finding these issues._ + +## v1.3.2 + +### Improved +- **Throw an error when an invalid key is present in the codegen configuration JSON ([#2942](https://github.com/apollographql/apollo-ios/issues/2942)):** See PR ([#3125](https://github.com/apollographql/apollo-ios/pull/3125)) _Thank you to [@Iron-Ham](https://github.com/Iron-Ham) for the contribution._ +- **Cleanup unused imports and declarations. ([#3099](https://github.com/apollographql/apollo-ios/issues/3099)):** See PR ([#3100](https://github.com/apollographql/apollo-ios/pull/3100)) _Thank you to [@Iron-Ham](https://github.com/Iron-Ham) for raising the issue and contributing the fix._ +- **Improvement to response code error API ([#2426](https://github.com/apollographql/apollo-ios/issues/2426)):** See PR ([#3123](https://github.com/apollographql/apollo-ios/pull/3123)). _Thank you to [@dfperry5](https://github.com/dfperry5) for the contribution._ +- **Improved file path support for operation manifest generation:** See PR ([#3128](https://github.com/apollographql/apollo-ios/pull/3128)) + +### Fixed +- **Fix two issues in test mock generation:** See PR ([#3120](https://github.com/apollographql/apollo-ios/pull/3120)). _Thank you to [@TizianoCoroneo](https://github.com/TizianoCoroneo) for finding this issue and contributing the fix._ +- **Fixed precondition failure when surpassing graphql-js max error count ([#3126](https://github.com/apollographql/apollo-ios/issues/3126)):** See PR ([#3132](https://github.com/apollographql/apollo-ios/pull/3132)). + +### Deprecated +- **Deprecated `queryStringLiteralFormat` in `ApolloCodegenConfiguration`:** Query string literals will now always be generated as single line strings. See PR ([#3129](https://github.com/apollographql/apollo-ios/pull/3129)). + +## v1.3.1 + +### Fixed +- **Fix crashes in test mocks when setting an array of union types ([#3023](https://github.com/apollographql/apollo-ios/pull/3023)):** See PR ([#3089](https://github.com/apollographql/apollo-ios/pull/3089)). _Thank you to [@jabeattie](https://github.com/jabeattie) & [@scottasoutherland](https://github.com/scottasoutherland) for raising the issue._ + +### Deprecated +- **Deprecated `APQConfig` & `operationIdentifiersPath` in `ApolloCodegenConfiguration`:** These have been replaced with `OperationDocumentFormat` and `OperationManifestFileOutput` respectively. Please see the documentation for [`ApolloCodegenConfiguration`](https://www.apollographql.com/docs/ios/code-generation/codegen-configuration) for more information. + +## v1.3.0 + +Though `1.3.0` is a minor version bump, some critical issues were addressed in this version that requires a small breaking change during the upgrade. While we strive to make the upgrade path for minor versions seamless, these issues could not be reasonably resolved without requiring this migration. + +For a detailed explanation of the breaking changes and a guide on how to migrate to `1.3.0`, see our [migration guide](https://www.apollographql.com/docs/ios/migrations/1.3). + +### Breaking +- **Using reserved keyword `Type` as in selection fields does not compile ([#3006](https://github.com/apollographql/apollo-ios/issues/3006)):** See PR [#3058](https://github.com/apollographql/apollo-ios/pull/3058). _Thank you to [@Nielssg](https://github.com/Nielssg) for raising the issue._ +- **Memory leak from `InterceptorRequestChain` when ending the chain with `returnValueAsync` ([#3057](https://github.com/apollographql/apollo-ios/issues/3057)):** See PR [#3070](https://github.com/apollographql/apollo-ios/pull/3070). _Thank you to [@marksvend](https://github.com/marksvend) for raising the issue._ + +## v1.2.2 + +### Added +- **Support SOCKS proxies for debugging websocket based subscriptions([#2788](https://github.com/apollographql/apollo-ios/issues/2788)):** _Thank you to [@tahirmit](https://github.com/tahirmt) for the contribution._ + +### Fixed +- **Fix conversion of generated models into nested type cases ([#2989](https://github.com/apollographql/apollo-ios/issues/2989) & [#2980](https://github.com/apollographql/apollo-ios/issues/2980)):** In some cases, the generated models were missing types when calculating which fragments were fulfilled for a selection set. This was causing type case conversion to return `nil` incorrectly. See PR [#3067](https://github.com/apollographql/apollo-ios/pull/3067). _Thank you to [@tgyhlsb](https://github.com/tgyhlsb) and [@dafurman](https://github.com/dafurman) for raising these issues._ +- **Fix crashes in code generation when merging fragments at definition root ([#3071](https://github.com/apollographql/apollo-ios/issues/3071)):** When fragments with type conditions were defined on the root of an operation or named fragment, the code generation engine was crashing. See PR [#3073](https://github.com/apollographql/apollo-ios/pull/3073). _Thank you to [@tahirmit](https://github.com/tahirmt) for raising and helping us reproduce this issue._ +- **Fix parsing of input objects as default values for input params ([#2978](https://github.com/apollographql/apollo-ios/issues/2978)):** The codegen engine will no longer crash in this situation. _Thank you to [@ecunha-ta](https://github.com/ecunha-ta) for raising the issue._ + +## v1.2.1 + +### Improved +- **Added new validation to alert users to type naming conflict when running code generation([#2405](https://github.com/apollographql/apollo-ios/issues/2405)):** See PR [#3041](https://github.com/apollographql/apollo-ios/pull/3041). + +### Fixed +- **Int values failing to cast to Scalar Type during cache key resolution ([#3034](https://github.com/apollographql/apollo-ios/issues/3034)):** See PR [#3037](https://github.com/apollographql/apollo-ios/pull/3037). _Thank you to [@asbhat](https://github.com/asbhat) for raising the issue._ +- **Fix malformed RootEntityType on generated fragment with `@include` condition. ([#2962](https://github.com/apollographql/apollo-ios/issues/2962)):** See PR [#3045](https://github.com/apollographql/apollo-ios/pull/3045). _Thank you to [@alexisbronchart](https://github.com/alexisbronchart) for raising the issue._ + + +## v1.2 + +Though 1.2 is a minor version bump, a critical problem was addressed in this version that requires a small breaking change during the upgrade. While we strive to make the upgrade path for minor versions seamless, this issue could not be reasonably resolved without requiring this migration. + +**For most users, this migration will only require a single change to your `SchemaConfiguration.swift` file.** + +For a detailed explanation of the breaking changes and a guide on how to migrate to v1.2, see our [migration guide](https://www.apollographql.com/docs/ios/migrations/1.2). + +### Breaking +- **Cache Key Configuration API Changes ([#2990](https://github.com/apollographql/apollo-ios/pull/2990)):** The API for configuring custom cache keys has had a minor change in this version. The signature of the `cacheKeyInfo(for:object:)` function, defined in your generated SchemaConfiguration.swift file, has been modified. For more information, see our [migration guide](https://www.apollographql.com/docs/ios/migrations/1.2). + +### Improved +- **Improved performance of GraphQL execution ([#2990](https://github.com/apollographql/apollo-ios/pull/2990)):** Improvements to the `GraphQLExecutor` resulted in a ~15-20% reduction in execution time for parsing and mapping network response or cache data onto generated models. +- **Improved performance of generated model initialization and type conversions ([#2990](https://github.com/apollographql/apollo-ios/pull/2990)):** The `DataDict` used to store the data for generated models has been updated to use copy-on-write value semantics. This resulted in a ~70-80% reduction in the execution time of initialization and type case conversions in the generated models. + +### Fixed +- **Pruning generated files for `.relative(subpath:)` operations ([#2969](https://github.com/apollographql/apollo-ios/issues/2969)):** See PR [#2994](https://github.com/apollographql/apollo-ios/pull/2994). _Thank you to [@jimisaacs](https://github.com/jimisaacs) for raising the issue._ +- **InputObjects generated with incorrect getter/setter key ([#2858](https://github.com/apollographql/apollo-ios/issues/2858)):** See PR [#2996](https://github.com/apollographql/apollo-ios/pull/2996). _Thank you to [@Austinpayne](https://github.com/Austinpayne) for raising the issue._ +- **Generates conflicting types for fields of singular and plural names ([#2850](https://github.com/apollographql/apollo-ios/issues/2850)):** See PR [#3009](https://github.com/apollographql/apollo-ios/pull/3009). _Thank you to [@sgade](https://github.com/sgade) for raising the issue._ +- **Equality operator shows incorrect values based on value of `__fulfilled` ([#2944](https://github.com/apollographql/apollo-ios/issues/2944)):** See PR [#2990](https://github.com/apollographql/apollo-ios/pull/2990). _Thank you to [@scottasoutherland](https://github.com/scottasoutherland) for raising the issue._ + +### New +- **Add option to generate objects with `internal` access modifier ([#2630](https://github.com/apollographql/apollo-ios/issues/2630)):** See PR [#2917](https://github.com/apollographql/apollo-ios/pull/2917). _Thank you to [@simonbilskyrollins](https://github.com/simonbilskyrollins) for the feature request._ + +## v1.1.3 + +### Fixed +- **`@dynamicMember` conflicting field name ([#2950](https://github.com/apollographql/apollo-ios/issues/2950)):** The subscript setters have been changed to allow a selection set property named `hash`. [#2965](https://github.com/apollographql/apollo-ios/pull/2965) _Thank you to [@renanbdias](https://github.com/renanbdias) for raising the issue._ +- **Disallow certain targetNames in code generation ([#2958](https://github.com/apollographql/apollo-ios/issues/2958)):** `apollo` is no longer allowed as a target name otherwise it causes a conflict when importing `Apollo` as a module. [#2972](https://github.com/apollographql/apollo-ios/pull/2972) _Thank you to [@moopoints](https://github.com/moopoints) for raising the issue._ +- **Fully Qualify name of RootEntityType and mergedSources ([#2949](https://github.com/apollographql/apollo-ios/issues/2949)):** Selection set types use fully qualified namespacing to prevent conflicts with other types. [#2956](https://github.com/apollographql/apollo-ios/pull/2956) _Thank you to [@martin-muller](https://github.com/martin-muller) for raising the issue._ +- **SelectionSet Codegen `__typename` fix ([#2955](https://github.com/apollographql/apollo-ios/issues/2955)):** Custom root types defined in the schema are now correctly applied to selection set fields typename definitions [#2983](https://github.com/apollographql/apollo-ios/pull/2983) _Thank you to [@ynnadrules](https://github.com/ynnadrules) for raising the issue._ + +## v1.1.2 + +### Fixed +- **Crash after calling `cancel()` on `Cancellable` ([#2932](https://github.com/apollographql/apollo-ios/issues/2932)):** Calling `cancel()` on a non-subscription `Cancellable` will now correctly handle the lifetime of the internally `Unmanaged` object. [#2943](https://github.com/apollographql/apollo-ios/pull/2943) - _Thank you to [@yonaskolb](https://github.com/yonaskolb) for raising the issue._ +- **Deprecation messages are not escaped ([#2879](https://github.com/apollographql/apollo-ios/issues/2879)):** If escaped characters are used in GraphQL deprecation messages they are now properly escaped in the rendered Swift warning or attribution message. [#2951](https://github.com/apollographql/apollo-ios/pull/2951) _Thank you to [@djavan-bertrand](https://github.com/djavan-bertrand) for raising the issue._ + +### Added +- **Add injecting additionalErrorHandler for upload operations to RequestChainNetworkTransport ([#2948](https://github.com/apollographql/apollo-ios/pull/2948)):** `Upload` operations can now have custom error interceptors like other operations. [#2948](https://github.com/apollographql/apollo-ios/pull/2948) _Thank you to [@RobertDresler](https://github.com/RobertDresler) for the contribution._ + +## v1.1.1 + +### Fixed +- **Version 1.1.0 does not compile when installed via CocoaPods ([#2936](https://github.com/apollographql/apollo-ios/issues/2936)):** Module names not present in CocoaPods builds have been removed from type declarations. [#2937](https://github.com/apollographql/apollo-ios/pull/2937) - _Thank you to [@simonliotier](https://github.com/simonliotier) for raising the issue._ +- **Crash when using mocks for Double Nested Arrays ([#2809](https://github.com/apollographql/apollo-ios/issues/2809)):** Test mock data is now correctly applied to the selection set. [#2939](https://github.com/apollographql/apollo-ios/pull/2939) - _Thank you to [@scottasoutherland](https://github.com/scottasoutherland) for raising the issue._ +- **In 1.1.0, passing custom scalars or GraphQLEnum to mocks fails ([#2928](https://github.com/apollographql/apollo-ios/issues/2928)):** Test mock data is now correctly applied to the selection set. [#2939](https://github.com/apollographql/apollo-ios/pull/2939) - _Thank you to [@scottasoutherland](https://github.com/scottasoutherland) for raising the issue._ + +## v1.1.0 + +Apollo iOS v1.1 primarily focuses on adding generated initializers to the generated operation models. + +In most cases, the upgrade from v1.0 to v1.1 should require no changes to your code. + +### **Breaking** +- **Changed generated fragment accessors with inclusion conditions:** When conditionally spreading a fragment with an `@include/@skip` directive that has a different parent type than the selection set it is being spread into, the shape of the generated models has changed. + - For example, a fragment accessor defined as `... on DetailNode @include(if: $includeDetails)` would have previously been named `asDetailNode`; it will now be generated as `asDetailNodeIfIncludeDetails`. +- While no breaking changes were made to official public APIs, some *underscore prefixed* APIs that are `public` but intended for internal usage only have been changed. + - **SelectionSet fulfilled fragment tracking:** `SelectionSet` models now keep track of which fragments were fulfilled during GraphQL execution in order to enable conversions between type cases. While this does not cause functional changes while using public APIs, this is a fundamental change to the way that the underlying data for a `SelectionSet` is formatted, it is now required that all `SelectionSet` creation must be processed by the `GraphQLExecutor` or a generated initializer that is guaranteed to correctly format the data. **This means that initializing a `SelectionSet` using raw JSON data directly will no longer work.** Please ensure that raw JSON data is only used with the new `RootSelectionSet.init(data: variables)` initializer. +### Fixed +- **Null/nil value parsing issues**. In some situations, writing/reading `null` or `nil` values to the cache was causing crashes in 1.1 Beta 1. This is now fixed. +### Added +- **Configuration option for generating initializers on SelectionSet models:** You can now get initializers for your generated selection set models by setting the `selectionSetInitializers` option on your code generation configuration. Manually initialized selection sets can be used for a number of purposes, including: + * Adding custom data to the normalized cache + * Setting up fixture data for SwiftUI previews or loading states + * An alternative to Test Mocks for unit testing +- **Safe initialization of `SelectionSet` models with raw JSON:** In 1.0, initializing `SelectionSet` models with raw JSON was unsafe and required usage of *underscore prefixed* APIs that were intended for internal usage only. Apollo iOS 1.1 introduces a new, safe initializer: `RootSelectionSet.init(data: variables)`. + * Previously, if you provided invalid JSON, your selection set's were unsafe and may cause crashes when used. The new initializer runs a lightweight version of GraphQL execution over the provided JSON data. This quickly parses, validates, and transforms the JSON data into the format required by the `SelectionSet` models. If the provided data is invalid, this initializer `throws` an error, ensuring that your model usage is always safe. +- **Added support for multipart subscriptions over HTTP.** +### Changed +- **Generate `__typename` selection for generated models:** In 1.1, the code generator adds the `__typename` field to each root object. In previous versions, this selection was automatically inferred by the `GraphQLExecutor`, however generating it directly should improve performance of GraphQL execution. + +## v1.1.0-beta.1 + +This is the first Beta Release of Apollo iOS 1.1. Version 1.1 primarily focuses on adding generated initializers to the generated operation models. + +While no breaking changes were made to official public APIs, some *underscore prefixed* APIs that are `public` but intended for internal usage only have been changed. + +### Added +- **Configuration option for generating initializers on SelectionSet models:** You can now get initializers for your generated selection set models by setting the `selectionSetInitializers` option on your code generation configuration. Manually initialized selection sets can be used for a number of purposes, including: + * Adding custom data to the normalized cache + * Setting up fixture data for SwiftUI previews or loading states + * An alternative to Test Mocks for unit testing +- **Safe initialization of `SelectionSet` models with raw JSON:** In 1.0, initializing `SelectionSet` models with raw JSON was unsafe and required usage of *underscore prefixed* APIs that were intended for internal usage only. Apollo iOS 1.1 introduces a new, safe initializer: `RootSelectionSet.init(data: variables)`. + * Previously, if you provided invalid JSON, your selection set's were unsafe and may cause crashes when used. The new initializer runs a lightweight version of GraphQL execution over the provided JSON data. This quickly parses, validates, and transforms the JSON data into the format required by the `SelectionSet` models. If the provided data is invalid, this initializer `throws` an error, ensuring that your model usage is always safe. +- **Added support for multipart subscriptions over HTTP.** +### Changed +- **SelectionSet fulfilled fragment tracking:** `SelectionSet` models now keep track of which fragments were fulfilled during GraphQL execution in order to enable conversions between type cases. While this does not cause functional changes while using public APIs, this is a fundamental change to the way that the underlying data for a `SelectionSet` is formatted, it is now required that all `SelectionSet` creation must be processed by the `GraphQLExecutor` or a generated initializer that is guaranteed to correctly format the data. **This means that initializing a `SelectionSet` using raw JSON data directly will no longer work.** Please ensure that raw JSON data is only used with the new `RootSelectionSet.init(data: variables)` initializer. +- **Generate `__typename` selection for generated models:** In 1.1, the code generator adds the `__typename` field to each root object. In previous versions, this selection was automatically inferred by the `GraphQLExecutor`, however generating it directly should improve performance of GraphQL execution. +- **Changed generated fragment accessors with inclusion conditions:** When conditionally spreading a fragment with an `@include/@skip` directive that has a different parent type than the selection set it is being spread into, the shape of the generated models has changed. This does not affect generated call sites, but only affects the generated `selection` metadata used internally by the `GraphQLExecutor`. + +## v1.0.7 + +### Fixed +- **Couldn't build when using some reserved words in a schema ([#2765](https://github.com/apollographql/apollo-ios/issues/2765)):** `for` has been added to the list of reserved keywords that are escaped with backticks when used in schema types and operations. [#2772](https://github.com/apollographql/apollo-ios/pull/2772) - _Thank you to [@torycons](https://github.com/torycons) for raising the issue._ +- **Subscript GraphQL variable from dictionary crash when Swift modifier used as key ([#2759](https://github.com/apollographql/apollo-ios/issues/2759)):** Backticks have been removed from subscript keys of input objects. [#2773](https://github.com/apollographql/apollo-ios/pull/2773) - _Thank you to [@SzymonMatysik](https://github.com/SzymonMatysik) for raising the issue._ +- **Unnamed fields in schema results in broken generated Swift code ([#2753](https://github.com/apollographql/apollo-ios/issues/2753)):** The `_` character can be used as a GraphQL field name. [#2769](https://github.com/apollographql/apollo-ios/pull/2769) - _Thank you to [@neakor](https://github.com/neakor) for raising the issue._ +- **LocalCacheMutation with an enum field fails ([#2775](https://github.com/apollographql/apollo-ios/issues/2775)):** When writing selection set data back into the cache, custom scalars are now re-encoded back into their `_jsonValue`. [#2778](https://github.com/apollographql/apollo-ios/pull/2778) - _Thank you to [@dabby-wombo](https://github.com/dabby-wombo) for raising the issue._ +- **DataDict subscript function crashes on iOS 14.4 and under ([#2668](https://github.com/apollographql/apollo-ios/issues/2668)):** `AnyHashable` conversions when accessing `DataDict` properties now perform checks on the base type. [#2784](https://github.com/apollographql/apollo-ios/pull/2784) - _Thank you to [@bdunay3](https://github.com/bdunay3) for raising the issue._ +- **`@include` directive based on variable with default value drops the included data ([#2690](https://github.com/apollographql/apollo-ios/issues/2690)):** The GraphQL executor will now correctly evaluate `GraphQLNullable` conditional variables. [#2794](https://github.com/apollographql/apollo-ios/pull/2794) - _Thank you to [@klanchman](https://github.com/klanchman) for raising the issue._ +- **Interfaces implemented by schema root are not generated ([#2756](https://github.com/apollographql/apollo-ios/issues/2756)):** Interfaces references on the root type Query, Mutation or Subscription are now included in the schema module. [#2816](https://github.com/apollographql/apollo-ios/pull/2816) - _Thank you to [@litso](https://github.com/litso) for raising the issue._ + +### Changed +- **HTTP headers format in schema download configuration JSON ([#2661](https://github.com/apollographql/apollo-ios/issues/2661)):** `HTTPHeaders` in the `ApolloSchemaDownloadConfiguration` section of the codegen configuration JSON file can now be specified using the more intuitive format `{ "Authorization": ""}`. [#2811](https://github.com/apollographql/apollo-ios/pull/2811) - _Thank you to [@nikitrivedii](https://github.com/nikitrivedii) for raising the issue._ + +## v1.0.6 + +### Fixed +- **Quotes in operation identifiers are not escaped ([#2671](https://github.com/apollographql/apollo-ios/issues/2671)):** Query strings are now enclosed within extended delimiters to allow inclusion of special characters such as quotation marks. [#2701](https://github.com/apollographql/apollo-ios/pull/2701) - _Thank you to [@StarLard](https://github.com/StarLard) for raising the issue._ +- **Cannot find type `graphQLSchema` in scope ([#2705](https://github.com/apollographql/apollo-ios/issues/2705)):** Generated fragments now use the correct schema namespace casing. [#2730](https://github.com/apollographql/apollo-ios/pull/2730) - _Thank you to [@iAmericanBoy](https://github.com/iAmericanBoy) for raising the issue._ +- **Updating a local cache mutation with an optional field fails with a `ApolloAPI.JSONDecodingError.missingValue` error ([#2697](https://github.com/apollographql/apollo-ios/issues/2697)):** Cache mutations will now allow incomplete data to be written to the cache without expecting all fields to be set. Please note that cache manipulation is an advanced feature and you should be aware of how the data written will affect network requests and cache policies. [#2751](https://github.com/apollographql/apollo-ios/pull/2751) - _Thank you to [@amseddi](https://github.com/amseddi) for raising the issue._ +- **`GraphQLEnum` value camel case conversion strategy ([#2640](https://github.com/apollographql/apollo-ios/issues/2640)), ([#2749](https://github.com/apollographql/apollo-ios/issues/2749)):** The camel case conversion logic for GraphQL enums has been improved to handle a wider range of edge cases that were causing invalid Swift code generation. [#2745](https://github.com/apollographql/apollo-ios/pull/2745) - _Thank you to [@ddanielczyk](https://github.com/ddanielczyk) and [@hispanico94](https://github.com/hispanico94) for raising the issues._ +- **Naming collision with `Selection` type from apollo ([#2708](https://github.com/apollographql/apollo-ios/issues/2708)):** `ParentType` and `Selection` types in generated selection sets now use a fully qualified namespace to prevent typename conflicts. [#2754](https://github.com/apollographql/apollo-ios/pull/2754) - _Thank you to [@tahirmt](https://github.com/tahirmt) for raising the issue._ +- **Namespace collision when using "Schema" for `schemaName` ([#2664](https://github.com/apollographql/apollo-ios/issues/2664)):** Certain strings are now disallowed for use as the schema namespace. [#2755](https://github.com/apollographql/apollo-ios/pull/2755) - _Thank you to [@StarLard](https://github.com/StarLard) for raising the issue._ +- **Naming collision with fragments and scalars ([#2691](https://github.com/apollographql/apollo-ios/issues/2691)):** Shared referenced schema types will always use the fully qualified names as the types of fields in selections sets. This prevents collisions with names of other generated selection sets for entity type fields whose names are the same as a referenced schema type. [#2757](https://github.com/apollographql/apollo-ios/pull/2757) - _Thank you to [@scottasoutherland](https://github.com/scottasoutherland) for raising the issue._ +- **Naming collision with `DocumentType` in generated mock code ([#2719](https://github.com/apollographql/apollo-ios/issues/2719)):** All shared referenced schema types within test mocks now use a fully qualified named type. [#2762](https://github.com/apollographql/apollo-ios/pull/2762) - _Thank you to [@dafurman](https://github.com/dafurman) for raising the issue._ +- **Schema/Target/Module name with spaces in it breaks generated code ([#2653](https://github.com/apollographql/apollo-ios/issues/2653)):** Spaces are no longer allowed in the schema namespace. Additional validation has been added to the CLI commands to provide the correct error response. [#2760](https://github.com/apollographql/apollo-ios/pull/2760) - _Thank you to [@Narayane](https://github.com/Narayane) for raising the issue._ + +### Changed +- **Raised minimum required tooling versions:** Swift 5.7 and Xcode 14 are now the minimum required versions to build Apollo iOS and the generated code. [#2695](https://github.com/apollographql/apollo-ios/pull/2695) + +## v1.0.5 + +#### Fixed +- **Fixed - Missing SPM plug-in:** The missing Swift Package product has been added and the `Install CLI` plug-in is now available from the SPM command line and the Xcode project menu. [#2683](https://github.com/apollographql/apollo-ios/pull/2683) + +## v1.0.4 + +#### Fixed +- **Fixed - Convenience initializer for mock objects without fields:** When mock objects did not have any fields a convenience initializer would still be generated causing infinite recursion during initialization. [#2634](https://github.com/apollographql/apollo-ios/pull/2634) _Thank you to [@Gois](https://github.com/Gois) for the contribution!_ +- **Fixed - Ambiguous use of operator '??':** When the nil coalescing operator was used on variables without a type the compiler could not determine which one to use. [#2650](https://github.com/apollographql/apollo-ios/pull/2650). _Thanks to [@skreberem](https://github.com/skreberem) for raising the issue._ +- **Fixed - Generate library for test mock target:** Previous versions would generate the SPM target for test mocks but not a library to properly import it into your unit tests. [#2638](https://github.com/apollographql/apollo-ios/pull/2638) _Thank you to [@Gois](https://github.com/Gois) for the contribution!_ +- **Fixed - Podspec Swift version mismatched with SPM package version:** The Swift version is now the same between the two dependency managers. [#2657](https://github.com/apollographql/apollo-ios/pull/2657) +- **Fixed - Conflicting configuration values:** There is now an error during code generation when the given configuration has conflicting values that cannot be fulfilled. [#2677](https://github.com/apollographql/apollo-ios/pull/2677) +- **Fixed - `DocumentType` namespacing:** The correct module namespacing is now used for `DocumentType` in generated operation code. [#2679](https://github.com/apollographql/apollo-ios/pull/2679) + +#### New +- **New - CLI version checker:** This ensures that the version of the CLI being used to generate Swift code is the same as the version of the Apollo iOS dependency being used. [#2562](https://github.com/apollographql/apollo-ios/issues/2562) + +#### Changed +- **Changed - Removed SPM plug-ins:** The SPM plug-ins for the CLI commands `init`, `fetch-schema`, and `generate` have been removed. There is a new plug-in to install the CLI and the CLI commands should be used from the command line instead. [#2649](https://github.com/apollographql/apollo-ios/pull/2649) +- **Changed - CLI defaults:** The updated default for the output of operation files is now `.inSchemaModule`, and the `init` command now requires a module type to be specified when creating a configuration file. [#2673](https://github.com/apollographql/apollo-ios/pull/2673) + +## v1.0.3 + +- **Fixed - Generated code produces compile error when accessing `data` dictionary in the `InputDict` struct if the name of the accessed property is `hash`:** Dyanamic Member Lookup has been removed from `InputDict` to prevent potential name clashes. [#2607](https://github.com/apollographql/apollo-ios/pull/2607) +- **Fixed - XCFramework archive builds:** `@inlinable` has been removed from parts of `ApolloAPI` that were preventing xcframework builds with the `BUILD_LIBRARY_FOR_DISTRIBUTION` build setting. [#2613](https://github.com/apollographql/apollo-ios/pull/2613) +- **Fixed - `Variables` type in local cache mutations is not properly namespaced:** The `Variables` type in `LocalCacheMutation` now has the required prefix of `GraphQLOperation` to build successfully. [#2615](https://github.com/apollographql/apollo-ios/pull/2615) +- **Fixed - Return error if no matches to schema or operation search paths:** When a schema file could not be found errors were emitted but they were not indicative of the underlying problem. There is now validation to ensure that at least one match of the schema/operation search paths is found otherwise an error is thrown. [#2618](https://github.com/apollographql/apollo-ios/pull/2618) +- **Fixed - File generation should ignore the `.build`/`.swiftpm`/`.Pods` folders:** If code generation was executed from a path where subfolders contained the apollo-ios repo, it would find internal test schemas and fail. These special folders are now ignored. [#2628](https://github.com/apollographql/apollo-ios/pull/2628) +- **Fixed - Download schema relative to root URL:** Even though a root URL could be provided it was not being used in all schema download logic to output the downloaded schema file to the correct locaiton. This is now fixed. [#2609](https://github.com/apollographql/apollo-ios/pull/2609) _Thanks to [@Anteo95](https://github.com/Anteo95) for the contribution._ + +## v1.0.2 + +- **Fixed - Not generating code for subtypes only used as input to mutations:** If you are using a JSON format schema that was fetched via GraphQL introspection code generation will now generate all referenced subtypes. [#2583](https://github.com/apollographql/apollo-ios/pull/2583) _Thank you to [@vrutberg](https://github.com/vrutberg) for reporting the issue._ +- **Fixed - When using the test mock, touching a `GraphQLEnum` property will cause a crash:** JSON Encoding the mocks into the `SelectionSet.DataDict` was causing `CustomScalar` values to get encoded into their JSON values. The mock data is now converted into the correct format for the `SelectionSet.DataDict`. [#2584](https://github.com/apollographql/apollo-ios/pull/2584) _Thank you to [@asapo](https://github.com/asapo) for reporting the issue._ +- **Fixed - Add namespace for ApolloAPI types in generated code:** The Apollo `DocumentType` enum is now correctly namespaced in generated code. [#2585](https://github.com/apollographql/apollo-ios/pull/2585) _Thank you to [@matijakregarGH](https://github.com/matijakregarGH) for reporting the issue._ +- **Fixed - Problems with schema name in generated code:** + - Schema name is now correctly cased for generated code namespacing. [#2586](https://github.com/apollographql/apollo-ios/pull/2586) _Thank you to [@pchmelar](https://github.com/pchmelar) for reporting the issue._ + - The schema name is now not allowed to match any referenced schema type, entity field, or entity list field names. [#2589](https://github.com/apollographql/apollo-ios/pull/2589) +- **Fixed - Test mocks crash when touching array of objects:** Test mock list of objects is now correctly converted into selection set data. [#2591](https://github.com/apollographql/apollo-ios/pull/2591) _Thank you to [@konomae](https://github.com/konomae) for reporting the issue._ +- **Fixed: `GraphQLNullable` nil coalescing:** @exported import statements now ensure that the operator overload is imported when using the generated models. [#2600](https://github.com/apollographql/apollo-ios/pull/2600) _Thank you to bassrock for reporting the issue._ + +## v1.0.1 + +- **Fixed - apollo-ios-cli code generation on CocoaPods installation:** All required resources for the CLI are now bundled correctly. This was an issue in CocoaPods installations where the `generate` command of `apollo-ios-cli` would result in a fatal error. [#2548](https://github.com/apollographql/apollo-ios/pull/2548) _Thank you to [@ilockett](https://github.com/ilockett) for reporting the issue._ +- **Fixed - Xcode integration for Swift Package Plugins:** The SwiftPM plugins now support `XcodePluginContext` from Xcode 14 and accepts the additional command line options that Xcode sends. [#2554](https://github.com/apollographql/apollo-ios/pull/2554) _Thank you to [@SilverTab](https://github.com/SilverTab) for reporting the issue._ +- **Fixed - Escaping input param names:** Input parameter names recognized as reserved words are now escaped to prevent build errors. [#2561](https://github.com/apollographql/apollo-ios/pull/2561) _Thank you to [@puls](https://github.com/puls) for the contribution._ +- **Fixed - Multiline deprecation messages:** Deprecation messages that span multiple lines would previously result in build errors. [#2579](https://github.com/apollographql/apollo-ios/pull/2579) _Thank you to [@TizianoCoroneo](https://github.com/TizianoCoroneo) for the contribution._ +- **Changed - Warnings for deprecated enums:** Deprecated enum cases are no longer annotated with the Swift `@available` attribute. They will now have comments indicating their deprecated status. [#2579](https://github.com/apollographql/apollo-ios/pull/2579) + +## v1.0.0 + +**This is the first major version release of Apollo iOS! The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library.** + +In a nutshell, v1.0.0 brings: +* A new code generation engine built entirely in Swift +* Improvements to the generated models +* Syntax and performance improvements across the entire library + +There is [documentation](https://www.apollographql.com/docs/ios) and a blog post coming soon. Feel free to ask questions by either [opening an issue on our GitHub repo](https://github.com/apollographql/apollo-ios/issues), or [joining the community](https://community.apollographql.com/tags/c/help/6/mobile). + +Thank you to all contributors who have helped us get to this first major release! ❤️ + +## v1.0.0-rc.1 - Release Candidate #1 + +This is the first Release Candidate for Apollo iOS 1.0. The Release Candidate is a fully featured and code-complete representation of the final 1.0 version. This includes full feature parity with the 0.x.x releases. + +API breaking changes are not expected between the Release Candidate and the General Availability (GA) release. The only code changes will be non-breaking bug fixes due to user feedback. The Release Candidate does not have complete documentation or usage guides, which will be completed prior to GA. + +This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **New: Option to Include Deprecated Input Arguments on Fields During Schema Download** Thanks to [@dave-perry](https://github.com/dave-perry) for this addition! +* **Fixed: Code Generation Config JSON File Compatibility** + * Previously, the `apollo-codegen-config.json` file used by the Apollo CLI needed to contain values for all optional fields. When new codegen options were added, this would cause errors until all newly added options has values provided. + * The `Codable` implementation for the `ApolloCodgenConfiguration` has been implemented manually to prevent this. Now, only required fields must be provided, all optional fields can be omitted from the config file safely. + * The CLI's `init` command also now generates a template config file with only the required fields. +* **Fixed: Swift Keywords are escaped when used as names of Input Parameters** +* **Fixed: Compilation Error when using `@skip` and `@include` conditions on the same field** +* **Fixed: Added permissions request to SPM Code Generation Plugin** + * When running the code generation plugin, you will be prompted to give permission for the plugin to write to the package directory. + * This permission check can be avoided by passing the `--allow-writing-to-package-directory` flag when executing the plugin command. +* **Fixed: APQ Operations Will no Longer be Retried when Unrecognized if using `.persistedOperationsOnly`** + * `.persistedOperationsOnly` is for use with allow-listed operations only. If an operation identifier is not recognized by the server, there is no way to register the operation in this configuration. +* **Breaking: Updated `ApolloAPI` internal metadata properties to be `__` prefixed.** + * Generated GraphQL files expose certain properties/functions that are consumed by the `Apollo` library during GraphQL Execution. These members must be public in order to be exposed to `Apollo`, but are not intended for external consumption. We have added underscore prefixes to each of these members to signify that intention, using `__` for GraphQL Metadata (in alignment with the GraphQL Specification) and `_` for `Apollo`'s utility and helper functions. + * The affected signatures are: + * `SelectionSet.schema` -> `SelectionSet.__schema` + * `SelectionSet.selection` -> `SelectionSet.__selection` + * `JSONEncodable.jsonValue` -> `JSONEncodable._jsonValue` + * `JSONDecodable.init(jsonValue:)` -> `JSONDecodable.init(_jsonValue:)` + * `AnyHashableConvertible.asAnyHashable` -> `AnyHashableConvertible._asAnyHashable` + * `OutputTypeConvertible.asOutputType` -> `OutputTypeConvertible._asOutputType` + * `GraphQLOperation.variables` -> `GraphQLOperation._variables` + * `LocalCacheMutation.variables` -> `LocalCacheMutation._variables` + +## v1.0.0-beta.4 + +This is the fourth Beta Release of Apollo iOS 1.0. The Beta version has full feature parity with the 0.x.x releases. The API is expected to be mostly stable. Some breaking changes may occur due to user feedback prior to General Availability (GA) Release. The Beta does not have complete documentation or usage guides, which will be completed prior to GA. + +This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **Breaking: Generated Files now have the file extension `.graphql.swift`.** + * This allows you to clearly distinguish which files in your project are Apollo generated files. + * Generated template files that are user-editable will still have the `.swift` file extension. + * `CustomScalar` templates as well as the `SchemaConfiguration` file are user-editable. Once these are generated, they are never overwritten by future code generation execution. + * This change is also necessary for the identification of generated files for the pruning functionality. +* **New: Pruning of Unused Generated Files** + * Generated files that no longer should exist are automatically deleted now. This occurs when a `.graphql` file is removed from your project. The generated file will also be deleted the next time code generation is run. + * This can be disabled with the new `pruneGeneratedFiles` codegen option. + * **Breaking: Automatic Deletion will not delete files generated in previous Alpha/Beta versions.** + * Only files with the `.graphql.swift` file extension will be deleted. + * If you have used previous Alpha/Beta versions, you will need to delete your generated files manually one last time before running code generation with this version. +* **New: Enum Case Names are Converted to Camel Case in Generated Enums.** + * **Breaking: This is enabled by default, your call sites will need to be updated.** + * Camel case conversion for enum cases can be disabled with the new `conversionStrategies.enumCases` codegen option. + * Thanks [@bannzai](https://github.com/bannzai) for this one! +* **Fixed: Swift Keywords are escaped when used as names of Enum Values** Thanks [@bannzai](https://github.com/bannzai) for the fix! +* **Fixed: Compilation Error when Using Fragment with Lowercased Name** This was an edge case that only occured when referencing a nested, merged selection set from the lowercase named fragment. +* **Fixed: Retain Cycle in `ReadTransaction`** Thanks [@lorraine-hatch](https://github.com/lorraine-hatch) for the fix! +* **Fixed: String `jsonValue` Initializer for Large Numbers** Thanks [@Almaz5200](https://github.com/Almaz5200) for the fix! + +## v1.0.0-beta.3 + +This is the third Beta Release of Apollo iOS 1.0. The Beta version has full feature parity with the 0.x.x releases. The API is expected to be mostly stable. Some breaking changes may occur due to user feedback prior to General Availability (GA) Release. The Beta does not have complete documentation or usage guides, which will be completed prior to GA. + +This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **Breaking: Changed the generated Schema files** + * The schema will now have two generated files, `SchemaMetadata.swift` and `SchemaConfiguration.swift.` + * We wanted to more clearly separate the parts of the schema that are generated for you (metadata) from the parts that you can configure yourself (configuration). + * **If you were using the last beta, you’ll need to move your cache key resolution logic into `SchemaConfiguration.swift`. You should also delete the old generated files.* + * *We will be implementing automatic deletion of generated files that should no longer be part of your project in a future beta, so you won't need to delete those files manually anymore.* +* **New: Added SPM Plugin for Code Generation CLI** + * When including Apollo iOS via Swift Package Manager, the Code Generation CLI is now accessible as an SPM Plugin. + * After installing the `apollo-ios` package, run `swift package --disable-sandbox apollo-initialize-codegen-config` to create the codegen configuration file. + * Then you can run `swift package --disable-sandbox apollo-generate` to run code generation. + * The `--disable-sandbox` or `--allow-writing-to-directory .` arguments must be used when running the Code Generation CLI via the SPM plugin to give the plugin permission to write the generated files to the output directory configured in your codegen configuration file. +* **Fixed: Compilation errors when schema types had lowercase names** +* **Fixed: Codegen engine crashing in specific situations** + * There were some bugs in the codegen compiler when merging nested fragments with non-matching parent types and using default values for input object list fields. +* **Fixed: Issues with websocket reconnections** Thanks [@STomperi](https://github.com/STomperi) for the fix! + +## v1.0.0-beta.2 + +This is the second Beta Release of Apollo iOS 1.0. The Beta version has full feature parity with the 0.x.x releases. The API is expected to be mostly stable. Some breaking changes may occur due to user feedback prior to General Availability (GA) Release. The Beta does not have complete documentation or usage guides, which will be completed prior to GA. + +This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +**Breaking: Changed API for Cache Key Configuration:** Cache Key Resolution is now easier to configure. See `CacheKeyInfo` for examples and documentation. +**Breaking: Changed API for generated Schema Types to support dynamic types** The API for generated schema types now initializes instances of `Object`, `Interface`, and `Union` for each corresponding type in your schema. These are still generated by the code generation engine. This differs from the previous API which generated static types that were subclasses of `Object`, `Interface`, and `Union`. The change provides the API to support the future addition of dynamic types added to your schema at runtime. +**New: Codegen CLI will now automatically create output directories:** You no longer are required to have already created all intermediary directories for your codegen output paths prior to running code generation. +**New: Codegen CLI is built locally with CocoaPods installations:** This is to ensure that the version of the Codegen CLI is the same as ApolloCodegenLib. This behaviour will be extended to Swift Package Manager installations too. +**New: Swift Keywords are escaped when used as names of fields or types in generated objects:** Previously, using Swift keywords (eg. `self`, `protocol`, `Type`) as the names of fields in your operations or types in your schema would cause compilation errors in your generated code. Now, these names will be escaped with backticks to prevent compiler errors. **The names `\_\_data` and `fragments` cannot be used as field names as they conflict with Apollo's generated object APIs** Using these names will result in a validation error being thrown when attempting to run the code generation engine. +**Fixed: Fragments with lowercase names caused compilation errors:** This bug is fixed. Fragments with lowercase names will be correctly uppercased when referencing the generated `Fragment` objects. +**Fixed: Build errors in Xcode 14/Swift 5.7:** The library was updated to support the Swift 5.7 language version. Swift 5.6 is still supported. +**Fixed: Xcode 14 does not support Bitcode:** Starting with Xcode 14, bitcode is no longer required for watchOS and tvOS applications, and the App Store no longer accepts bitcode submissions from Xcode 14. +**Fixed: "No such module `ApolloAPI`" error when using CocoaPods:** The podspec was not configured to import all required source files and some import statements were unnecessary in a CocoaPods environment. A code generation configuration option was added to order to ensure generated files are generated with the correct import statements in a CocoaPods environment. **When generating code for a project that includes `Apollo` via Cocoapods, you must set the `cocoapodsCompatibleImportStatements` option to `true` in your `ApolloCodegenConfiguration`.** When using the Codegen CLI that is built for you during `pod install` the `apollo-ios-cli init` command will default this option to `true`. When building the Codegen CLI in by other method, this option will default to `false`. +**Removed: ApolloUtils target no longer necessary:** The things that used to be shared here are actually no longer shared. There is no code shared between the `Apollo` and `ApolloCodegenLib` targets. +**Removed: ApolloCodegenConfiguration.validation:** This method was incorrectly requiring destination paths to exist before code generation. Once that was removed it was no longer necessary. Any errors that are encountered with destination output paths will be raised during code generation. + +## v1.0.0-beta.1 + +This is the first Beta Release of Apollo iOS 1.0. The Beta version has full feature parity with the 0.x.x releases. The API is expected to be mostly stable. Some breaking changes may occur due to user feedback prior to General Availability (GA) Release. The Beta does not have complete documentation or usage guides, which will be completed prior to GA. + +This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **New: Additional Generated Code Output Configuration Options.** + * `queryStringLiteralFormat`: Configures how the generated operations render the operation document source. Either multi-line (as defined in operation definition) or minified to a single line. + * `schemaDocumentation`: Documentation of fields and objects from your schema will now be included as in-line documentation on generated objects. This can be disabled by setting `schemaDocumentation` to `.excluded` in your codegen configuration. + * `warningsOnDeprecatedUsage`: Adds warning annotation when using fields and arguments in generated operations that are deprecated by the schema. + * `additionalInflectionRules`: Allows you to configure custom singularization rules for generated fields names. +* **New: Support Automatic Persisted Queries:** APQs are now fully functional. *Note: Legacy operation safelisting support may experience issues in some cases.* If you have problems using operation safelisting, please create an issue so that we may understand and resolve the edge cases in the safelisting process. +* **Fixed: Singularization of plural names for non-list fields.** +* **Fixed: Runtime failure on execution of operations with InputObjects.** +* **Fixed: `__typename` field no longer generated when manually included:** `__typename` is automatically included in all operations and fragments and has a default property on all Selection Sets. Generating the field was redundant and caused compilation errors. + +## v1.0.0-alpha.8 + +This is the eighth Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **New: Added `Equatable` and `Hashable` Conformance to public API Models:** Object's like `GraphQLRequest` and `GraphQLError` now can be compared! +* **New: Code Generation now supports Schema Extensions**. +* **Fixed: Namespacing and Access Control on Generated Models:** Generated models were failing to compile due to namespacing and access control issues in certain code generation configurations. This is fixed now! +* **Improved: Custom Scalar Default Float Behavior:** If the response for a custom scalar is provided as a `Float`, it will automatically be converetd to a `String` (just like it's always done for `Int`). +* **Improved: GraphQL Float now treated as Swift Double:** The `Float` defined in the GraphQL spec is actually compliant with a Swift `Double`. Generated code will now generate Swift code with fields of type `Double` for GraphQL `Float`. +* **Improved: Rename `SelectionSet.data` to `SelectionSet.__data`:** This is to prevent naming conflicts with GraphQL fields named `data`. +* **Fixed: `graphql_transport_ws` protocol now sends 'complete' to end subscription:** The protocol implementation was previously sending the wrong message to close the connection. +* **Improved: Generated Operations Folder Structure:** The generated output folder structure for fragments and operations are now organized into sub-folders. +* **New: Introspection Schema Download can output JSON:** Schema downloads via Introspection now support output as JSON instead of only SDL. Note that Apollo Registry schema downloads still only support SDL as the output. + +## v1.0.0-alpha.7 + +This is the seventh Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **New: Local Cache Mutations are now supported:** In order to perform a local cache mutation, define a `.graphql` file with an operation or a fragment and mark it with the directive `@apollo_client_ios_localCacheMutation`. This will ensure the code generator generates a mutable cache mutation operation. + * **Note: Local Cache Mutation operations cannot be used for fetching from the network!** You should define separate GraphQL operations for network operations and local cache mutations. + * Example Usage: + +```graphql +/// SampleLocalCacheMutation.graphql +query SampleLocalCacheMutation @apollo_client_ios_localCacheMutation { + allAnimals { + species + skinCovering + ... on Bird { + wingspan + } + } +} + +/// SampleLocalCacheMutationFragment.graphql +fragment SampleLocalCacheMutationFragment on Pet @apollo_client_ios_localCacheMutation { + owner { + firstName + } +} +``` + +* **New: Support Code Generation Configuration Option: `deprecatedEnumCases`:** If `deprecatedEnumCases` is set to `exclude`, deprecated cases in graphql enums from your schema will not be generated and will be treated as unknown enum values. +* **Fixed - Compilation Errors in Generated Code When Schema was Embedded In Target:** When embedding the generated schema in your own target, rather than generating a separate module for it, there were compilation errors due to access control and namespacing issues. These are resolved. This fixes #2301 & #2302. Thanks [@kimdv](https://github.com/kimdv) for calling attention to these bugs! + * **Note: Compilation Errors for Test Mocks are still present.** We are aware of ongoing issues with generated test mocks. We are actively working on fixing these issues and they will be resolved in a future alpha release soon. +* **Fixed: Crash When Accessing a Conditionally Included Fragment That is Nil.** This is fixed now and will return `nil` as it should. This fixes #2310. + +## v1.0.0-alpha.6 + +This is the sixth Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **New: Objects and InputObjects are now equatable:** Many objects now conform to `AnyHashable` bringing with them the ability to conform to `Equatable`, this should make tests easier to write. +* **Change: GraphQLOperation fields are now static:** Previously an instance of a GraphQLOperation was required to query any of it's properties, you can do that on the type now. +* **Fixed - Nested fragment type cases:** Nested fragment type cases were not being generated causing a crash in selection set generation. +* **New - Code generation now has a CLI:** A new command line executable has been built and will be available on Homebrew very soon! Check it out [here](https://github.com/apollographql/apollo-ios/tree/release/1.0/CodegenCLI). +* **Fixed - SelectionSet and InlineFragment protocol definitions:** These were incorrectly being generated within the namespace when a module of type `.embeddedInTarget` was being used. +* **Fixed - Test mock convenience initializers:** These were incorrectly definining parameter types for Interface and Union fields and the generated package could not successfully build. + +## v1.0.0-alpha.5 + +This is the fifth Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **Test Mocks are now supported!** + * Test mocks can be generated to make it much easier to create mocks of your generated selection sets for unit testing. + * This long requested feature can be enabled in your code generation config with the option `config.output.testMocks`. + * Once you've generated test mocks, import the new `ApolloTestSupport` target (as well as your generated mocks) in your unit tests to start. + * More documentation for test mocks will be coming soon. In the mean time, here is some example usage: + +```swift +let mockDog = Mock() +mock.species = "Canine" +mock.height = Mock(feet: 3, inches: 6) + +// To mock an object in a generated operation: +let generatedDogMock: AnimalQuery.Data.Animal = AnimalQuery.Data.Animal.mock(from: mockDog) + +// To mock an entire query: +let queryMock = Mock() +queryMock.animals = [mockDog] +let generatedSelectionSetMock: AnimalQuery.Data = AnimalQuery.Data.mock(from: queryMock) +``` + +* `GraphQLNullable` and `GraphQLEnum` from the `ApolloAPI` target are now exported by your generated operations. This prevents you from having to `import ApolloAPI` everywhere that you are consuming your generated models. +* `CacheKeyProvider` now supports grouping multiple types that share key uniqueness. +* Lots of performance improvements + * Using `StaticString` instead of `String` in generated files. + * Added `@inlinable` to many `ApolloAPI` functions consumed by generated code. + * And more! + +## v1.0.0-alpha.4 + +This is the fourth Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **Client Controlled Nullability (CCN) is now supported!** + * CCN is an experimental new feature addition to GraphQL. This feature allows you to override the optionality of fields from a schema in your client operations. CCN can help you create cleaner generated models that require less optional unwrapping. + * You can read more about CCN [here](https://github.com/graphql/graphql-spec/issues/867). + * Because CCN is an experimental feature, the API is subject to change before its final release. + * Apollo iOS 1.0.0 is the first client to provide support for this new functionality! Huge thanks to [@twof](https://github.com/twof)! +* **Fixed - Names of generated objects are now correctly uppercased.** +* **Fixed - Names of inline fragments with inclusion conditions were sometimes generated incorrectly.** +* **Fixed - `__typename` field is now selected by executor on all entities automatically.** + +## v1.0.0-alpha.3 + +This is the third Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **Include/Skip Directives are now supported!** + * Adding `@include/@skip` directives to fields, inline fragments, or fragment spreads will now generate code that respects the optionality of these conditionally included selections. +* **Changed - Generated TypeCase renamed to InlineFragment** These are now used for both type cases and inline fragments that are conditionally included using `@include/@skip` directives. +* **Custom Scalars are now supported!** + * Template Files will be generated for custom scalars. The template files `typealias` each custom scalar to a `String` by default. These generated files can be edited to provide custom functionality for advanced custom scalars. Custom scalar template files that have been edited will not be overwritten on later code generation executions. +* **Improved multi-module support** + * Including your generated code using package managers other than SPM can be done using the `.other` option for `moduleType` in your code generation configuration. +* **Nil Coalescing Operator added to `GraphQLNullable` + * This allows for optional variables to easily be used with `GraphQLNullable` parameters and a default value + +```swift +class MyQuery: GraphQLQuery { + + var myVar: GraphQLNullable + + init(myVar: GraphQLNullable { ... } + // ... +} + +let optionalString: String? + +// Before + +let query = MyQuery(myVar: optionalString.map { .some($0) } ?? .none) + +// After +let query = MyQuery(myVar: optionalString ?? .none) +``` +* **Fixed - `fragments` not accessible on generated `SelectionSet`s. +* **Fixed - `__typename` is now added to all operation and fragment definitions. +* **Fixed - Missing Generated Interface Types** + * Interface types that were only referenced as an implemented interface of a referenced concrete type were not being generated previously. + +## v1.0.0-alpha.2 + +This is the second Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +* **Operation Variables and Field Arguments are now supported!** +* **Fixed - Capitalized field names generate code that doesn't compile**[#2167](https://github.com/apollographql/apollo-ios/issues/2167) + +## v1.0.0-alpha.1 + +This is the first Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library. + +### What’s New + +* The size of generated code has been reduced dramatically. In the most complex operations, the generated code can be up to **90% smaller** than in the previous version. +* Generated response objects are more powerful and easier to consume. + * The response objects now intelligently merge fields from not only their parents, but also other matching siblings. + +``` +query AnimalQuery { + allAnimals { + species + ... on Pet { + name + } + ... on Cat { + furColor + } +} +``` + +In the past, the `AsCat` model would have fields for `species`, and `furColor`, but to access the `name` field, you would need to keep a reference to the `AllAnimal` object and call `AsPet.name`. This means that you couldn’t just pass the `AsCat` object to a UI component. + +In 1.0, because we know that `Cat` implements the `Pet` interface, the `name` field is merged into the `Cat` object. + +*Any property that should exist based on the type of the object will be accessible.* This makes consuming our generated response objects in your applications much easier. This should greatly reduce the need for view models to wrap our generated response objects. + +* The code generation engine is now written in native Swift! This makes it easier for Swift developers to contribute to the project or alter the generated code for their specific needs! In future iterations, we hope to open up the code generation templating API to allow for even easier customization of your generated code! +* Computation of Cache Keys is protocol oriented now. Instead of a single `cacheKeyForObject` closure on your `ApolloClient`, you can implement cache key computation on individual object types with the `CacheKeyProvider` protocol. See [Cache Key Resolution](https://github.com/apollographql/apollo-ios/blob/release/1.0-alpha-incubating/CodegenProposal.md#cache-key-resolution) in the RFC for more information. ## v0.53.0 - **Remove all instances of bitcode as not supported in Xcode 14**: Starting with Xcode 14, bitcode is no longer required for watchOS and tvOS applications, and the App Store no longer accepts bitcode submissions from Xcode 14. [#2398](https://github.com/apollographql/apollo-ios/pull/2398) - _Thanks to [@stareque-atlassian](stareque-atlassian) for the contribution!_ diff --git a/CLI/apollo-ios-cli.tar.gz b/CLI/apollo-ios-cli.tar.gz new file mode 100644 index 0000000000..f42aa8ddba Binary files /dev/null and b/CLI/apollo-ios-cli.tar.gz differ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 34de4aef97..5da25b5625 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,82 +1 @@ -# Apollo iOS Contributor Guide - -Excited about Apollo iOS and want to make it better? We’re excited too! - -Apollo is a community of developers just like you, striving to create the best tools and libraries around GraphQL. We welcome anyone who wants to contribute or provide constructive feedback, no matter your age or level of experience. If you want to help but don't know where to start, let us know, and we'll find something for you. - -Oh, and if you haven't already, stop by our [community forums!](https://community.apollographql.com)! - -Here are some ways to contribute to the project, from easiest to most difficult: - -* [Reporting bugs](#reporting-bugs) -* [Improving the documentation](#improving-the-documentation) -* [Responding to issues](#responding-to-issues) -* [Small bug fixes](#small-bug-fixes) -* [Suggesting features](#suggesting-features) -* [Big pull requests](#big-prs) - -## Issues - -### Reporting bugs - -If you encounter a bug, please file an issue here on GitHub, and make sure you note which library is causing the problem. If an issue you have is already reported, please add additional information or add a 👍 reaction to indicate your agreement. - -While we will try to be as helpful as we can on any issue reported, please include the following to maximize the chances of a quick fix: - -1. **Intended outcome:** What you were trying to accomplish when the bug occurred, and as much code as possible related to the source of the problem. -2. **Actual outcome:** A description of what actually happened, including a screenshot or copy-paste of any related error messages, logs, or other output that might be related. Places to look for information include your browser console, server console, and network logs. Please avoid non-specific phrases like “didn’t work” or “broke”. -3. **How to reproduce the issue:** Instructions for how the issue can be reproduced by a maintainer or contributor. Be as specific as possible, and only mention what is necessary to reproduce the bug. If possible, try to isolate the exact circumstances in which the bug occurs and avoid speculation over what the cause might be. - -Creating a good reproduction really helps contributors investigate and resolve your issue quickly. In many cases, the act of creating a minimal reproduction illuminates that the source of the bug was somewhere outside the library in question, saving time and effort for everyone. - -### Improving the documentation - -Improving the documentation, examples, and other open source content can be the easiest way to contribute to the library. If you see a piece of content that can be better, open a PR with an improvement, no matter how small! If you would like to suggest a big change or major rewrite, we’d love to hear your ideas but please open an issue for discussion before writing the PR. - -### Responding to issues - -In addition to reporting issues, a great way to contribute to Apollo is to respond to other peoples' issues and try to identify the problem or help them work around it. If you’re interested in taking a more active role in this process, please go ahead and respond to issues. And don't forget to say "Hi" on our community forums! - -### Small bug fixes - -For a small bug fix change (less than 20 lines of code changed), feel free to open a pull request. We’ll try to merge it as fast as possible and ideally publish a new release on the same day. The only requirement is, make sure you also add a test that verifies the bug you are trying to fix. - -### Suggesting features - -Most of the features in Apollo came from suggestions by you, the community! We welcome any ideas about how to make Apollo better for your use case. Unless there is overwhelming demand for a feature, it might not get implemented immediately, but please include as much information as possible that will help people have a discussion about your proposal: - -1. **Use case:** What are you trying to accomplish, in specific terms? Often, there might already be a good way to do what you need and a new feature is unnecessary, but it’s hard to know without information about the specific use case. -2. **Could this be a companion package?** In many cases, a feature might be too niche to be included in the core of a library, and is better implemented as a companion package. If there isn’t a way to extend the library to do what you want, could we expose additional APIs that a companion package could plug into? It’s important to make the case for why a feature should be part of the core functionality of the library. -3. **Is there a workaround?** Is this a more convenient way to do something that is already possible, or is there some blocker that makes a workaround unfeasible? - -Feature requests will be labeled as such, and we encourage using GitHub issues as a place to discuss new features and possible implementation designs. Please refrain from submitting a pull request to implement a proposed feature until there is consensus that it should be included. This way, you can avoid putting in work that can’t be merged in. - -Once there is a consensus on the need for a new feature, proceed as listed below under “Big PRs”. - -## Big PRs - -This includes: - -- Big bug fixes -- New features - -For significant changes to a repository, it’s important to settle on a design before starting on the implementation. This way, we can make sure that major improvements get the care and attention they deserve. Since big changes can be risky and might not always get merged, it’s good to reduce the amount of possible wasted effort by agreeing on an implementation design/plan first. - -1. **Open an issue.** Open an issue about your bug or feature, as described above. -2. **Reach consensus.** Some contributors and community members should reach an agreement that this feature or bug is important, and that someone should work on implementing or fixing it. -3. **Agree on intended behavior.** On the issue, reach an agreement about the desired behavior. In the case of a bug fix, it should be clear what it means for the bug to be fixed, and in the case of a feature, it should be clear what it will be like for developers to use the new feature. -4. **Agree on implementation plan.** Write a plan for how this feature or bug fix should be implemented. What modules need to be added or rewritten? Should this be one pull request or multiple incremental improvements? Who is going to do each part? -5. **Submit PR.** In the case where multiple dependent patches need to be made to implement the change, only submit one at a time. Otherwise, the others might get stale while the first is reviewed and merged. Make sure to avoid “while we’re here” type changes - if something isn’t relevant to the improvement at hand, it should be in a separate PR; this especially includes code style changes of unrelated code. -6. **Review.** At least one core contributor should sign off on the change before it’s merged. Look at the “code review” section below to learn about factors are important in the code review. If you want to expedite the code being merged, try to review your own code first! -7. **Merge and release!** - -### Code review guidelines - -It’s important that every piece of code in Apollo packages is reviewed by at least one core contributor familiar with that codebase. Here are some things we look for: - -1. **Required CI checks pass.** This is a prerequisite for the review, and it is the PR author's responsibility. As long as the tests don’t pass, the PR won't get reviewed. -2. **Simplicity.** Is this the simplest way to achieve the intended goal? If there are too many files, redundant functions, or complex lines of code, suggest a simpler way to do the same thing. In particular, avoid implementing an overly general solution when a simple, small, and pragmatic fix will do. -3. **Testing.** Do the tests ensure this code won’t break when other stuff changes around it? When it does break, will the tests added help us identify which part of the library has the problem? Did we cover an appropriate set of edge cases? Look at the test coverage report if there is one. Are all significant code paths in the new code exercised at least once? -4. **No unnecessary or unrelated changes.** PRs shouldn’t come with random formatting changes, especially in unrelated parts of the code. If there is some refactoring that needs to be done, it should be in a separate PR from a bug fix or feature, if possible. -5. **Code has appropriate comments.** Code should be commented for *why* things are happening, not *what* is happening. *What* is happening should be clear from the names of your functions and variables. This is sometimes called "self-documenting code", but you may still need to add comments to explain why a workaround is necessary so other developers can better understand your code. -6. **Idiomatic use of the language.** Make sure to use idiomatic Swift when working with this repository. We don't presently use SwiftLint or any other linter, but please use your common sense and follow the style of the surrounding code. +If you would like to contribute to this library, you should make your code modifications and pull requests in the the [apollo-ios-dev](https://github.com/apollographql/apollo-ios-dev) repository. For more information, see the contributor guide in the `apollo-ios-dev` repo [here](https://github.com/apollographql/apollo-ios-dev/tree/main/CONTRIBUTING.md) diff --git a/CodegenProposal.md b/CodegenProposal.md new file mode 100644 index 0000000000..bae29f89e9 --- /dev/null +++ b/CodegenProposal.md @@ -0,0 +1,1642 @@ +# iOS Codegen Proposal + +# Overview + +This document provides explanation, context, and examples for a proposal for the new code generation for iOS. + +> **Example code in this document is used only to illustrate the concepts being discussed, as is not comprehensive. Actual generated objects may have additional properties, functions, or nested types to support all functionality. For an examples of an entire generated operation, see the [Example Generated Output](Tests/ApolloCodegenTests/AnimalKingdomAPI/ExpectedGeneratedOutput/Queries/AllAnimalsQuery.swift) in the repository.** + +## Key Changes in 1.0 + +While the generated models in version 1.0 look much different than the current generated code, under the hood, they function relatively similarly. Though there are a few important functional differences, they are still structs backed by a dictionary of keys and values. Consuming your response data looks very similar to the previous version. Fragments and Type Cases are still accessed as nested objects. **The most noticeable difference is that the generated code will be a fraction of its previous size and should be much easier to read and understand!** + +The most important functional differences are: + +### Immutable Response Objects + +The generated response objects are now immutable. This allows for the generated code to be much more compact. Previously, fields on the generated models could be mutated, however this was not used for mutating objects server-side. Response objects could be mutated and then saved to the local cache to make manual cache mutations. + +The ability to mutate the local cache will implemented by using mutable fields on generated schema types in a follow-up to this RFC. This will be implemented prior to the 1.0 release. + +Local cache mutations using response objects had a number of limitations: +- Cache data could only be mutated in the scope of a defined operation. +- Validation of mutated data was weak. + - In certain edge cases, data that would be invalid according to the schema could be inserted in the local cache. This could cause failures when reading cached data. In the worst case scenario, this could result in runtime crashes. +- Data that had not yet been fetched from the server was difficult to insert in the local cache. + - This was especially problematic when wanting to add values for Non-null fields on partially fetched objects. + +### Generated Schema Types + +In addition to generating the immutable operation response data models, the new codegen generates "Schema Types". Schema Types represent the backing types defined on the GraphQL schema itself. These objects provide metadata that is used by the Apollo Client under the hood to understand the relationships between the types in your generated operation response models. These generated Schema Types will also be expanded prior to the 1.0 release to include fields that allow for local cache mutations. For more information, see [Schema Type Generation](#schema-type-generation). + +### Fragment Fields Are Always Merged In + +In previous versions of the Code Generation tool, this functionality was exposed via the `mergeInFieldsFromFragmentSpreads` option, which defaulted to `false`. Merging in fragment fields provides for easier consumption of generated models, but it also increases the size of the generated code. Because the size of the generated code is being dramatically reduced with the new Code Generation tooling, we have opted to always merge in fragment fields. If generated code size becomes a concern with the new Code Generation, adding an option to disable fragment merging may be considered in the future. For an example of this see [Merging Fragment Fields Into Parent `SelectionSet`](#merging-fragment-fields-into-parent-selectionset) + +### CacheKeyProvider + +For normalization of cache data, a mechanism for providing unique cache keys for entities is necessary. In the previous version of Apollo, this was configured via a single `cacheKeyForObject` closure that could be set on the `ApolloClient`. In version 1.0, this configuration will move to extensions on the Schema Types. For more information, see [Cache Key Resolution](#cache-key-resolution) + +### GraphQLNullable + +The previous Apollo versions used double optionals (`??`) to represent `null` vs `nil` input values. This was unclear to most users and make reading and reasoning about your code difficult in many situations. The new version provides a custom enum for this cases named `GraphQLNullable`. For more information, see [Nullable Arguments - GraphQLNullable](#nullable-arguments---graphqlnullable) + +### Multiple Module Support + +We are excited to say that the 1.0 release of Apollo iOS will support code generation for projects that use multiple modules! There will be multiple options for generating your model objects: + +- Single Target + - Single Location + - All files will be generated into a folder that is included in your application target. + - Co-located Models + - Generated operation objects will be located relative to the defining `.graphql` file. + - Schema types will be generated in a single folder. +- Modular (Built-in support for SPM & Cocoapods) + - Single Location + - All files will be generated into a folder that can be included as it's own module. + - Co-located Models + - Generated operation objects will be located relative to the defining `.graphql` file. + - Schema types and shared fragments will be generated into a folder that can be included as it's own module. + +The primary limitation with multi-module support is that code generation must be run on your entire project at one time. You will not be able to run code generation for modules individually at this time. More information about how to generate models for multi-module projects will be coming prior to the 1.0 release. + +### Type Case Execution + +The logic for generating, validating, and executing selections for Type Cases has changed significantly. While this change is entirely under the hood – it should rarely, if ever, affect the consumer – because the generated code and the way the executor parses Type Cases functionally deviates from it's previous behavior, it is included here. + +Type Cases previously included all of the selections that would be selected if the underlying `__typename` of the returned object matched the Type Case. For interfaces, the same TypeCase could be used for multiple different `__typename` values. + +In the new generated models, type cases are generated to only select the additional fields that should be selected if the underlying `__typename` matches that type. The executor can now handling selecting multiple different Type Cases for the same object, if it matches multiple Type Cases (ie. A concrete type and an interface). This simplifies the execution logic; reduces the amount of generated code necessary; and makes the generated objects easier to understand. + +For more information see [TypeCase Selections](#typecase-selections). + +## Objectives + +There are a number of reasons to build a new Codegen tool. There are limitations of the current Codegen, as well as improvements and features that can be added with a new Codegen tool that are difficult to address with the current tooling. + +### Dependency on Typescript + +The current Codegen tooling is written in Typescript, and supports multiple languages. This code base is not maintained and is in a messy state currently. Making changes to this tooling is difficult because of the state of the code and because it must maintain compatibility with generating code for other languages. Additionally, we believe that a Codegen tool written primarily in Swift opens up more opportunity for the community to make contributions in the future. + +### Dependency on NPM + +The current Codegen tooling CLI runs as a node package. This requires iOS developers to include an NPM project. This is not ideal, as it adds a lot of cruft to our user’s projects. Since many iOS engineers are not familiar with NPM, the installation and usage of it creates additional hurdles to getting a project started and maintaining projects that iOS engineers struggle with. We have pulled out the GraphQL compiler to work without NPM, and by wrapping it in a Swift library, we can remove the NPM dependency. + +### Runtime Performance + +This Codegen proposal uses a dictionary of values that are passed around and accessed each time a property is accessed, this has some run time implications as they must be retrieved from the dictionary each time they are accessed. This is similar to the way the current Codegen works. + +An alternative approach may map field data onto stored properties on the response object once and only once during parsing, which is typically done on a background thread. However, this approach would require a lot of data duplication and would increase the complexity and size of the generated code considerably. + +### Generated Code Size + +The size of the generated code for large or complex queries can rapidly become very large under the current CodeGen. This is something we would like to improve upon. Though we understand that there is only so much we can do to reduce code size while accurately reflecting all the data and handling edge cases. + +### Generated Code Complexity + +The current Codegen generates objects that are often difficult to parse and understand for developers looking at the generated code. While we recognize that the functionality required and edge cases that must be accounted for cause complexity to be inevitable, we hope that the new Codegen can reduce the complexity. This may or may not be possible, and complexity will likely have trade-offs with functionality, generated code size, and other goals. + +### Compiled Binary Size + +The size of the compiled binary when using our generated data objects must also be considered. Alternatives have been proposed that use classes for models rather than structs to reduce the size of the compiled binary. While classes can reduce binary size, they incurs an additional runtime cost when consumed. + +This proposal opts for using lightweight structs that only store a single property in memory — a pointer to their data dictionary. By restricting the size of our structs to a single pointer, we are able to achieve the benefits of structs without incurring the majority of the overhead they create. See [Memory Management and Performance of Value Types](https://swiftrocks.com/memory-management-and-performance-of-value-types) for more information. + +### Compilation Time + +We have had customer concerns with the compilation time of large generated queries under the current Codegen. While we recognize that large queries will always add some noticeable time to compilation, it is a goal of this project to minimize the build time impact of our generated data objects. + +Easy wins in this aspect of performance can be gained by explicitly providing types where they could be inferred. Other compilation time improvements should be considered and any trade-offs with other goals weighed. + +### Memory Allocation + +Because response data from a query may be considerably large, it is important to consider the memory usage of our generated data objects. This proposal utilizes multiple mechanisms for minimizing memory usage. + +Because the underlying storage of the current Codegen objects is a dictionary, it is already heap allocated and shared. Accessing fields through different structs (like fragments) does not lead to additional copies of the data. This proposal maintains this functionality. + +### Fragment Usage + +One of the primary use cases for fragments is for dependency inversion and component reuse. A fragment of data can be used with a UI component or other object, irrespective of the GraphQL operation the data comes from or the other fields that were fetched in addition to the fragments fields. + +While the ideal way to provide this functionality is to generate fragments as protocols, which the generated data objects conform to, this does not work. This is due to lack of Swift language support for covariant protocol conformance and protocols with associated types as concrete properties. For more information on this see: [Appendix A: Why Fragment Protocols Don’t Work](#appendix-a-why-fragment-protocols-dont-work) + +This proposal aims to provide a simple way to construct fragment objects from the generated data objects. + +### Data Validation + +Data received in the response of a GraphQL Operation must be validated to ensure that all required fields exist and all objects are valid. The response data objects should return data that is guaranteed to be valid. While the current Codegen does data validation appropriately, it is important to note that this is a required goal of any proposed replacement as well. + +### Ease of Use + +Our generated objects should be easy to use by the consumer in order to be useful. This involves the structure of the data; the manner in which type cases and fragments are accessed; usage of enums and unions; providing strict type safety and nullability; and enabling code completion for all fields (including merged fields). + +Because we cannot understand or determine the optimal structure for each user’s individual use cases, it is likely that many users will use adapters to map our generated data objects onto their own models/view models. This is especially true for users who want to store data in a separate cache, such as `CoreData` or `Realm`. The generated data objects must be structured in a way that provides an easy way to access the data for mapping onto the user’s custom model types. + +While we do not expect the generated data objects to be appropriate for every use case, it is our aim to maximize the instances in which custom models/view models are not necessary. This requires type safety, nullability, code completion, and merged fields to work in an intuitive manner. + +### Flexibility + +The generated code, as well as the implementation of the code generation tooling, should be architected in a flexible manner that allows for additional features additions to be implemented as easily as possible. + +## Example Schema + +For all examples in this document, we will use the following schema: + +```graphql +type Query { + allAnimals: [Animal!]! + allPets: [Pet!]! + classroomPets: [ClassroomPet!]! +} + +interface Animal { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering +} + +interface Pet { + humanName: String + favoriteToy: String! + owner: Human +} + +interface HousePet implements Animal & Pet { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + humanName: String + favoriteToy: String! + owner: Human + bestFriend: Pet + rival: Pet + livesWith: ClassroomPet +} + +interface WarmBlooded implements Animal { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + bodyTemperature: Int! + laysEggs: Boolean! +} + +type Height { + relativeSize: RelativeSize! + centimeters: Int! + meters: Int! + feet: Int! + inches: Int! + yards: Int! +} + +type Human implements Animal & WarmBlooded { + firstName: String! + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + bodyTemperature: Int! + laysEggs: Boolean! +} + +type Cat implements Animal & Pet & WarmBlooded { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + humanName: String + favoriteToy: String! + owner: Human + bodyTemperature: Int! + laysEggs: Boolean! + isJellicle: Boolean! +} + +type Dog implements Animal & Pet & HousePet & WarmBlooded { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + humanName: String + favoriteToy: String! + owner: Human + bodyTemperature: Int! + laysEggs: Boolean! + bestFriend: HousePet + rival: Cat + livesWith: Bird +} + +type Bird implements Animal & Pet & WarmBlooded { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + humanName: String + favoriteToy: String! + owner: Human + bodyTemperature: Int! + laysEggs: Boolean! + wingspan: Int! +} + +type Fish implements Animal & Pet { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + humanName: String + favoriteToy: String! + owner: Human +} + +type Rat implements Animal & Pet { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + humanName: String + favoriteToy: String! + owner: Human +} + +type Crocodile implements Animal { + species: String! + height: Height! + predators: [Animal!]! + skinCovering: SkinCovering + age: Int! +} + +type PetRock implements Pet { + humanName: String + favoriteToy: String! + owner: Human +} + +union ClassroomPet = Cat | Bird | Rat | PetRock + +enum RelativeSize { + LARGE + AVERAGE + SMALL +} + +enum SkinCovering { + FUR + HAIR + FEATHERS + SCALES +} +``` + +# Core Concepts + +In order to fulfill all of the stated goals of this project, the following approach is proposed for the structure of the Codegen: + +## `SelectionSet` - A “View” of an Entity + +We will refer to each individual object fetched in a GraphQL response as an “entity”. An entity defines a single type (object, interface, or union) that has fields on it that can be fetched. + +A `SelectionSet` defines a set of fields that have been selected to be visible for access on a given entity. The `SelectionSet` determines the shape of the generated response data objects for a given operation. + +Given the query: + +```graphql +query { + allAnimals { + species + ... on Pet { + humanName + } + } +} +``` + +Each animal in the list of `allAnimals` is a single entity. Each of those entities has a concrete type (Cat, Fish, Bird, etc.). For each animal entity, we define a group of `SelectionSet`s that exposes the `species` field and, if the entity is a `Pet`, the `humanName` field. + +Each generated data object conforms to a `SelectionSet` protocol, which defines some universal behaviors. Type cases, fragments, and root types all conform to this protocol. For reference see [SelectionSet.swift](Sources/ApolloAPI/SelectionSet.swift). + +### `SelectionSet` Data is Represented as Structs With Dictionary Storage +--- + +The generated data objects are structs that have a single stored property. The stored property is to another struct named `ResponseDict`, which has a single stored constant property of type `[String: Any]`. + +Often times the same data can be represented by different generated types. For example, when checking a type condition or accessing a fragment on an entity. By using structs with a single dictionary pointer, we are able to reference the same underlying data, while providing different accessors for fields at different scopes. + +This allows us to store all the fetched data for an entity one time, rather than duplicating data in memory. The structs allow for hyper-performant conversions, as they are stack allocated at compile time and just increment a pointer to the single storage dictionary reference. + +### Field Accessors +--- + +Accessors to the fields that a generated object has are implemented as computed properties that access the dictionary storage. + +Let’s start with a simple example to illustrate what the `Fields` object looks like: + +**Query Input:** + +```graphql +query { + allAnimals { + species + height { + feet + } + } +} +``` + +**Generated Output:** (`Animal` Object) + +```swift +struct Animal: SelectionSet, HasFragments { + let data: ResponseDict + + var species: String { data["species"] } + var height: Height { data["height"] } + + struct Height: SelectionSet { + let data: ResponseDict + + var feet: Int { data["feet"] } + } +} +``` + +In this simple example, the `Animal` object has a nested `Height` object. Each conforms to `SelectionSet` and each has a single stored property let data: `ResponseDict`. The `ResponseDict` is a struct that wraps the dictionary storage, and provides custom subscript accessors for casting/transforming the underlying data to the correct types. For more information and implementation details, see: [ResponseDict.swift](Sources/ApolloAPI/ResponseDict.swift) + +## GraphQL Execution + +GraphQL execution is the process in which the Apollo iOS client converts raw data — either from a network response or the local cache — into a `SelectionSet`. The execution process determines which fields should be “selected”; maps the data for those fields; decodes raw data to the correct types for the fields; validates that all fields have valid data; and returns `SelectionSet` objects that are guaranteed to be valid. + +A field that is “selected” is mapped from the raw data onto the `SelectionSet` to be accessed using a generated field accessor. If data exists in the cache or on a raw network response for a field, but the field is not “selected” the resulting `SelectionSet` will not include that data after execution. + +Because `SelectionSet` field access uses unsafe force casting under the hood, it is necessary that a `SelectionSet` is only ever created via the execution process. A `SelectionSet` that is initialized manually cannot be guaranteed to contain all the expected data for its field accessors, and as such, could cause crashes at run time. `SelectionSet`s returned from GraphQL execution are guaranteed to be safe. + +## Nullable Arguments - `GraphQLNullable` + +By default, `GraphQLOperation` field variables; fields on `InputObject`s; and field arguments are nullable. For a nullable argument, the value can be provided as a value, a `null` value, or omitted entirely. In `GraphQL`, omitting an argument and passing a `null` value have semantically different meanings. While often, they may be identical, it is up to the implementation of the server to interpret these values. For example, a `null` value for an argument on a mutation may indicate that a field on the object should be set to `null`, while omitting the argument indicates that the field should retain it's current value -- or be set to a default value. + +Because of the semantic difference between `null` and ommitted arguments, we have introduced `GraphQLNullable`. `GraphQLNullable` is a generic enum that acts very similarly to `Optional`, but it differentiates between a `nil` value (the `.none` case), and a `null` value (the `.null` case). Values are still wrapped using the `.some(value)` case as in `Optional`. + +The previous Apollo versions used double optionals (`??`) to represent `null` vs ` nil`. This was unclear to most users and make reading and reasoning about your code difficult in many situations. `GraphQLNullable` makes your intentions clear and explicit when dealing with nullable input values. + +For more information and implementation details, see: [GraphQLNullable.swift](Sources/ApolloAPI/GraphQLNullable.swift) + +# Generated Objects + +An overview of the format of all generated object types. + +# Schema Type Generation + +In addition to generating `SelectionSet`s for your `GraphQLOperation`s, types will be generated for each type (object, interface, or union) that is used in any operations across your entire application. These types will include all the fields that may be fetched by any operation used and can include other type metadata. + +The schema types have a number of functions. + +* Include metadata that allows the `GraphQLExecutor` and runtime type checking on `TypeCase`s to operate. +* Can be extended to provide cache key computation for types to configure the normalized cache. +* Used for interacting with the cache for manual read/write functionality. +* Used to create mock objects for generated `SelectionSet`s to be used in unit tests. + + +These schema types can be included directly in your application target, or be generated into a separate shared library that can be used across modules in your application. + +Schema types are implemented as `class` objects, not `struct`s. They will use reference type semantics and are mutable within a cache transaction. + +## `Object` Types + +For each concrete type declared in your schema and referenced by any generated operation, an `Object` subclass is generated. Each `Object` type contains a `static var __metadata` containing a struct that provides a list of the interfaces implemented by the concrete type. + +```swift +public final class Dog: Object { + override public class var __typename: String { "Dog" } + + // MARK: - Metadata + override public class var __metadata: Metadata { _metadata } + private static let _metadata: Metadata = Metadata( + implements: [Animal.self, Pet.self, WarmBlooded.self, HousePet.self] + ) +} +``` + +## `Interface` Types + +For each interface type declared in your schema and referenced by any generated operation, an `Interface` subclass is generated. Interfaces wrap an underlying `Object` type and ensure that only objects of types that they are only initialized with a wrapped object of a type that implements the interface. + +```swift +public final class Pet: Interface {} +``` + +## `Union` Types + +For each union type declared in your schema and referenced by any generated operation, a `UnionType` enum is generated. `UnionType` enums have cases representing each possible type in the union. Each case has an associated value of the `Object` type represented by that case. `UnionType` enums are referenced as fields by being wrapped in a `Union` enum that provides access to the underlying `UnionType` and unknown cases. See [Handling Unknown Types](#handling-unknown-types) for more information. `UnionType` enums contain a `static let possibleTypes` property that provides a list of the concrete `Object` types contained in the union. +```swift +public enum ClassroomPet: UnionType, Equatable { + case Cat(Cat) + case Bird(Bird) + case Rat(Rat) + case PetRock(PetRock) + + public init?(_ object: Object) { + switch object { + case let ent as Cat: self = .Cat(ent) + case let ent as Bird: self = .Bird(ent) + case let ent as Rat: self = .Rat(ent) + case let ent as PetRock: self = .PetRock(ent) + default: return nil + } + } + + public var object: Object { + switch self { + case let .Cat(object as Object), let .Bird(object as Object), let .Rat(object as Object), let .PetRock(object as Object): + return object + } + } + + static public let possibleTypes: [Object.Type] = + [AnimalKingdomAPI.Cat.self, AnimalKingdomAPI.Bird.self, AnimalKingdomAPI.Rat.self, AnimalKingdomAPI.PetRock.self] +} +``` + +## `Schema` Metadata + +A `SchemaConfiguration` object will also be generated for your schema. This object will have a function that maps the `Object` types in your schema to their `__typename` string. This allows the execution to convert data (from a network response from the cache) to the correct `Object` type at runtime. + +For an example of generated schema metadata see [AnimalKindgomAPI/Schema.swift](Tests/ApolloCodegenTests/AnimalKingdomAPI/ExpectedGeneratedOutput/Schema.swift). + +# `EnumType` Generation + +Enums will be generated for each `enum` type in the schema that is used in any of the operations defined in your application. These enums will conform to a simple `EnumType` protocol. When used as the type for a field on a `SelectionSet`, these enums will be wrapped in the generic `GraphQLEnum`. Unlike the previous code generation engine, the new code generation will respect the capitalization of the enum cases from the schema. + +```swift +enum RelativeSize: String, EnumType { + case LARGE + case AVERAGE + case SMALL +} +``` +```swift +struct Animal: SelectionSet { + // ... + var size: GraphQLEnum { data["size"] } +} +``` +`GraphQLEnum` wraps your generated `EnumType`s and provides the `__unknown` case with an associated value of a raw string. This is necessary for clients to provide forward-compatibility with new enum cases added to a schema in the future. `GraphQLEnum` has pattern matching and `Equatable` conformance implemented that allows you to consume it as if it were your underlying `EnumType` in most cases. + +**Examples:** +```swift +let size: GraphQLEnum = .init(.SMALL) + +size == .SMALL // true +``` +When using switch, you must provide a case for the unknown value. +```swift +switch size { +case .SMALL: break +case .AVERAGE: break +case .LARGE: break +case .__unknown(_): break +default: break +} +``` +Because pattern matching is being used to match against the underling `EnumType` cases, you must also provide a default case. + +To ensure exhaustive switch cases without a default case your generated cases can be wrapped in `.case()`. +```swift +switch size { +case .case(.SMALL): break +case .case(.AVERAGE): break +case .case(.LARGE): break +case .__unknown(_): break +} +``` +If you want to ignore the unknown case, you can access the `.value` field, which returns an optional value of the wrapped type. If the type is an unknown case `.value` will be `nil`. +```swift +switch size.value { +case .SMALL: break +case .AVERAGE: break +case .LARGE: break +default: break +// or +case .none: break +} +``` +See [GraphQLEnum.swift](Sources/ApolloAPI/GraphQLEnum.swift) for implementation details. + +# `InputObject` Generation + +Input objects will be generated for each `input` type in the schema that is used in an argument for any of the operations defined in your application. Input objects are structs that are backed by a `InputDict` struct that stores the values for the fields on the input object in a dictionary. This allows for `InputObject`s to be treated as values types but use copy-on-write semantics under the hood. + +Nullable fields on input objects are represented using `GraphQLNullable` to allow for both `null` and `nil` values. + +Following the [Input Coercion rules](https://spec.graphql.org/draft/#sec-Input-Objects.Input-Coercion) from the GraphQL spec, the server defined default value for a field will be used when passing `nil`. Nullable fields on input objects are represented using `GraphQLNullable` to allow for both `null` and `nil` values. For non-nullable fields, if the schema provides a default value, the field will be represented as an optional to allow for `nil` to be passed. + +**Examples:** + +Nullable field with no default value: +```graphql +input MyInput { + size: RelativeSize +} +``` +```swift +struct MyInput: InputObject { + public private(set) var dict: InputDict + + init(size: GraphQLNullable = nil) { + dict = InputDict(["size": size]) + } + + var size: GraphQLNullable { + get { dict["size"] } + set { dict["size"] = newValue } + } +} +``` +Nullable field with a default value: +```graphql +input MyInput { + size: RelativeSize = SMALL +} +``` +```swift +struct MyInput: InputObject { + public private(set) var dict: InputDict + + init(size: GraphQLNullable) { ... } + + /// If `.none`, defaults to server-provided default value (.SMALL) + var size: GraphQLNullable { ... } +} +``` +Non-nullable field with no default value: +```graphql +input MyInput { + size: RelativeSize! +} +``` +```swift +struct MyInput: InputObject { + public private(set) var dict: InputDict + + init(size: RelativeSize) { ... } + + var size: RelativeSize { ... } +} +``` +Non-nullable field with a default value: +```graphql +input MyInput { + size: RelativeSize! = SMALL +} +``` +```swift +struct MyInput: InputObject { + public private(set) var dict: InputDict + + init(size: RelativeSize?) { ... } + + /// If `nil`, defaults to server-provided default value (.SMALL) + var size: RelativeSize? { ... } +} +``` +> Note that we are not generating these fields with the provided default values. This is to account for default values that may change on the schema in the future. See [Generate Default Parameter Values for `InputObject` Default Values](#generate-default-parameter-values-for-inputobject-default-values) for more discussion. + + +# `GraphQLOperation` Generation + +A `GraphQLOperation` is generated for each operation defined in your application. `GraphQLOperation`s can be queries (`GraphQLQuery`), mutations (`GraphQLMutation`), or subscriptions (`GraphQLSubscription`). + +Each generated operation will conform to the `GraphQLOperation` protocol defined in [GraphQLOperation.swift](Sources/ApolloAPI/GraphQLOperation.swift). + +**Simple Operation - Example:** + +```swift +class AnimalQuery: GraphQLQuery { + let operationName: String = "AnimalQuery" + let document: DocumentType = .notPersisted(definition: .init( + """ + query AnimalQuery { + allAnimals { + species + } + } + """) + + init() {} + + struct Data: SelectionSet { + // ... + } +} +``` + +## Operation Arguments + +For an operation that takes input arguments, the initializer will be generated with parameters for each argument. Arguments can be scalar types, `GraphQLEnum`s, or `InputObject`s. During execution, these arguments will be used as the operation's `variables`, which are then used as the values for arguments on `SelectionSet` fields matching the variables name. + +**Operation With Scalar Argument - Example:** + +```swift +class AnimalQuery: GraphQLQuery { + let operationName: String = "AnimalQuery" + let document: DocumentType = .notPersisted(definition: .init( + """ + query AnimalQuery($count: Int!) { + allAnimals { + predators(first: $count) { + species + } + } + } + """) + + var count: Int + + init(count: Int) { + self.count = count + } + + var variables: Variables? { ["count": count] } + + struct Data: SelectionSet { + // ... + struct Animal: SelectionSet { + static var selections: [Selection] {[ + .field("predators", [Predator.self], arguments: ["first": .variable("count")]) + ]} + } + } +} +``` +In this example, the value of the `count` property is passed into the `variables` for the variable with the key `"count"`. The `Selection` for the field `"predators"`, the argument `"first"` has a value of `.variable("count")`. During execution, the `predators` field will be evaluated with the argument from the operation's `"count"` variable. + +### Nullable Operation Arguments + +For nullable arguments, the code generator will wrap the argument value in a `GraphQLNullable`. The executor will evaluate the `GraphQLNullable` to format the operation variables correctly. See [GraphQLNullable](#nullable-arguments-graphqlnullable) for more information. + +**Operation With Nullable Scalar Argument - Example:** + +```swift +class AnimalQuery: GraphQLQuery { + let operationName: String = "AnimalQuery" + let document: DocumentType = .notPersisted(definition: .init( + """ + query AnimalQuery($count: Int) { + allAnimals { + predators(first: $count) { + species + } + } + } + """) + + var count: GraphQLNullable + + init(count: GraphQLNullable) { + self.count = count + } + + var variables: Variables? { ["count": count] } + + // ... +} +``` + +# `SelectionSet` Generation + +## Metadata + +Each `SelectionSet` has metadata properties that provide the Apollo library the ability to check for valid type conversions at runtime. + +### `__typename` + +`__typename` is a computed property on each concrete instance of a `SelectionSet` that defines the concrete type of the underlying entity that the `SelectionSet` represents. This is a `String` representation that is fetched from the server using the `__typename` metadata field in the query. All queried selection sets will automatically include the `__typename` field. + +### `__objectType` + +`__objectType` is a computed property that provides a strongly typed wrapper for `__typename`. It converts the `__typename` string into a concrete case of the `Object` enum from the schema. + +### `__parentType` + + `__parentType` is a static property on each `SelectionSet` *type* that defines the known type that the `SelectionSet` is being fetched on. The `__parentType` may be an `Object`, `Interface`, or `Union`. This property is represented by the `ParentType` enum. `__parentType` is generated for each `SelectionSet`, not computed at runtime. + +### `selections` + +Indicates the fields that should be “selected” during GraphQL execution. See [Selection Generation](#selection-generation) for more information. + +### Example + +To illustrate the difference between these properties, we will use an example. Given the query: + +```graphql +query { + allAnimals { + species + } +} +``` + +The `allAnimals` field has a type of `Animal`, which is an interface. Each concrete instance of the `Animal` struct could have a different concrete type (`Cat`, `Fish`, `Bird`, etc.) + +The `__typename` field, provided by the server would provide the actual concrete type for each entity as a `String`. +The `__objectType` property would convert this into a strongly typed `Object` from the generated schema types. This property will have different values for each concrete `Animal` object. +The `__parentType` for all of these entities would still be the same — the `Animal` interface. + +# Field Accessor Generation + +Each field selected in a `SelectionSet`'s `selections` can be accessed via a generated field accessor. Generated field accessors provide type-safe access to the values for fields that are selected on the `SelectionSet`. These field accessors access the data on the underlying `ResponseDict`, which holds the data for the `SelectionSet`. The data is then cast to the correct type and any transformations needed are applied under the hood. Because the GraphQL execution validates response data before mapping it onto generated `SelectionSet`s, the data is guarunteed to exist and be the correct type. + +When the `species` field on an `Animal` is selected, the following field accessor is generated: +```swift +var species: String { data["species"] } +``` +The `ResponseDict` accesses the field's value and force casts it to a `String`, which will always be safe. + +# `Fragment` Generation + +Fragments are used in GraphQL operations primarily for two reasons: + +1. Sharing common `SelectionSet`s across multiple operations +2. Querying fields on a more specific type than the current parent type + +## Fragment Structs + +When sharing a common `SelectionSet` across multiple operations, a fragment can be used. This can reduce the size of your operation definition files. Additionally, and often more importantly, it allows you to reuse generated `SelectionSet` data objects across multiple operations. This can enable your code to consume fragments of an operation’s response data irrespective of the operation executed. Using fragments this way acts as a form of abstraction similar to protocols. It has often been proposed that fragments should be represented as generated protocols, however due to implementation details of the Swift language, this approach has serious limitations. See [Appendix A: Why Fragment Protocols Don’t Work](#appendix-a-why-fragment-protocols-dont-work) for more information. + +Instead of protocols, fragments are generated as concrete `SelectionSet` structs that any `SelectionSet` that contains the fragment can then be converted to. + +**Fragment Definition:** + +```graphql +fragment AnimalDetails on Animal { + species +} +``` + +**Query Input:** + +```graphql +query AllAnimalSpecies { + allAnimals { + ...AnimalDetails + } +} +``` + +**Generated Output:** +`AnimalDetails.Swift` + +```swift +struct AnimalDetails: SelectionSet, Fragment { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Animal.self) } + let data: ResponseDict + + var species: String { data["species"] } +} +``` + +`AllAnimalSpeciesQuery.swift` (`Animal` Object) + +```swift +struct Animal: SelectionSet, HasFragments { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Animal.self) } + let data: ResponseDict + + var species: String { data["species"] } + + struct Fragments: ResponseObject { + let data: ResponseDict + + var animalDetails: AnimalDetails { _toFragment() } + } +} +``` + +The query’s `Animal` struct conforms to `HasFragments`, which is a protocol that exposes a `fragments` property that exposes the nested `Fragments` struct. The fragments a `SelectionSet` contains are exposed in this `Fragments` struct via computed properties that utilize a `_toFragment()` helper function. This allows you to access the `AnimalDetails` fragment via `myAnimal.fragments.animalDetails`. + +### Merging Fragment Fields Into Parent `SelectionSet` + +In the above example you may note that the `species` field is accessible directly on the `Animal` object without having to access the `AnimalDetails` fragment first. This is because fields from fragments that have the same `__parentType` as the enclosing `SelectionSet` are automatically merged into the enclosing `SelectionSet`. + +## Inline Fragments + +Inline fragments are fragments that are unnamed and defined within an individual operation. These fragments cannot be shared, and as such, individual fragment `SelectionSet`s are not generated. Inline fragments are used strictly for handling “Type Cases“. + +# `TypeCase` Generation + +When using a fragment to fetch fields on a more specific interface or type than the `SelectionSet`’s `__parentType`, we create a new `SelectionSet` for the more specific type. We refer to these more specific `SelectionSet`s as “Type Cases”. + + +> Note: A Type Case can be defined using either an inline fragment or an independent, named fragment. + + +For example, an inline fragment `... on Pet { humanName }` would generate an `AsPet` object nested inside of the enclosing entity’s `SelectionSet`. + +A Type Case is always represented as an optional property on the enclosing entity, as the enclosing entity may or may not be of a type that matches the fragment’s type. + +Let’s take a look at an example of this: + +**Query Input:** + +```graphql +query { + allAnimals { + species + ... on Pet { + humanName + } + } +} +``` + +**Generated Output:** (`Animal` Object) + +```swift +struct Animal: RootSelectionSet { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Animal.self) } + let data: ResponseDict + + var asPet: AsPet? { _asType() } + + var species: String { data["species"] } + + struct AsPet: TypeCase { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Pet.self) } + let data: ResponseDict + + var species: String { data["species"] } + var humanName: String? { data["humanName"] } + } +} +``` + +The computed property for `asPet` uses an internal function `_asType()`, which is defined in an extension on `SelectionSet`. This function checks the concrete `__objectType` against the `__parentType` of the Type Case to see if the entity can be converted to the `SelectionSet` of the TypeCase. An `AsPet` struct will only be returned if the underlying entity for the `Animal` is a type that conforms to the `Pet` `Interface`, otherwise `asPet` will return `nil`. + +## Merging `TypeCase` Fields Into Children and Siblings + +Similarly to merging in fragment fields, fields from a parent and any sibling `TypeCase`s that match the `__parentType` of a `TypeCase` are merged in as well. In the above example the `species` field that is selected by the `Animal` `SelectionSet` is merged into the child `AsPet` `TypeCase`. The `AsPet` represents the same entity as the `Animal`, and because we know that the `species` field will exist for the entity, it is merged in. Since the field will already be selected and will exist in the underlying `ResponseDict`, the child `SelectionSet` does not need to duplicate the `Selection` for the field. Only a duplicated field accessor needs to be generated. For more explanation of how the `Selection`s for `TypeCase`s work, see [`TypeCase` Selections](#typecase-selections). + +Additionally, since any fields from other `TypeCases` defined on the parent `SelectionSet` that match the type of a `TypeCase` are guaranteed to exist, they are also merged in. This makes it much easier to consume the data on a generated `TypeCase`. + +Expanding on the above example, we can see how sibling `TypeCase` selections can be merged. + +**Query Input:** + +```graphql +query { + allAnimals { + species + ... on Pet { + humanName + } + ... on Cat { + isJellicle + } + } +} +``` + +**Generated Output:** (`Animal` Object) + +```swift +struct Animal: RootSelectionSet { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Animal.self) } + let data: ResponseDict + + var species: String { data["species"] } + + var asPet: AsPet? { _asType() } + var asCat: AsCat? { _asType() } + + struct AsPet: TypeCase { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Pet.self) } + let data: ResponseDict + + var species: String { data["species"] } + var humanName: String? { data["humanName"] } + } + + struct AsCat: TypeCase { + static var __parentType: ParentType { .Object(AnimalKingdomAPI.Cat.self) } + let data: ResponseDict + + var species: String { data["species"] } + var humanName: String? { data["humanName"] } + var isJellicle: Bool { data["isJellicle"] } + } +} +``` + +The `AsCat` `TypeCase` is on the `__parentType` “`Cat`" and the "`Cat`" object type implements the “`Pet`" `Interface`. Given this information the code generation engine can deduce that, any `AsCat` will also have the `humanName` field selected by the `AsPet` `TypeCase`. This field gets merged in and the `AsCat` has a field accessor for it. + +# Union Generation + +Union types are generated just like any other `SelectionSet`. Because a union has no knowledge of the underlying type or the selections available, a union `SelectionSet` will not generally include any field accessors itself. Rather, a union will only provide access to its child `TypeCases`s. + +**Example:** +```graphql +query { + classroomPets { + ... on Pet { + humanName + } + ... on Bird { + wingspan + } + } +} +``` +```swift +struct ClassroomPet: RootSelectionSet { + static var __parentType: ParentType { .Union(AnimalKingdomAPI.ClassroomPet.self) } + + var asPet: AsPet? { _asType() } + var asBird: AsBird? { _asType() } + + struct AsPet: TypeCase { + static var __parentType: ParentType { .Interface(AnimalKingdomAPI.Pet.self) } + + var humanName: String? { data["humanName"] } + } + + struct AsBird: TypeCase { + static var __parentType: ParentType { .Object(AnimalKingdomAPI.Bird.self) } + + var humanName: String? { data["humanName"] } + var wingspan: Int { data["wingspan"] } + } +} +``` + +# `Selection` Generation + +Each `SelectionSet` includes an array of `Selection`s that indicate what fields should be “selected” during execution. +A parent `SelectionSet` will conditionally include its children’s selections as nested selections. The `GraphQLExecutor` determines if child selections should be included. + +While merged fields will be generated as field accessors on children, the `selections` array for each `SelectionSet` does not merge in selections from parents, children, or siblings. The `selections` array will closely mirror the query operation definition that the generated objects are based upon. + +`Selection` is an enum with cases representing different types of selections. A simple field selection is represented as a `Field`, but nested selections that are conditionally included are represented by additional types. + +## `Field` Selections + +The `Selection.field(Field)` case represents a specific field that should be selected. It contains a `Field` struct that includes the field name; the field alias if it exists; any arguments the field takes, and the field’s type. + +**Example:** + +```graphql +query { + allAnimals { + species + } +} +``` + +```swift +struct Animal: RootSelectionSet { + static var selections: [Selection] {[ + .field("species", String.self) + ]} +} +``` + +### Field Arguments + +If a field takes arguments, the arguments will be generated on the field’s `Selection`. Arguments are represented as a dictionary of argument names and their values. An argument’s value is represented as an `InputValue` and can be a scalar value, a list of other `InputValue`s, a generated input type, or a variable. Variable arguments have their values provided when an instance of an operation is created. + +**Scalar Value Argument Example:** + +```graphql +query { + allAnimals { + predators(first: 3) + } +} +``` + +```swift +struct Animal: RootSelectionSet { + static var selections: [Selection] {[ + .field("predators", [Predator].self, arguments: ["first": 3]) + ]} +} +``` + +**Variable Argument Example:** + +``` +query($count: Int) { + allAnimals { + predators(first: $count) + } +} +``` + +```swift +class Query: GraphQLQuery { + var count: Int + init(count: Int) { ... } + + struct Animal: RootSelectionSet { + static var selections: [Selection] {[ + .field("predators", [Predator].self, arguments: ["first": .variable("count")]) + ]} + } +} +``` + +## `@skip/@include` Selections + +One or more `Selection`s may be conditionally included based on a `@skip` or `@include` directive. These `Selection`s provide a variable name for a variable of type `Boolean` on the operation that will determine if the `Selection`s are included. + +**Single Field Example:** + +```graphql +query($skipSpecies: Boolean) { + allAnimals { + species @skip(if: $skipSpecies) + } +} +``` + +```swift +class Query: GraphQLQuery { + var skipSpecies: Bool + init(skipSpecies: Bool) { ... } + + struct Animal: RootSelectionSet { + static var selections: [Selection] {[ + .skip(if: "skipSpecies", .field("species", String.self)) + ]} + } +} +``` + +**Multiple Fields Example:** + +```graphql +query($includeDetails: Boolean) { + allAnimals { + species + @include(if: $includeDetails) { + height { + meters + } + skinCovering + } + } +} +``` + +```swift +class Query: GraphQLQuery { + var includeDetails: Bool + init(includeDetails: Bool) { ... } + + struct Animal: RootSelectionSet { + static var selections: [Selection] {[ + .field("species", String.self) + .include(if: "includeDetails", [ + .field("height", Height.self), + .field("skinCovering", GraphQLEnum.self), + ]), + ]} + + struct Height: RootSelectionSet { + static var selections: [Selection] {[ + .field("meters", Int.self) + ]} + } + } +} +``` + +## `Fragment` Selections + +Fragments included by a `SelectionSet` reference the `Fragment` `SelectionSet` and automatically include all the fragment’s `selections`. + +**Example:** + +```graphql +query { + allAnimals { + ...AnimalDetails + } +} + +fragment AnimalDetails on Animal { + height { + meters + } + skinCovering +} +``` + +```swift +struct AnimalDetails: RootSelectionSet, Fragment { + static var selections: [Selection] {[ + .field("height", Height.self) + .field("skinCovering", GraphQLEnum.self), + ]} + + struct Height: RootSelectionSet { + static var selections: [Selection] {[ + .field("meters", Int.self) + ]} + } +} + +class Query: GraphQLQuery { + struct Data: RootSelectionSet { + static var selections: [Selection] {[ + .field("allAnimals", [Animal].self), + ]} + + struct Animal: RootSelectionSet { + static var selections: [Selection] {[ + .fragment(AnimalDetails.self) + ]} + } + } +} +``` + +## `TypeCase` Selections + +When a `SelectionSet` has a nested type case, the type case’s selections are only included if the `__typename` of the object matches a type that is compatible with the `TypeCase`’s `__parentType`. This is determined at runtime by the `GraphQLExecutor` during the process of executing the `selections` on each `SelectionSet`. While the selections for each `TypeCase` are not duplicated, field accessors for fields merged from the parent and other `TypeCase`s will be generated on each `TypeCase` struct. This is described in [Merging `TypeCase` Fields Into Children and Siblings](#merging-typecase-fields-into-children-and-siblings). + +The `selections` for a `TypeCase` are included if: + +* If the `__parentType` is an `Object` type: + * If the runtime type of the data object is equal to the object type. +* If the `__parentType` is an `Interface` type: + * If the runtime type of the data object is a type that implements the interface. +* If the `__parentType` is a `Union` type: + * If the runtime type of the data object is an object type in the union’s possible types. + +**Inline TypeCase Example:** + +```graphql +query { + allAnimals { + species + ... on Pet { + humanName + } + ... on Bird { + wingpsan + } + } +} +``` + +```swift +struct Animal: RootSelectionSet { + static var __parentType: ParentType { .Interface(.Animal) } + static var selections: [Selection] {[ + .field("species", String.self), + .typeCase(AsPet.self), + .typeCase(AsBird.self), + ]} + + var species: String { data["species" ]} + + var asPet: AsPet? { _asType() } + var asBird: AsBird? { _asType() } + + struct AsPet: TypeCase { + static var __parentType: ParentType { .Interface(.Pet) } + static var selections: [Selection] {[ + .field("humanName", String?.self), + ]} + + var species: String { data["species" ]} + var humanName: String? { data["humanName" ]} + } + + struct AsBird: TypeCase { + static var __parentType: ParentType { .Interface(.Pet) } + static var selections: [Selection] {[ + .field("wingspan", Int.self), + ]} + + var species: String { data["species" ]} + var humanName: String? { data["humanName" ]} + var wingspan: Int { data["wingspan" ]} + } +} +``` + +**Named Fragment TypeCase Example:** *Field and type case accessors omitted for brevity.* +```graphql +query { + allAnimals { + species + ...PetDetails + } +} + +fragment PetDetails on Pet { + humanName +} +``` + +```swift +struct PetDetails: RootSelectionSet, Fragment { + static var __parentType: ParentType { .Interface(.Pet) } + static var selections: [Selection] {[ + .field("humanName", String?.self), + ]} +} + +struct Animal: RootSelectionSet { + static var __parentType: ParentType { .Interface(.Animal) } + static var selections: [Selection] {[ + .field("species", String.self), + .typeCase(AsPet.self), + ]} + + struct AsPet: TypeCase { + static var __parentType: ParentType { .Interface(.Pet) } + static var selections: [Selection] {[ + .fragment(PetDetails.self), + ]} + } +} +``` + +## `RootSelectionSet` vs `TypeCase` + +A `SelectionSet` that represents the root selections on its `__parentType` is a `RootSelectionSet`. Nested selection sets for `TypeCase`s are not `RootSelectionSet`s. + +While a `TypeCase` only provides the additional selections that should be selected for its specific type, a `RootSelectionSet` guarantees that all fields for itself and its nested type cases are selected. When considering a specific `TypeCase`, all fields will be selected either by the root selection set, a fragment spread, the type case itself, or another compatible `TypeCase` on the root selection set. + +For this reason, only a `RootSelectionSet` can be executed by a `GraphQLExecutor`. Executing a non-root `SelectionSet` would result in fields from its parent `RootSelectionSet` not being collected into the `ResponseDict` for the `SelectionSet`'s data. + +# Handling Unknown Types + +Types that are added to your schema server side after the code generation has run could be returned in a response from the server, but will not have a generated `Object` type object that recognizes them. These types are unknown to the client-side type system. Because all data about these types is not known, certain functionality will be limited on unknown types. The `RootSelectionSet` fields will be selected properly for unknown types, but any child `TypeCase` will not be present on unknown types, as we are unable to know if the unknown type matches a `TypeCase` or not. + +# Cache Key Resolution + +Each generated object can provide a function for computing it's cache key by conforming to the `CacheKeyProvider` protocol. Extensions can be created manually to provide conformance to this protocol on object types. + +```swift +extension Cat: CacheKeyProvider { + static func cacheKey(for data: JSONObject) -> String? { + guard let humanName = data["humanName"] as? String, + let species = data["species"] as? String else { + return nil + } + return humanName + "_" + species + } +} +``` +This function will be called whenever a cache key needs to be computed for a JSON response with a `__typename` matching the typename for a `Cat` object. (This mapping uses the generated mapper function on the `SchemaConfiguration`.) + +If `nil` is returned, the object will be treated as if it does not have a unique cache key and will cached without normalization. + +> When reading/writing data to the cache, the `__typename` will always be prepended to the returned cache key. It does not need to be included in the value returned by your `CacheKeyProvider`. This means that cache keys only need to be guaranteed to be unique across objects of the same type. + +## Composable Cache Key Providers + +Multiple types that compute their cache keys in the same way can share their cache key provider function via protocol composition. + +```swift +protocol PetCacheKeyProvider: CacheKeyProvider { } +extension PetCacheKeyProvider { + static func cacheKey(for data: JSONObject) -> String? { + guard let humanName = data["humanName"] as? String, + let species = data["species"] as? String else { + return nil + } + return humanName + "_" + species + } +} + +extension Cat: PetCacheKeyProvider {} +extension Dog: PetCacheKeyProvider {} +extension Fish: PetCacheKeyProvider {} +``` + +> In the future, we hope to provide mechanisms to have `CacheKeyProvider` implementations automatically generated based on client-side directives that can be added as extensions to your graphql schema directly. + +## Unknown Type Cache Key Providers + +If you would like to automatically provide cache key computation for unknown types (types that are added to your schema after code generation), you can extend your generated `SchemaConfiguration` to conform to the `SchemaUnknownTypeCacheKeyProvider` protocol. + +```swift +extension AnimalKindgomAPI: SchemaUnknownTypeCacheKeyProvider { + static func cacheKeyForUnknownType(withTypename typename: String, data: JSONObject) -> String? { + guard let id = data["id"] as? String else { + return nil + } + + return id + } +} +``` + +# Appendices + +## Appendix A: Why Fragment Protocols Don’t Work + +Consider the following fragment and queries. + +```graphql +fragment HeightInMeters on Animal { + height { + meters + } + } + +query AnimalHeight { + allAnimals { + ...HeightInMeters + height { + feet + yards + } + } +} + +query AnimalMeters { + allAnimals { + ...HeightInMeters + } +} +``` + +If we generated protocols for the `HeightInMeters` fragment, it would look like this: + +```swift +protocol HeightInMeters { + associatedtype Height: HeightInMeters_Height + + var height: Height { get } +} + +protocol HeightInMeters_Height { + var meters: Int { get } +} +``` + +The generated queries `ResponseData` objects would be: *(generated code simplified for example)* + +```swift +// AnimalHeightQuery.Data.Animal +struct Animal: RootSelectionSet, HeightInMeters { + struct Height: RootSelectionSet, HeightInMeters_Height { + let meters: Int + let feet: Int + let yards: Int + } + + let height: Height { data["height"] } +} + +// AnimalMetersQuery.Data.Animal +struct Animal: RootSelectionSet, HeightInMeters { + final class Height: RootSelectionSet, HeightInMeters_Height { + let meters: Int + } + + let height: Height { data["height"] } +} + +``` + +Then you could not reference the fragment as a concrete type for re-use (such as in a UI component). + +```swift +class AnimalMetersLabelView { + let animalHeight: HeightInMeters // Compiler Error: + // "Protocol with associatedtype cannot be + // referenced as concrete property type." +} +``` + +This gets even more complicated (and broken) when you nest fragments inside of each other. + +While [SE-309](https://github.com/apple/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md) aims to make working with existential types easier, it does not solve this problem. The error will only be moved from when you reference the `HeightInMeters` protocol, to when you attempt access its `height` field. + +## Appendix B: Nested Fragments for Composition of Multiple Types + +Here we want to generate the `Pet` & `WarmBlooded` types, but we also want to generate an additional composed type that is both a `Pet & Warmblooded`. We do that by explicitly copying the referenced fragment into a nested field on the `Pet` `TypeCase`. The idea here is that you are able to configure your response objects to provide data in the shape you want. Even if certain selections – or entire type cases – are redundant, you can provide them to ensure that your generated models provide fields in the way you want to consume them in your application. + +**Query Input:** +```graphql +query { + allAnimals { + species + ... on Pet { + ...PetDetails + ... on WarmBlooded { + ...WarmBloodedDetails + } + } + ...WarmBloodedDetails + } +} + +fragment PetDetails on Pet { + humanName + favoriteToy +} + +fragment WarmBloodedDetails on WarmBlooded { + bodyTemperature +} +``` + +**Output:** +```swift +public struct Animal: RootSelectionSet: HasFragments { + var species: String { data["species"] } + + var asPet: AsPet? { _asType() } + var asWarmBlooded: AsWarmBlooded? { _asType() } + + /// Animal.AsPet + struct AsPet: TypeCase, HasFragments { + var species: String { data["species"] } + var humanName: String? { data["humanName"] } + var favoriteToy: String { data["favoriteToy"] } + + var asWarmBlooded: AsWarmBlooded? { _asType() } + + struct Fragments: ResponseObject { + var PetDetails: PetDetails { _toFragment() } + } + + /// Animal.AsPet.AsWarmBlooded + struct AsWarmBlooded: TypeCase, HasFragments { + var species: String { data["species"] } + var humanName: String? { data["humanName"] } + var favoriteToy: String { data["favoriteToy"] } + var bodyTemperature: Int { data["bodyTemperature"] } + + struct Fragments: ResponseObject { + var warmBloodedDetails: WarmBloodedDetails { _toFragment() } + } + } + } + + /// Animal.AsWarmBlooded + struct AsWarmBlooded: TypeCase, HasFragments { + var species: String { data["species"] } + var bodyTemperature: Int { data["bodyTemperature"] } + + struct Fragments: ResponseObject { + var warmBloodedDetails: WarmBloodedDetails { _toFragment() } + } + } +} +``` + +# Alternatives & Suggestions + +## `Codable` Support For Generated Objects + +Previous proposals for iOS code generation have implemented `Codable` on generated model object. This functionality has been discussed by the community frequently. However, this proposal does not include `Codable` conformance. While `Codable` has become a commonly used standard in iOS development, we do not believe it adds value to our generated objects. + +Under the hood, all the JSON from a response must be parsed and validated through the `GraphQLExecutor` before being mapped onto the generated `SelectionSet` models. It cannot be automatically decoded onto `Codable` objects using the `JSONDecoder`. We could explore creating a custom decoder that uses the `GraphQLExecutor`, but adding this additional layer of abstraction would only add more complexity to the internal execution process and likely negatively impact performance without providing any new user-facing functionality. + +We also see little value in `Codable` conformance for encoding the objects after the data has been executed and mapped onto them. The ideal way to persist GraphQL data is in the `NormalizedCache` that provided by the Apollo Client. The `NormalizedCache` relies on the `GraphQLExecutor` for reading and writing cache data, so `Codable` doesn't provide us any value internally. + +Storing GraphQL data outside of the `NormalizedCache` is generally discouraged. While we won't prevent users from doing so, it is not officially supported by the Apollo iOS Client. We are looking into features to make the `NormalizedCache` more feature rich and performant in future versions. Investing in `Codable` support provides no value to users that are using the `NormalizedCache`, and as such is outside the scope of this project at the current time. + +## Generate Default Parameter Values for InputObject Default Values + +For fields with default values provided by the schema, we have decided to generate the fields as optional, but not include the default values in the generated code. + +```graphql +input MyInput { + size: RelativeSize = SMALL +} +``` +```swift +struct MyInput: InputObject { + public private(set) var dict: InputDict + + init(size: GraphQLNullable) { ... } + + /// If `nil`, defaults to server-provided default value (.SMALL) + var size: GraphQLNullable { ... } +} +``` +An alternative approach is to provide the default value as a generated default argument. +```swift +struct MyInput: InputObject { + public private(set) var dict: InputDict + + init(size: GraphQLNullable = .some(.SMALL)) { ... } + + /// If `nil`, defaults to server-provided default value (.SMALL) + var size: GraphQLNullable { ... } +} +``` +This however does not account for the fact that future changes to the default value of a field on an input type in a schema are considered to be backwards compatible. By generating the default value, we create a client that explicitly sends the value that *was* the default value when the type was generated – not necessarily the current default value of the server. In this case, the user could still explicitly pass `nil` to the initializer to indicate the intention to use the current default value as resolved by the server. However this is unclear at the call site and does not fall inline with the intentions of input coercion in the GraphQL Spec. + +For this reason, we have opted to not generate default values. + +## Concrete Subtypes as Enums + +[@designatedNerd’s initial proposal includes enums with associated values for subtypes.](https://github.com/apollographql/StarWarsiOSMk2/blob/master/StarWarsMark2/Queries/HeroTypeDependentAliasedFieldQueryMk2.swift#L43) + +These `SubType` enums work for concrete types but not interfaces (because a type could conform to multiple interfaces). We don't plan on generating all the concrete types as data structures unless they are specifically enumerated (`... on Pet`) + +It is undecided if we should implement these or not. They are only valuable in the specific scenario where you have inline fragments for multiple concrete types. + +Given this query: + +```graphql +query { + allAnimals { + ... on Bird { + wingspan + } + ... on Cat { + bodyTemperature + } + } +} +``` + +Without the `Subtypes` enum: + +```swift +struct Animal: RootSelectionSet { + var asBird: AsBird? { _asType() } + var asCat: Cat? { _asType() } + + struct AsBird: TypeCase { ... } + struct AsCat: TypeCase { ... } +} +``` + +With the `Subtypes` enum: + +```swift +struct Animal: RootSelectionSet { + var asBird: AsBird? { _asType() } + var asCat: Cat? { _asType() } + + enum Subtype { + case bird(AsBird) + case cat(AsCat) + case _other(Animal) + } + + var subtype: Subtype { + switch __objectType { + case is Bird.self: return .bird(AsBird(data: data)) + case is Cat.Type: return .cat(AsCat(data: data)) + default: return ._other(self) + } + } + + struct AsBird: TypeCase { ... } + struct AsCat: TypeCase { ... } +} +``` + +Possible Options: + +* Don't implement the subtypes enum at all +* Use a directive `@generateSubTypeEnum` (or some other name) to inform us that the subtypes enum should be generated (if the directive is not present default is option #1.) + ```graphql + query { + allAnimals @generateSubTypeEnum { + ... on Bird { + wingspan + } + ... on Cat { + bodyTemperature + } + } + } + ``` +* Implement logic so that if your query has _**one or more**_ fragments on a concrete type, then we generate the subtypes (generate the enum with only 1 case + `_other`) +* Implement logic so that if your query has _**more than one**_ fragment on a concrete type, then we generate the subtypes + +# Possible Future Additions + +Looking towards the future, the 1.0 implementation of the code generation engine opens the door to many possible future improvements to Apollo iOS. Here are some of the most highly considered additions that may come in future versions. + +## Client-Side Directives For Automatic `CacheKeyProvider` Generation + +Under this proposal, computation of cache keys must be implemented manually using the process described in [Cache Key Resolution](#cache-key-resolution). In the future, we hope to add a `keyFields` client-side directive that can be added to your project as extensions to the types on your GraphQL schema. This would allow us to generate the `CacheKeyProviders` for you. + +## Better Support For Types Added To Schema After Code Generation + +In order to cast new concrete types to type conditions, we would need to know the metadata about what interfaces the types implement. We could possibly use a schema introspection query to fetch additional types added to the schema after code generation. Some information about these types may also be able to be assumed based on the response data returned from the server, indicating if a specific unknown type matches with some certain type cases. + +## Generation of Enums Providing All Known Possible Types for Unions + + Similar to the [proposal for subtype enums for Type Cases](#concrete-subtypes-as-enums), subtypes enum could be genera diff --git a/Configuration/Apollo/Apollo-Project-Debug.xcconfig b/Configuration/Apollo/Apollo-Project-Debug.xcconfig deleted file mode 100644 index 96f6ca2629..0000000000 --- a/Configuration/Apollo/Apollo-Project-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "../Shared/Project-Debug.xcconfig" diff --git a/Configuration/Apollo/Apollo-Project-Performance-Testing.xcconfig b/Configuration/Apollo/Apollo-Project-Performance-Testing.xcconfig deleted file mode 100644 index 642cf691b3..0000000000 --- a/Configuration/Apollo/Apollo-Project-Performance-Testing.xcconfig +++ /dev/null @@ -1,6 +0,0 @@ -#include "../Shared/Project-Release.xcconfig" - -ONLY_ACTIVE_ARCH = YES - -COPY_PHASE_STRIP = NO -ENABLE_TESTABILITY = YES diff --git a/Configuration/Apollo/Apollo-Project-Release.xcconfig b/Configuration/Apollo/Apollo-Project-Release.xcconfig deleted file mode 100644 index 364f240d89..0000000000 --- a/Configuration/Apollo/Apollo-Project-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "../Shared/Project-Release.xcconfig" diff --git a/Configuration/Apollo/Apollo-Target-ApolloAPI.xcconfig b/Configuration/Apollo/Apollo-Target-ApolloAPI.xcconfig deleted file mode 100644 index d8891077fa..0000000000 --- a/Configuration/Apollo/Apollo-Target-ApolloAPI.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/ApolloAPI/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-ApolloCodegenLib.xcconfig b/Configuration/Apollo/Apollo-Target-ApolloCodegenLib.xcconfig deleted file mode 100644 index cf7e182e14..0000000000 --- a/Configuration/Apollo/Apollo-Target-ApolloCodegenLib.xcconfig +++ /dev/null @@ -1,4 +0,0 @@ -#include "../Shared/Workspace-Target-Framework.xcconfig" -#include "../Shared/Workspace-Target-Codegen.xcconfig" - -INFOPLIST_FILE = Sources/ApolloCodegenLib/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-ApolloUtils.xcconfig b/Configuration/Apollo/Apollo-Target-ApolloUtils.xcconfig deleted file mode 100644 index 4ed55ec6ba..0000000000 --- a/Configuration/Apollo/Apollo-Target-ApolloUtils.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/ApolloUtils/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-CodegenTestSupport.xcconfig b/Configuration/Apollo/Apollo-Target-CodegenTestSupport.xcconfig deleted file mode 100644 index 9a4b0d7109..0000000000 --- a/Configuration/Apollo/Apollo-Target-CodegenTestSupport.xcconfig +++ /dev/null @@ -1,4 +0,0 @@ -#include "../Shared/Workspace-Target-TestSupport.xcconfig" -#include "../Shared/Workspace-Target-Codegen.xcconfig" - -INFOPLIST_FILE = Sources/ApolloCodegenTestSupport/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-CodegenTests.xcconfig b/Configuration/Apollo/Apollo-Target-CodegenTests.xcconfig deleted file mode 100644 index 114ec72b9a..0000000000 --- a/Configuration/Apollo/Apollo-Target-CodegenTests.xcconfig +++ /dev/null @@ -1,4 +0,0 @@ -#include "../Shared/Workspace-Target-Codegen.xcconfig" -#include "../Shared/Workspace-Target-Test.xcconfig" - -INFOPLIST_FILE = Tests/ApolloCodegenTests/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-Framework.xcconfig b/Configuration/Apollo/Apollo-Target-Framework.xcconfig deleted file mode 100644 index e99c60a3ab..0000000000 --- a/Configuration/Apollo/Apollo-Target-Framework.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/Apollo/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-GitHubAPI.xcconfig b/Configuration/Apollo/Apollo-Target-GitHubAPI.xcconfig deleted file mode 100644 index 70d0c0205b..0000000000 --- a/Configuration/Apollo/Apollo-Target-GitHubAPI.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/GitHubAPI/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-PerformanceTests.xcconfig b/Configuration/Apollo/Apollo-Target-PerformanceTests.xcconfig deleted file mode 100644 index 28d3d34faa..0000000000 --- a/Configuration/Apollo/Apollo-Target-PerformanceTests.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Test.xcconfig" - -INFOPLIST_FILE = Tests/ApolloPerformanceTests/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-ServerIntegrationTests.xcconfig b/Configuration/Apollo/Apollo-Target-ServerIntegrationTests.xcconfig deleted file mode 100644 index df8accca9a..0000000000 --- a/Configuration/Apollo/Apollo-Target-ServerIntegrationTests.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -#include "../Shared/Workspace-Universal-Test.xcconfig" - -INFOPLIST_FILE = Tests/ApolloServerIntegrationTests/Info.plist - -SUPPORTED_PLATFORMS = macosx diff --git a/Configuration/Apollo/Apollo-Target-StarWarsAPI.xcconfig b/Configuration/Apollo/Apollo-Target-StarWarsAPI.xcconfig deleted file mode 100644 index dd499beef2..0000000000 --- a/Configuration/Apollo/Apollo-Target-StarWarsAPI.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/StarWarsAPI/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-SubscriptionAPI.xcconfig b/Configuration/Apollo/Apollo-Target-SubscriptionAPI.xcconfig deleted file mode 100644 index 8da079e221..0000000000 --- a/Configuration/Apollo/Apollo-Target-SubscriptionAPI.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/SubscriptionAPI/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-TestHost-iOS.xcconfig b/Configuration/Apollo/Apollo-Target-TestHost-iOS.xcconfig deleted file mode 100644 index bfb1742c9c..0000000000 --- a/Configuration/Apollo/Apollo-Target-TestHost-iOS.xcconfig +++ /dev/null @@ -1,12 +0,0 @@ -#include "../Shared/Workspace-Target-Application.xcconfig" - -SDKROOT = iphoneos -SUPPORTED_PLATFORMS = iphonesimulator iphoneos - -ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES - -INFOPLIST_FILE = Tests/TestHost iOS/Info.plist -PRODUCT_BUNDLE_IDENTIFIER = com.apollographql.$(PRODUCT_NAME:rfc1034identifier) -PRODUCT_NAME = $(TARGET_NAME) - -ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon diff --git a/Configuration/Apollo/Apollo-Target-TestSupport.xcconfig b/Configuration/Apollo/Apollo-Target-TestSupport.xcconfig deleted file mode 100644 index 4ee2a63e67..0000000000 --- a/Configuration/Apollo/Apollo-Target-TestSupport.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Target-TestSupport.xcconfig" - -INFOPLIST_FILE = Sources/ApolloTestSupport/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-Tests.xcconfig b/Configuration/Apollo/Apollo-Target-Tests.xcconfig deleted file mode 100644 index 83f979af1e..0000000000 --- a/Configuration/Apollo/Apollo-Target-Tests.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Test.xcconfig" - -INFOPLIST_FILE = Tests/ApolloTests/Info.plist diff --git a/Configuration/Apollo/Apollo-Target-UploadAPI.xcconfig b/Configuration/Apollo/Apollo-Target-UploadAPI.xcconfig deleted file mode 100644 index 86be4a4c1c..0000000000 --- a/Configuration/Apollo/Apollo-Target-UploadAPI.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/UploadAPI/Info.plist diff --git a/Configuration/Apollo/ApolloSQLite-Project-Debug.xcconfig b/Configuration/Apollo/ApolloSQLite-Project-Debug.xcconfig deleted file mode 100644 index 96f6ca2629..0000000000 --- a/Configuration/Apollo/ApolloSQLite-Project-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "../Shared/Project-Debug.xcconfig" diff --git a/Configuration/Apollo/ApolloSQLite-Project-Release.xcconfig b/Configuration/Apollo/ApolloSQLite-Project-Release.xcconfig deleted file mode 100644 index 364f240d89..0000000000 --- a/Configuration/Apollo/ApolloSQLite-Project-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "../Shared/Project-Release.xcconfig" diff --git a/Configuration/Apollo/ApolloSQLite-Target-Framework.xcconfig b/Configuration/Apollo/ApolloSQLite-Target-Framework.xcconfig deleted file mode 100644 index 1634591778..0000000000 --- a/Configuration/Apollo/ApolloSQLite-Target-Framework.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/ApolloSQLite/Info.plist diff --git a/Configuration/Apollo/ApolloWebSocket-Project-Debug.xcconfig b/Configuration/Apollo/ApolloWebSocket-Project-Debug.xcconfig deleted file mode 100644 index 96f6ca2629..0000000000 --- a/Configuration/Apollo/ApolloWebSocket-Project-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "../Shared/Project-Debug.xcconfig" diff --git a/Configuration/Apollo/ApolloWebSocket-Project-Release.xcconfig b/Configuration/Apollo/ApolloWebSocket-Project-Release.xcconfig deleted file mode 100644 index 364f240d89..0000000000 --- a/Configuration/Apollo/ApolloWebSocket-Project-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "../Shared/Project-Release.xcconfig" diff --git a/Configuration/Apollo/ApolloWebSocket-Target-Framework.xcconfig b/Configuration/Apollo/ApolloWebSocket-Target-Framework.xcconfig deleted file mode 100644 index bf6d204cb8..0000000000 --- a/Configuration/Apollo/ApolloWebSocket-Target-Framework.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -INFOPLIST_FILE = Sources/ApolloWebSocket/Info.plist diff --git a/Configuration/Shared/Project-Debug.xcconfig b/Configuration/Shared/Project-Debug.xcconfig deleted file mode 100644 index ae03656ce4..0000000000 --- a/Configuration/Shared/Project-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Workspace-Debug.xcconfig" diff --git a/Configuration/Shared/Project-Release.xcconfig b/Configuration/Shared/Project-Release.xcconfig deleted file mode 100644 index b266f89403..0000000000 --- a/Configuration/Shared/Project-Release.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -#include "Workspace-Release.xcconfig" - -COPY_PHASE_STRIP = YES -DEPLOYMENT_POSTPROCESSING = YES -STRIP_INSTALLED_PRODUCT = YES diff --git a/Configuration/Shared/Project-Version.xcconfig b/Configuration/Shared/Project-Version.xcconfig deleted file mode 100644 index beec2bce5e..0000000000 --- a/Configuration/Shared/Project-Version.xcconfig +++ /dev/null @@ -1 +0,0 @@ -CURRENT_PROJECT_VERSION = 0.53.0 diff --git a/Configuration/Shared/Workspace-Analysis.xcconfig b/Configuration/Shared/Workspace-Analysis.xcconfig deleted file mode 100644 index f75a82686f..0000000000 --- a/Configuration/Shared/Workspace-Analysis.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -CLANG_ANALYZER_NONNULL = YES -CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE diff --git a/Configuration/Shared/Workspace-Code-Generation.xcconfig b/Configuration/Shared/Workspace-Code-Generation.xcconfig deleted file mode 100644 index 6ecec38c92..0000000000 --- a/Configuration/Shared/Workspace-Code-Generation.xcconfig +++ /dev/null @@ -1,6 +0,0 @@ -// Code generation -GCC_STRICT_ALIASING = YES -GCC_DYNAMIC_NO_PIC = NO -GCC_SYMBOLS_PRIVATE_EXTERN = NO -GCC_THREADSAFE_STATICS = YES -GCC_NO_COMMON_BLOCKS = YES diff --git a/Configuration/Shared/Workspace-Debug.xcconfig b/Configuration/Shared/Workspace-Debug.xcconfig deleted file mode 100644 index 5ee2a21b77..0000000000 --- a/Configuration/Shared/Workspace-Debug.xcconfig +++ /dev/null @@ -1,23 +0,0 @@ -#include "Workspace-Shared.xcconfig" - -// Architectures -ONLY_ACTIVE_ARCH = YES - -// Build Options -ENABLE_TESTABILITY = YES -VALIDATE_PRODUCT = NO - -// Deployment -COPY_PHASE_STRIP = NO - -// Code Generation -GCC_OPTIMIZATION_LEVEL = 0 -SWIFT_OPTIMIZATION_LEVEL = -Onone -LLVM_LTO = NO -SWIFT_COMPILATION_MODE = singlefile - -// Build Options -DEBUG_INFORMATION_FORMAT = dwarf - -ENABLE_NS_ASSERTIONS = YES -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES diff --git a/Configuration/Shared/Workspace-Deployment-Targets.xcconfig b/Configuration/Shared/Workspace-Deployment-Targets.xcconfig deleted file mode 100644 index 8892174ab9..0000000000 --- a/Configuration/Shared/Workspace-Deployment-Targets.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Base Deployment Targets -IPHONEOS_DEPLOYMENT_TARGET = 12.0 -MACOSX_DEPLOYMENT_TARGET = 10.14 -TVOS_DEPLOYMENT_TARGET = 12.0 -WATCHOS_DEPLOYMENT_TARGET = 5.0 - -WARNING_CFLAGS[sdk=iphone*] = $(inherited) -DAPI_TO_BE_DEPRECATED=12_0 -WARNING_CFLAGS[sdk=macosx*] = $(inherited) -DAPI_TO_BE_DEPRECATED=10_14 -WARNING_CFLAGS[sdk=tvos*] = $(inherited) -DAPI_TO_BE_DEPRECATED=12_0 -WARNING_CFLAGS[sdk=watchos*] = $(inherited) -DAPI_TO_BE_DEPRECATED=5_0 - -// macOS-specific default settings -COMBINE_HIDPI_IMAGES[sdk=macosx*] = YES - diff --git a/Configuration/Shared/Workspace-Language.xcconfig b/Configuration/Shared/Workspace-Language.xcconfig deleted file mode 100644 index 523640345f..0000000000 --- a/Configuration/Shared/Workspace-Language.xcconfig +++ /dev/null @@ -1,25 +0,0 @@ -// Language -GCC_C_LANGUAGE_STANDARD = gnu99 -GCC_ENABLE_OBJC_EXCEPTIONS = YES -GCC_ENABLE_ASM_KEYWORD = YES -CLANG_LINK_OBJC_RUNTIME = YES -CLANG_ENABLE_OBJC_WEAK = YES - -// ARC enabled -CLANG_ENABLE_OBJC_ARC = YES - -// Enable @import modules support -CLANG_ENABLE_MODULES = YES -CLANG_MODULES_AUTOLINK = YES - -CLANG_CXX_LANGUAGE_STANDARD = gnu++11 -CLANG_CXX_LIBRARY = libc++ -CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES - -ENABLE_STRICT_OBJC_MSGSEND = YES - -// Swift -SWIFT_VERSION = 5.0 -SWIFT_PRECOMPILE_BRIDGING_HEADER = YES -SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(CONFIGURATION:upper) -SWIFT_SWIFT3_OBJC_INFERENCE = Off diff --git a/Configuration/Shared/Workspace-Linking.xcconfig b/Configuration/Shared/Workspace-Linking.xcconfig deleted file mode 100644 index 14d45fba1e..0000000000 --- a/Configuration/Shared/Workspace-Linking.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -// Dynamic linking uses different default copy paths. Reset LD_RUNPATH_SEARCH_PATHS for each SDK. -LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = '@executable_path/../Frameworks' '@loader_path/../Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=watch*] = '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=appletv*] = '@executable_path/Frameworks' '@loader_path/Frameworks' diff --git a/Configuration/Shared/Workspace-Packaging.xcconfig b/Configuration/Shared/Workspace-Packaging.xcconfig deleted file mode 100644 index f8e5532d2a..0000000000 --- a/Configuration/Shared/Workspace-Packaging.xcconfig +++ /dev/null @@ -1,4 +0,0 @@ -PRODUCT_NAME = $(TARGET_NAME) -PRODUCT_BUNDLE_IDENTIFIER = com.apollographql.$(TARGET_NAME:rfc1034identifier).$(PLATFORM_NAME) - -ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO diff --git a/Configuration/Shared/Workspace-Release.xcconfig b/Configuration/Shared/Workspace-Release.xcconfig deleted file mode 100644 index 2b2ebb3b7a..0000000000 --- a/Configuration/Shared/Workspace-Release.xcconfig +++ /dev/null @@ -1,22 +0,0 @@ -#include "Workspace-Shared.xcconfig" - -// Architectures -ONLY_ACTIVE_ARCH = NO - -// Build Options -VALIDATE_PRODUCT = YES - -// Deployment Options -COPY_PHASE_STRIP = YES - -// Code Generation -GCC_OPTIMIZATION_LEVEL = s -SWIFT_OPTIMIZATION_LEVEL = -O -SWIFT_COMPILATION_MODE = wholemodule -LLVM_LTO = YES - -// Build Options -DEBUG_INFORMATION_FORMAT = dwarf-with-dsym - -ENABLE_NS_ASSERTIONS = NO -CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES diff --git a/Configuration/Shared/Workspace-Search-Paths.xcconfig b/Configuration/Shared/Workspace-Search-Paths.xcconfig deleted file mode 100644 index c6078a25d1..0000000000 --- a/Configuration/Shared/Workspace-Search-Paths.xcconfig +++ /dev/null @@ -1,4 +0,0 @@ -// Search Paths -ALWAYS_SEARCH_USER_PATHS = NO -HEADER_SEARCH_PATHS = $(inherited) $(CONFIGURATION_BUILD_DIR) -FRAMEWORK_SEARCH_PATHS = $(inherited) $(CONFIGURATION_BUILD_DIR) diff --git a/Configuration/Shared/Workspace-Shared.xcconfig b/Configuration/Shared/Workspace-Shared.xcconfig deleted file mode 100644 index 171b81fdf9..0000000000 --- a/Configuration/Shared/Workspace-Shared.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -#include "Workspace-Analysis.xcconfig" -#include "Workspace-Code-Generation.xcconfig" -#include "Workspace-Deployment-Targets.xcconfig" -#include "Workspace-Language.xcconfig" -#include "Workspace-Linking.xcconfig" -#include "Workspace-Packaging.xcconfig" -#include "Workspace-Search-Paths.xcconfig" -#include "Workspace-Warnings.xcconfig" -#include "Project-Version.xcconfig" - -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(CONFIGURATION:upper)=1 -SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(CONFIGURATION:upper) -VERSIONING_SYSTEM = apple-generic diff --git a/Configuration/Shared/Workspace-Target-Application.xcconfig b/Configuration/Shared/Workspace-Target-Application.xcconfig deleted file mode 100644 index 688b7be118..0000000000 --- a/Configuration/Shared/Workspace-Target-Application.xcconfig +++ /dev/null @@ -1 +0,0 @@ -WRAPPER_EXTENSION = app diff --git a/Configuration/Shared/Workspace-Target-Codegen.xcconfig b/Configuration/Shared/Workspace-Target-Codegen.xcconfig deleted file mode 100644 index e3dcad0c3c..0000000000 --- a/Configuration/Shared/Workspace-Target-Codegen.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -SDKROOT = macosx -SUPPORTED_PLATFORMS = macosx - diff --git a/Configuration/Shared/Workspace-Target-Framework.xcconfig b/Configuration/Shared/Workspace-Target-Framework.xcconfig deleted file mode 100644 index f02138d8d1..0000000000 --- a/Configuration/Shared/Workspace-Target-Framework.xcconfig +++ /dev/null @@ -1,15 +0,0 @@ -WRAPPER_EXTENSION = framework - -INSTALL_PATH = @rpath -LD_DYLIB_INSTALL_NAME = @rpath/$(PRODUCT_NAME).$(WRAPPER_EXTENSION)/$(PRODUCT_NAME) -SKIP_INSTALL = YES - -DYLIB_COMPATIBILITY_VERSION = 1 -DYLIB_CURRENT_VERSION = 1 -DYLIB_INSTALL_NAME_BASE = @rpath - -FRAMEWORK_VERSION[sdk=macosx*] = A - -APPLICATION_EXTENSION_API_ONLY = YES - -DEFINES_MODULE = YES diff --git a/Configuration/Shared/Workspace-Target-Test.xcconfig b/Configuration/Shared/Workspace-Target-Test.xcconfig deleted file mode 100644 index 4c7a189f05..0000000000 --- a/Configuration/Shared/Workspace-Target-Test.xcconfig +++ /dev/null @@ -1,8 +0,0 @@ -// Packaging -WRAPPER_EXTENSION = xctest - -// Disable some known troublesome warnings for the test target, as -Weverything without these exceptions causes errors when importing XCTest -WARNING_CFLAGS = $(inherited) -Wno-documentation-unknown-command -Wno-incomplete-module -Wno-disabled-macro-expansion -Wno-shadow - -/// Test Target Deployment Target -MACOSX_DEPLOYMENT_TARGET = 10.15 diff --git a/Configuration/Shared/Workspace-Target-TestSupport.xcconfig b/Configuration/Shared/Workspace-Target-TestSupport.xcconfig deleted file mode 100644 index 5b94d087b9..0000000000 --- a/Configuration/Shared/Workspace-Target-TestSupport.xcconfig +++ /dev/null @@ -1,9 +0,0 @@ -#include "../Shared/Workspace-Universal-Framework.xcconfig" - -APPLICATION_EXTENSION_API_ONLY = NO -LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*] = $(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift-$(SWIFT_VERSION)/$(PLATFORM_NAME) -FRAMEWORK_SEARCH_PATHS = $(DEVELOPER_FRAMEWORKS_DIR) $(PLATFORM_DIR)/Developer/Library/Frameworks -OTHER_LDFLAGS = -weak_framework XCTest - -/// Test Target Deployment Target -MACOSX_DEPLOYMENT_TARGET = 10.15 diff --git a/Configuration/Shared/Workspace-Universal-Framework.xcconfig b/Configuration/Shared/Workspace-Universal-Framework.xcconfig deleted file mode 100644 index 22768cede4..0000000000 --- a/Configuration/Shared/Workspace-Universal-Framework.xcconfig +++ /dev/null @@ -1,21 +0,0 @@ -#include "Workspace-Universal-Target.xcconfig" -#include "Workspace-Target-Framework.xcconfig" - -SUPPORTED_PLATFORMS = iphoneos iphonesimulator appletvsimulator appletvos watchsimulator watchos macosx - -// iOS-specific default settings -SDKROOT[sdk=iphone*] = iphoneos -TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2 - -// TV-specific default settings -SDKROOT[sdk=appletv*] = appletvos -TARGETED_DEVICE_FAMILY[sdk=appletv*] = 3 - -// Watch-specific default settings -SDKROOT[sdk=watch*] = watchos -TARGETED_DEVICE_FAMILY[sdk=watch*] = 4 - -// macOS-specific default settings -SDKROOT[sdk=macosx*] = macosx -SUPPORTS_MACCATALYST = YES - diff --git a/Configuration/Shared/Workspace-Universal-Target.xcconfig b/Configuration/Shared/Workspace-Universal-Target.xcconfig deleted file mode 100644 index c1870b6d68..0000000000 --- a/Configuration/Shared/Workspace-Universal-Target.xcconfig +++ /dev/null @@ -1,3 +0,0 @@ -#include "Workspace-Deployment-Targets.xcconfig" - -SUPPORTED_PLATFORMS = macosx iphonesimulator iphoneos watchos watchsimulator appletvos appletvsimulator diff --git a/Configuration/Shared/Workspace-Universal-Test.xcconfig b/Configuration/Shared/Workspace-Universal-Test.xcconfig deleted file mode 100644 index 0ac69c2fa3..0000000000 --- a/Configuration/Shared/Workspace-Universal-Test.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "Workspace-Universal-Target.xcconfig" -#include "Workspace-Target-Test.xcconfig" diff --git a/Configuration/Shared/Workspace-Warnings.xcconfig b/Configuration/Shared/Workspace-Warnings.xcconfig deleted file mode 100644 index 75f73f2245..0000000000 --- a/Configuration/Shared/Workspace-Warnings.xcconfig +++ /dev/null @@ -1,27 +0,0 @@ -CLANG_ANALYZER_NONNULL = YES -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES -CLANG_WARN_BOOL_CONVERSION = YES -CLANG_WARN_COMMA = YES -CLANG_WARN_CONSTANT_CONVERSION = YES -CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES -CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR -CLANG_WARN_DOCUMENTATION_COMMENTS = YES -CLANG_WARN_EMPTY_BODY = YES -CLANG_WARN_ENUM_CONVERSION = YES -CLANG_WARN_INFINITE_RECURSION = YES -CLANG_WARN_INT_CONVERSION = YES -CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -CLANG_WARN_OBJC_LITERAL_CONVERSION = YES -CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR -CLANG_WARN_RANGE_LOOP_ANALYSIS = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_SUSPICIOUS_MOVE = YES -CLANG_WARN_UNREACHABLE_CODE = YES -GCC_WARN_64_TO_32_BIT_CONVERSION = YES -GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR -GCC_WARN_UNDECLARED_SELECTOR = YES -GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE -GCC_WARN_UNUSED_FUNCTION = YES -GCC_WARN_UNUSED_VARIABLE = YES diff --git a/Design/3093-graphql-defer.md b/Design/3093-graphql-defer.md new file mode 100644 index 0000000000..44fcc70a25 --- /dev/null +++ b/Design/3093-graphql-defer.md @@ -0,0 +1,471 @@ +* Feature Name: GraphQL `@defer` +* Start Date: 2023-06-26 +* RFC PR: [3093](https://github.com/apollographql/apollo-ios/pull/3093) + +# Summary + +The specification for `@defer`/`@stream` is slowly making it's way through the GraphQL Foundation approval process and once formally merged into the GraphQL specification Apollo iOS will need to support it. However, Apollo already has a public implementation of `@defer` in the other OSS offerings, namely Apollo Server, Apollo Client, and Apollo Kotlin. The goal of this project is to implement support for `@defer` that matches the other Apollo OSS clients which, based on the commit history, we believe is [the specification as dated at `2022-08-24`](https://github.com/graphql/graphql-spec/tree/48cf7263a71a683fab03d45d309fd42d8d9a6659/spec). This project will not include support for the `@stream` directive. + +Based on the progress of `@defer`/`@stream` through the approval process there may be some differences in the final specification vs. what is currently implemented in Apollo's OSS. This project does not attempt to preemptively anticipate those changes nor comply with the potentially merged specification. Any client affecting-changes in the merged specification will be implemented into Apollo iOS. + +# Proposed Changes + +## Update graphql-js dependency + +Apollo iOS uses [graphql-js](https://github.com/graphql/graphql-js) for validation of the GraphQL schema and operation documents as the first step in the code generation workflow. The version of this [dependency](https://github.com/apollographql/apollo-ios/blob/spike/defer/Sources/ApolloCodegenLib/Frontend/JavaScript/package.json#L16) is fixed at [`16.3.0-canary.pr.3510.5099f4491dc2a35a3e4a0270a55e2a228c15f13b`](https://www.npmjs.com/package/graphql/v/16.3.0-canary.pr.3510.5099f4491dc2a35a3e4a0270a55e2a228c15f13b?activeTab=versions). This is a version of graphql-js that supports the experimental [Client Controlled Nullability](https://github.com/graphql/graphql-wg/blob/main/rfcs/ClientControlledNullability.md) feature but does not support the `@defer` directive. + +The latest `16.x` release of graphql-js with support for the `@defer` directive is [`16.1.0-experimental-stream-defer.6`](https://www.npmjs.com/package/graphql/v/16.1.0-experimental-stream-defer.6) but it looks like the 'experimental' named releases for `@defer` have been discontinued and the recommendation is to use [`17.0.0-alpha.2`](https://www.npmjs.com/package/graphql/v/17.0.0-alpha.2). This is further validated by the fact that [`16.7.0` does not](https://github.com/graphql/graphql-js/blob/v16.7.0/src/type/directives.ts#L167) include the `@defer` directive whereas [`17.0.0-alpha.2` does](https://github.com/graphql/graphql-js/blob/v17.0.0-alpha.2/src/type/directives.ts#L159). + +**Preferred solution (see the end of this document for discarded solutions)** + +We will take a staggered approach where we adopt `17.0.0-alpha.2`, or the latest 17.0.0 alpha release, limiting the changes to our frontend javascript only and at a later stage bring the CCN changes from [PR `#3510`](https://github.com/graphql/graphql-js/pull/3510) to the `17.x` release path and reintroduce support for CCN to Apollo iOS. This would also require the experiemental CCN feature to be removed, with no committment to when it would be reintroduced. + +_The work to port the CCN PRs to `17.0.0-alpha.2` is being done externally as part of the renewed interest in the CCN proposal._ + +## Rename `PossiblyDeferred` types/functions + +Adding support for `@defer` brings new meaning of the word 'deferred' to the codebase. There is an enum type named [`PossiblyDeferred`](https://github.com/apollographql/apollo-ios/blob/spike/defer/Sources/Apollo/PossiblyDeferred.swift#L47) which would cause confusion when trying to understand it’s intent. This type and its related functions should be renamed to disambiguate it from the incoming `@defer` related types and functions. + +`PossiblyDeferred` is an internal type so this should have no adverse effect on users’ code. + +## Generated models + +Generated models will need to adapt with the introduction of `@defer` statements in operations. Ideally there is easy-to-read annotation indicating something is deferred by simply reading the generated model code but more importantly it must be easy when using the generated models in code to detect whether something is able to be deferred and it's current state when receiving a response. + +**Preferred solution (see the end of this document for discarded solutions)** + +These are the key changes: + +**All deferred fragments including inline fragments are treated as isolated fragments** + +This is necessary because they are delivered separately in the incremental response, therefore they cannot be merged together. This means that inline fragments, even on the same typecase with matching arguments, will be treated as separate fragments in the same way that named fragments are. They will be placed into the `Fragments` container along with an accessor. + +This is still undecided but we may require that _all_ deferred fragments be named with the `label` argument. This provides us with a naming paradigm and aids us in identifying the fulfilled fragments in the incremental responses. At a minimum any fragments on the same typecase will need to be uniquely identifable with at least one having an associated label. + +**Deferred fragment accessors are stored properties** + +This is different to data fields which are computed properties that use a subscript on the underlying data dictionary to return the value. We decided to do this so that we can use a property wrapper, which are not available for computed properties. The property wrapper is an easy-to-read annotation on the accessor to aid in identifying a deferred fragment from other named fragments in the fragment container. + +It's worth noting though that the fragment accessors are not true stored properties but rather a pseudo stored-property because the property wrapper is still initialized with a data dictionary that holds the data. This is also made possible by the underlying data dictionary having copy-on-write semantics. + +**`@Deferred` property wrapper** + +Aside from being a conveinent annotation the property wrapper also unlocks both deferred value and state. The wrapped value is used to access the returned value and the projected value is used to determine the state of the fragment in the response, i.e.: pending, fulfilled or a not-executed. + +The not-executed case is used to indicate when a merged deferred fragment could never be fulfilled, such as when the response type is different from the deferred fragment typecase. + +Here is a snippet of a generated model to illustrate the above three points: +```swift +public struct Fragments: FragmentContainer { + public let __data: DataDict + public init(_dataDict: DataDict) { + __data = _dataDict + _root = Deferred(_dataDict: _dataDict) + } + + @Deferred public var deferredFragmentFoo: DeferredFragmentFoo? +} + +public struct DeferredFragmentFoo: AnimalKingdomAPI.InlineFragment, ApolloAPI.Deferrable { +} +``` + +Below is the expected property wrapper: +```swift +public protocol Deferrable: SelectionSet { } + +@propertyWrapper +public struct Deferred { + public enum State { // the naming of these cases is not final + case pending + case notExecuted + case fulfilled(Fragment) + } + + public init(_dataDict: DataDict) { + __data = _dataDict + } + + public var state: State { + let fragment = ObjectIdentifier(Fragment.self) + if __data._fulfilledFragments.contains(fragment) { + return .fulfilled(Fragment.init(_dataDict: __data)) + } + else if __data._deferredFragments.contains(fragment) { + return .pending + } else { + return .notExecuted + } + } + + private let __data: DataDict + public var projectedValue: State { state } + public var wrappedValue: Fragment? { + guard case let .fulfilled(value) = state else { + return nil + } + return value + } +} +``` + +`DataDict`, the underlying data dictionary to data fields will now need to keep track of deferred fragments in a new property, as it does for fulfilled fragments: +```swift +public struct DataDict: Hashable { + // initializer and other properties not shown + + @inlinable public var _deferredFragments: Set { + _storage.deferredFragments + } + + // functions not shown +} +``` + +**A new `deferred(if:type:label:)` case in `Selection`** + +This is necessary for the field selection collector to be able to handle both inline and named fragments the same, which is different from the separate case logic that exists for them today. + +Here is a snippet of a generated model to illustrate the selection: +```swift +public static var __selections: [ApolloAPI.Selection] { [ + .deferred(if: "a", DeferredFragmentFoo.self, label: "deferredFragmentFoo") +] } +``` + +**Field merging** + +Field merging is a feature in Apollo iOS where fields from fragments that have the same `__parentType` as the enclosing `SelectionSet` are automatically merged into the enclosing `SelectionSet`. This makes it easier to consume fragment fields instead of having to access the fragment first. + +Deferred fragment fields will **not** be merged into the enclosing selection set. Merging in the fields of a deferred fragment would require the field types to become optional or use another wrapper-type solution where the field value and state can be represented. We decided it would be better to treat deferred fragments as an isolated selection set with clearer sementics on the collective state and values. + +**Selection set initializers** + +In the preview release of `@defer`, operations with deferred fragments will **not** be able to have generated selection set initializers. This is due to the complexities of field merging which is dependent on work being done by other members of the team. Once we can support this the fields will be optional properties on the initializer and fragment fulfillment will be determined at access time, in a lightweight version of the GraphQL executor, to determine if all deferred fragment field values were provided. + +## Networking + +### Request header + +If an operation can support an incremental delivery response it must add an `Accept` header to the HTTP request specifying the protocol version that can be parsed. An [example](https://github.com/apollographql/apollo-ios/blob/spike/defer/Sources/Apollo/RequestChainNetworkTransport.swift#L115) is HTTP subscription requests that include the `subscriptionSpec=1.0` specification. `@defer` would introduce another operation feature that would request an incremental delivery response. + +This should not be sent with all requests though so operations will need to be identifiable as having deferred fragments to signal inclusion of the request header. + +```swift +// Sample code for RequestChainNetworkTransport +open func constructRequest( + for operation: Operation, + cachePolicy: CachePolicy, + contextIdentifier: UUID? = nil +) -> HTTPRequest { + let request = ... // build request + + if Operation.hasDeferredFragments { + request.addHeader( + name: "Accept", + value: "multipart/mixed;boundary=\"graphql\";deferSpec=20220824,application/json" + ) + } + + return request +} + +// Sample of new property on GraphQLOperation +public protocol GraphQLOperation: AnyObject, Hashable { + // other properties not shown + + static var hasDeferredFragments: Bool { get } // computed for each operation during codegen +} +``` + +### Response parsing + +Apollo iOS already has support for parsing incremental delivery responses. That provides a great foundation to build on however there are some changes needed. + +#### Multipart parsing protocol + +The current `MultipartResponseParsingInterceptor` implementation is specific to the `subscriptionSpec` version `1.0` specification. Adopting a protocol with implementations for each of the supported specifications will enable us to support any number of incremental delivery specifications in the future. + +These would be registered with the `MultipartResponseParsingInterceptor` each with a unique specification string, to be used as a lookup key. When a response is received the specification string is extracted from the response `content-type` header, and the correct specification parser can be used to parse the response data. + +```swift +// Sample code in MultipartResponseParsingInterceptor +public struct MultipartResponseParsingInterceptor: ApolloInterceptor { + private static let responseParsers: [String: MultipartResponseSpecificationParser.Type] = [ + MultipartResponseSubscriptionParser.protocolSpec: MultipartResponseSubscriptionParser.self, + MultipartResponseDeferParser.protocolSpec: MultipartResponseDeferParser.self, + ] + + public func interceptAsync( + chain: RequestChain, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation { + // response validators not shown + + guard + let multipartBoundary = response.httpResponse.multipartBoundary, + let protocolSpec = response.httpResponse.multipartProtocolSpec, + let protocolParser = Self.responseParsers[protocolSpec], + let dataString = String(data: response.rawData, encoding: .utf8) + else { + // call request chain error handler + + return + } + + let dataHandler: ((Data) -> Void) = { data in + // proceed ahead on the request chain + } + + let errorHandler: (() -> Void) = { + // call request chain error handler + } + + for chunk in dataString.components(separatedBy: "--\(boundary)") { + if chunk.isEmpty || chunk.isBoundaryMarker { continue } + + parser.parse(chunk: chunk, dataHandler: dataHandler, errorHandler: errorHandler) + } + } +} + +// Sample protocol for multipart specification parsing +protocol MultipartResponseSpecificationParser { + static var protocolSpec: String { get } + + static func parse( + chunk: String, + dataHandler: ((Data) -> Void), + errorHandler: ((Error) -> Void) + ) +} + +// Sample implementations of multipart specification parsers + +struct MultipartResponseSubscriptionParser: MultipartResponseSpecificationParser { + static let protocolSpec: String = "subscriptionSpec=1.0" + + static func parse( + chunk: String, + dataHandler: ((Data) -> Void), + errorHandler: ((Error) -> Void) + ) { + // parsing code currently in MultipartResponseParsingInterceptor + } +} + +struct MultipartResponseDeferParser: MultipartResponseSpecificationParser { + static let protocolSpec: String = "deferSpec=20220824" + + static func parse( + chunk: String, + dataHandler: ((Data) -> Void), + errorHandler: ((Error) -> Void) + ) { + // new code to parse the defer specification + } +} +``` + +#### Response data + +The initial response data and data received in each incremental response will need to be retained and combined so that each incremental response can insert the latest received incremental response data at the correct path and return an up-to-date response to the request callback. + +The data being retained and combined will be passed through the GraphQL executor on each response, initial and incremental. + +### Completion handler + +`GraphQLResult` should be modified to provide query completion blocks with a high-level abstraction of whether the request has been fulfilled or is still in progress. This prevents clients from having to dig into the deferred fragments to identify the state of the overall request. + +**Preferred solution (see the end of this document for discarded solutions)** + +Introduce a new property on the `GraphQLResult` type that can be used to express the state of the request. + +```swift +// New Response type and property +public struct GraphQLResult { + // other properties and types not shown + + public enum Response { + case partial + case complete + } + + public let response: Response +} + +// Sample usage in an app completion block +client.fetch(query: ExampleQuery()) { result in + switch (result) { + case let .success(data): + switch (data.response) { + case .complete: + case .partial: + } + case let .failure(error): + } +} +``` + +## GraphQL execution + +The executor currently executes on an entire operation selection set. It will need to be adapted to be able to execute on a partial response when deferred fragments have not been received. Each response will be passed to the GraphQL executor. + +There is an oustanding question about whether the Apollo Router has implemented early execution of deferred fragments, potentially returning them in the initial response. If it does then that could have an outsided impact on the changes to the executor. This problem does appear to have been addressed in GraphQL spec edits after `2022-08-24`. + +## Caching + +Similarly to GraphQL execution the cache write interceptor is designed to work holistically on the operation and write cache records for a single response. This approach still works for HTTP-based subscriptions because each incremental response contains a selection set for the entire operation. + +This approach is not going to work for the incremental responses of `@defer` though and partial responses cannot be written to the cache for the operation. Instead all deferred responses will need to be fulfilled before the record is written to the cache. + +```swift +// Only write cache records for complete responses +public struct CacheWriteInterceptor: ApolloInterceptor { + // other code not shown + + public func interceptAsync( + chain: RequestChain, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) { + // response validators not shown + + guard + let createdResponse = response, + let parsedResponse = createdResponse.parsedResponse, + parsedResponse.source == .server(.complete) + else { + // a partial response must have been received and should not be written to the cache + return + } + + // cache write code not shown + } +} +``` + +There is a bunch of complexity in writing partial records to the cache such as: query watchers without deferred fragments; how would we handle failed requests; race conditions to fulfil deferred data; amongst others. These problems need careful, thoughtful solutions and this project will not include them in the scope for initial implementation. + +# Discarded solutions + +## Update graphql-js dependency +1. Add support for Client Controlled Nullability to `17.0.0-alpha.2`, or the latest 17.0.0 alpha release, and publish that to NPM. The level of effort for this is unknown but it would allow us to maintain support for CCN. +2. Use `17.0.0-alpha.2`, or the latest 17.0.0 alpha release, as-is and remove the experimental Client Controlled Nullability feature. We do not know how many users rely on the CCN functionality so this may be a controversial decision. This path doesn’t necessarily imply an easier dependency update because there will be changes needed to our frontend javascript to adapt to the changes in graphql-js. + +## Generated models +1. Property wrappers - I explored Swift's property wrappers but they suffer from the limitation of not being able to be applied to a computed property. All GraphQL fields in the generated models are computed properties because they simply route access to the value in the underlying data dictionary storage. It would be nice to be able to simply annotate fragments and fields with something like `@Deferred` but unfortunately that is not possible. +2. Optional types - this solution would change the deferred property type to an optional version of that type. This may not seem necessary when considering that only fragments can be marked as deferred but it would be required to cater for the way that Apollo iOS does field merging in the generated model fragments. Field merging is non-optional at the moment but there is an issue ([#2560](https://github.com/apollographql/apollo-ios/issues/2560)) that would make this a configuration option. This solution hides detail though because you wouldn't be able to tell whether the field value is `nil` because the response data hasn't been received yet (i.e.: deferred) or whether the data was returned and it was explicitly `null`. It also gets more complicated when a field type is already optional; would that result in a Swift double-optional type? As we learnt with the legacy implementation of GraphQL nullability, double-optionals are difficult to interpret and easily lead to mistakes. +3. `Enum` wrapper - an idea that was suggested by [`@Iron-Ham`](https://github.com/apollographql/apollo-ios/issues/2395#issuecomment-1433628466) is to wrap the type in a Swift enum that can expose the deferred state as well as the underlying value once it has been received. This is an improvement to option 2 where the state of the deferred value can be determined. + +```swift +// Sample enum to wrap deferred properties +enum DeferredValue { + case loading + case result(Result) +} + +// Sample model with a deferred property +public struct ModelSelectionSet: GraphAPI.SelectionSet { + // other properties not shown + + public var name: DeferredValue { __data["name"] } +} +``` + +4. Optional fragments (disabling field merging) - optional types are only needed when fragment fields are merged into entity selection sets. If field merging were disabled automatically for deferred fragments then the solution is simplified and we only need to alter the deferred fragments to be optional. Consuming the result data is intuitive too where a `nil` fragment value would indicate that the fragment data has not yet been received (i.e.: deferred) and when the complete response is received the fragment value is populated and the result sent to the client. This seems a more elegant and ergonimic way to indicate the status of deferred data but complicates the understanding of field merging. + +```swift +// Sample usage in a generated model +public class ExampleQuery: GraphQLQuery { + // other properties and types not shown + + public struct Data: ExampleSchema.SelectionSet { + public static var __selections: [ApolloAPI.Selection] { [ + .fragment(EntityFragment?.self, deferred: true) + ] } + } +} + +// Sample usage in an app completion block +client.fetch(query: ExampleQuery()) { result in + switch (result) { + case let .success(data): + client.fetch(query: ExampleQuery()) { result in + switch (result) { + case let .success(data): + guard let fragment = data.data?.item.fragments.entityFragment else { + // partial result + } + + // complete result + case let .failure(error): + print("Query Failure! \(error)") + } + } + case let .failure(error): + } +} + +``` + +Regardless of the fragment/field solution chosen all deferred fragment definitions in generated models `__selections` will get an additional property to indicate they are deferred. This helps to understand the models when reading them as well as being used by internal code. + +```swift +// Updated Selection enum +public enum Selection { + // other cases not shown + case fragment(any Fragment.Type, deferred: Bool) + case inlineFragment(any InlineFragment.Type, deferred: Bool) + + // other properties and types not shown +} + +// Sample usage in a generated model +public class ExampleQuery: GraphQLQuery { + // other properties and types not shown + + public struct Data: ExampleSchema.SelectionSet { + public static var __selections: [ApolloAPI.Selection] { [ + .fragment(EntityFragment.self, deferred: true), + .inlineFragment(AsEntity.self, deferred: true), + ] } + } +} +``` +## Networking + +1. Another way which may be a bit more intuitive is to make the `server` case on `Source` have an associated value since `cache` sources will always be complete. The cache could return partial responses for deferred operations but for the initial implementation we will probably only write the cache record once all deferred fragments have been received. This solution becomes invalid though once the cache can return partial responses, with that in mind maybe option 1 is better. + +```swift +// Updated server case on Source with associated value of Response type +public struct GraphQLResult { + // other properties and types not shown + + public enum Response { + case partial + case complete + } + + public enum Source: Hashable { + case cache + case server(_ response: Response) + } +} + +// Sample usage in an app +client.fetch(query: ExampleQuery()) { result in + switch (result) { + case let .success(data): + switch (data.source) { + case .server(.complete): + case .server(.partial): + case .cache: + } + case let .failure(error): + } +} +``` diff --git a/Package.resolved b/Package.resolved index 9811f1b1a0..cb4b75775e 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,16 +1,14 @@ { - "object": { - "pins": [ - { - "package": "SQLite.swift", - "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git", - "state": { - "branch": null, - "revision": "5f5ad81ac0d0a0f3e56e39e646e8423c617df523", - "version": "0.13.2" - } + "pins" : [ + { + "identity" : "sqlite.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/stephencelis/SQLite.swift.git", + "state" : { + "revision" : "7a2e3cd27de56f6d396e84f63beefd0267b55ccb", + "version" : "0.14.1" } - ] - }, - "version": 1 + } + ], + "version" : 2 } diff --git a/Package.swift b/Package.swift index 663e5c2153..12ae353c7d 100644 --- a/Package.swift +++ b/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( - name: "Apollo", + name: "ApolloPGATOUR", platforms: [ .iOS(.v12), .macOS(.v10_14), @@ -12,87 +12,74 @@ let package = Package( .watchOS(.v5) ], products: [ - .library( - name: "Apollo", - targets: ["Apollo"]), - .library( - name: "ApolloAPI", - targets: ["ApolloAPI"]), - .library( - name: "ApolloUtils", - targets: ["ApolloUtils"]), - .library( - name: "Apollo-Dynamic", - type: .dynamic, - targets: ["Apollo"]), - .library( - name: "ApolloCodegenLib", - targets: ["ApolloCodegenLib"]), - .library( - name: "ApolloSQLite", - targets: ["ApolloSQLite"]), - .library( - name: "ApolloWebSocket", - targets: ["ApolloWebSocket"]), + .library(name: "ApolloPGATOUR", targets: ["ApolloPGATOUR"]), + .library(name: "ApolloAPI", targets: ["ApolloAPI"]), + .library(name: "Apollo-Dynamic", type: .dynamic, targets: ["ApolloPGATOUR"]), + .library(name: "ApolloSQLite", targets: ["ApolloSQLite"]), + .library(name: "ApolloWebSocket", targets: ["ApolloWebSocket"]), + .library(name: "ApolloTestSupport", targets: ["ApolloTestSupport"]), + .plugin(name: "InstallCLI", targets: ["Install CLI"]) ], dependencies: [ .package( url: "https://github.com/stephencelis/SQLite.swift.git", - .upToNextMinor(from: "0.13.1")) + .upToNextMajor(from: "0.13.1")), ], targets: [ .target( - name: "Apollo", + name: "ApolloPGATOUR", dependencies: [ - "ApolloAPI", - "ApolloUtils" + "ApolloAPI" ], - exclude: [ - "Info.plist" - ]), + resources: [ + .copy("Resources/PrivacyInfo.xcprivacy") + ] + ), .target( name: "ApolloAPI", dependencies: [], - exclude: [ - "Info.plist", - "CodegenV1" - ]), - .target( - name: "ApolloUtils", - dependencies: [], - exclude: [ - "Info.plist" - ]), - .target( - name: "ApolloCodegenLib", - dependencies: [ - "ApolloUtils", - ], - exclude: [ - "Info.plist", - "Frontend/JavaScript", - ], resources: [ - .copy("Frontend/dist/ApolloCodegenFrontend.bundle.js"), - .copy("Frontend/dist/ApolloCodegenFrontend.bundle.js.map") - ]), + .copy("Resources/PrivacyInfo.xcprivacy") + ] + ), .target( name: "ApolloSQLite", dependencies: [ - "Apollo", + "ApolloPGATOUR", .product(name: "SQLite", package: "SQLite.swift"), ], - exclude: [ - "Info.plist" - ]), + resources: [ + .copy("Resources/PrivacyInfo.xcprivacy") + ] + ), .target( name: "ApolloWebSocket", dependencies: [ - "Apollo", - "ApolloUtils" + "ApolloPGATOUR" ], - exclude: [ - "Info.plist" - ]) + resources: [ + .copy("Resources/PrivacyInfo.xcprivacy") + ] + ), + .target( + name: "ApolloTestSupport", + dependencies: [ + "ApolloPGATOUR", + "ApolloAPI" + ] + ), + .plugin( + name: "Install CLI", + capability: .command( + intent: .custom( + verb: "apollo-cli-install", + description: "Installs the Apollo iOS Command line interface."), + permissions: [ + .writeToPackageDirectory(reason: "Downloads and unzips the CLI executable into your project directory."), + .allowNetworkConnections(scope: .all(ports: []), reason: "Downloads the Apollo iOS CLI executable from the GitHub Release.") + ]), + dependencies: [], + path: "Plugins/InstallCLI" + ) ] ) diff --git a/Plugins/InstallCLI/InstallCLIPluginCommand.swift b/Plugins/InstallCLI/InstallCLIPluginCommand.swift new file mode 100644 index 0000000000..d8b968f108 --- /dev/null +++ b/Plugins/InstallCLI/InstallCLIPluginCommand.swift @@ -0,0 +1,41 @@ +import Foundation +import PackagePlugin + +@main +struct InstallCLIPluginCommand: CommandPlugin { + + func performCommand(context: PackagePlugin.PluginContext, arguments: [String]) async throws { + let dependencies = context.package.dependencies + try dependencies.forEach { dep in + if dep.package.displayName == "Apollo" { + let process = Process() + let path = try context.tool(named: "sh").path + process.executableURL = URL(fileURLWithPath: path.string) + process.arguments = ["\(dep.package.directory)/scripts/download-cli.sh", context.package.directory.string] + try process.run() + process.waitUntilExit() + } + } + } + +} + +#if canImport(XcodeProjectPlugin) +import XcodeProjectPlugin + +extension InstallCLIPluginCommand: XcodeCommandPlugin { + + /// 👇 This entry point is called when operating on an Xcode project. + func performCommand(context: XcodePluginContext, arguments: [String]) throws { + print("Installing Apollo CLI Plugin to Xcode project \(context.xcodeProject.displayName)") + let apolloPath = "\(context.pluginWorkDirectory)/../../checkouts/apollo-ios" + let process = Process() + let path = try context.tool(named: "sh").path + process.executableURL = URL(fileURLWithPath: path.string) + process.arguments = ["\(apolloPath)/scripts/download-cli.sh", context.xcodeProject.directory.string] + try process.run() + process.waitUntilExit() + } + +} +#endif diff --git a/README.md b/README.md index 3aba0468d4..328e3c80bc 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@

- - CircleCI build status + + GitHub Action Status MIT license @@ -16,20 +16,21 @@

- Swift 5 supported + Swift 5.7 supported Swift Package Manager compatible - - Carthage compatible - CocoaPods compatible

-### Apollo iOS is a strongly-typed, caching GraphQL client, written in Swift. +| ☑️ Apollo Clients User Survey | +| :----- | +| What do you like best about Apollo iOS? What needs to be improved? Please tell us by taking a [one-minute survey](https://docs.google.com/forms/d/e/1FAIpQLSczNDXfJne3ZUOXjk9Ursm9JYvhTh1_nFTDfdq3XBAFWCzplQ/viewform?usp=pp_url&entry.1170701325=Apollo+iOS&entry.204965213=Readme). Your responses will help us understand Apollo iOS usage and allow us to serve you better. | + +### Apollo iOS is a strongly-typed, caching GraphQL client, written in Swift It allows you to execute queries and mutations against a GraphQL server, and returns results as query-specific Swift types. This means you don’t have to deal with parsing JSON, or passing around dictionaries and making clients cast values to the right type manually. You also don't have to write model types yourself, because these are generated from the GraphQL definitions your UI uses. @@ -41,11 +42,13 @@ This combination of models with value semantics, one way data flow, and automati ## Getting started -If you are new to Apollo iOS there are two ways to get started: -1. The [tutorial](https://www.apollographql.com/docs/ios/tutorial/tutorial-introduction/) which will guide you through building an iOS app using Swift and Apollo iOS. -2. A [Playground](https://github.com/apollographql/apollo-client-swift-playground) covering the concepts of queries, mutations, subscriptions, SQLite caching and custom scalars. +If you are new to Apollo iOS we recommend our [Getting Started](https://www.apollographql.com/docs/ios/get-started) guide. + +There is also [comprehensive documentation](https://www.apollographql.com/docs/ios/) including an [API reference](https://www.apollographql.com/docs/ios/docc/documentation/index). + +### Carthage/XCFramework Support -There is also [comprehensive documentation](https://www.apollographql.com/docs/ios/) including an [API reference](https://www.apollographql.com/docs/ios/api-reference/). +The Apollo iOS repo no longer contains an Xcode project, as a result if you are using Carthage or need to build XCFrameworks for use in your development environment you will want to use the [apollo-ios-xcframework](https://github.com/apollographql/apollo-ios-xcframework) repo we have created that contains an Xcode project generated with Tuist that can be used for this purpose and is tagged to match the releases of Apollo iOS. ## Releases and changelog @@ -57,29 +60,23 @@ The [roadmap](https://github.com/apollographql/apollo-ios/blob/main/ROADMAP.md) ## Contributing -This project is being developed using Xcode 12.5 and Swift 5.4. - -If you open `Apollo.xcodeproj`, you should be able to run the tests of the Apollo, ApolloSQLite, and ApolloWebSocket frameworks on your Mac or an iOS Simulator. - -> **NOTE**: Due to a change in behavior in Xcode 11's git integration, if you check this repo out using Xcode, please close the window Xcode automatically opens using the Swift Package manager structure, and open the `Apollo.xcodeproj` file instead. - -Some of the tests run against [a simple GraphQL server serving the Star Wars example schema](https://github.com/apollographql/starwars-server) (see installation instructions there). - -If you'd like to contribute, please refer to the [Apollo Contributor Guide](https://github.com/apollographql/apollo-ios/blob/main/CONTRIBUTING.md). +If you'd like to contribute, please refer to the [Apollo Contributor Guide](https://github.com/apollographql/apollo-ios-dev/blob/main/CONTRIBUTING.md). ## Maintainers -- [@AnthonyMDev](https://github.com/AnthonyMDev) (Apollo) -- [@calvincestari](https://github.com/calvincestari) (Apollo) +- [@AnthonyMDev](https://github.com/AnthonyMDev) +- [@calvincestari](https://github.com/calvincestari) +- [@bignimbus](https://github.com/bignimbus) +- [@bobafetters](https://github.com/bobafetters) ## Who is Apollo? [Apollo](https://apollographql.com/) builds open-source software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with: -* [Apollo Studio](https://www.apollographql.com/studio/develop/) – A free, end-to-end platform for managing your GraphQL lifecycle. Track your GraphQL schemas in a hosted registry to create a source of truth for everything in your graph. Studio provides an IDE (Apollo Explorer) so you can explore data, collaborate on queries, observe usage, and safely make schema changes. -* [Apollo Federation](https://www.apollographql.com/apollo-federation) – The industry-standard open architecture for building a distributed graph. Use Apollo’s gateway to compose a unified graph from multiple subgraphs, determine a query plan, and route requests across your services. -* [Apollo Client](https://www.apollographql.com/apollo-client/) – The most popular GraphQL client for the web. Apollo also builds and maintains [Apollo iOS](https://github.com/apollographql/apollo-ios) and [Apollo Android](https://github.com/apollographql/apollo-android). -* [Apollo Server](https://www.apollographql.com/docs/apollo-server/) – A production-ready JavaScript GraphQL server that connects to any microservice, API, or database. Compatible with all popular JavaScript frameworks and deployable in serverless environments. +- [Apollo Studio](https://www.apollographql.com/studio/develop/) – A free, end-to-end platform for managing your GraphQL lifecycle. Track your GraphQL schemas in a hosted registry to create a source of truth for everything in your graph. Studio provides an IDE (Apollo Explorer) so you can explore data, collaborate on queries, observe usage, and safely make schema changes. +- [Apollo Federation](https://www.apollographql.com/apollo-federation) – The industry-standard open architecture for building a distributed graph. Use Apollo’s gateway to compose a unified graph from multiple subgraphs, determine a query plan, and route requests across your services. +- [Apollo Client](https://www.apollographql.com/apollo-client/) – The most popular GraphQL client for the web. Apollo also builds and maintains [Apollo iOS](https://github.com/apollographql/apollo-ios) and [Apollo Kotlin](https://github.com/apollographql/apollo-kotlin). +- [Apollo Server](https://www.apollographql.com/docs/apollo-server/) – A production-ready JavaScript GraphQL server that connects to any microservice, API, or database. Compatible with all popular JavaScript frameworks and deployable in serverless environments. ## Learn how to build with Apollo diff --git a/RELEASE_CHECKLIST.md b/RELEASE_CHECKLIST.md deleted file mode 100644 index 4b16ffc88b..0000000000 --- a/RELEASE_CHECKLIST.md +++ /dev/null @@ -1 +0,0 @@ -The release checklist has been moved to a [Pull Request template](https://github.com/apollographql/apollo-ios/blob/main/.github/PULL_REQUEST_TEMPLATE/pull-request-template-release.md). Unfortunately Pull Request templates aren't offered as a selection list when creating a new Pull Request, nor can a static link be used. To get the template contents in your new Pull Request you need to manually append the query parameter `template=pull-request-template-release.md` in the address bar once you've selected the compare branches. diff --git a/ROADMAP.md b/ROADMAP.md index 39c418f649..2277c96d16 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,8 +1,8 @@ # 🔮 Apollo iOS Roadmap -**Last updated: July 2022** +**Last updated: 2024-04-02** -For up to date release notes, refer to the project's [Change Log](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md). +For up to date release notes, refer to the project's [Changelog](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md). > **Please note:** This is an approximation of **larger effort** work planned for the next 6 - 12 months. It does not cover all new functionality that will be added, and nothing here is set in stone. Also note that each of these releases, and several patch releases in-between, will include bug fixes (based on issue triaging) and community submitted PR's. @@ -12,52 +12,100 @@ For up to date release notes, refer to the project's [Change Log](https://github - If you already see an issue that interests you please add a 👍 or a comment so we can measure community interest. --- -## 0.x - _Current_ -This version is being used in many Production codebases, and we're committed to resolving issues and bugs raised by the community. We are not considering any further substantial work to be done in this version. +## [1.x.x patch releases](https://github.com/apollographql/apollo-ios/milestone/70) -These are the three guiding principles we aim for in each major release: +Please see our [patch releases milestone](https://github.com/apollographql/apollo-ios/milestone/70) for more information about the fixes and enhancements we plan to ship in the near future. Anything labeled [`planned-next`](https://github.com/apollographql/apollo-ios/labels/planned-next) is slated for the next patch release. -- **Stability**: Achieve a stable foundation that can be trusted for years to come, maintaining backwards compatibility within major version releases. -- **Completeness**: There are three main parts to the SDK: code generation, network fetching/parsing, and caching. These must provide enough functionality to be a good foundation for incremental improvements within major releases without requiring breaking changes. -- **Clarity**: Everything must be clearly documented with as many working samples as possible. +## Upcoming 1.x features -## 1.0 - _In Beta release phase_ +As we identify feature sets that we intend to ship, we'll add to and update the subheadings in this section. We intend to keep this section in chronological order. In order to enable rapid and continuous feature delivery, we'll avoid assigning minor version numbers to these feature groups in the roadmap. -[Beta 1 is available](https://github.com/apollographql/apollo-ios/releases/tag/1.0.0-beta.1), please try it and give us your feedback. +### [`@defer` support](https://github.com/apollographql/apollo-ios/issues/2395) -These are the major initiatives planned for 1.0/1.x: +_Now available for preview in the `preview-defer.1` branch_ +_Approximate Date: 2024-04-09 (experimental)_ -- **Swift-based Codegen**: The code generation is being rewritten with a Swift-first approach instead of relying on scripting and Typescript. This will allow easier community contribution to code generation and provide the opportunity to improve various characteristics such as generated code size and performance. -- **Modularized GraphQL Code Generation Output**: To support advanced usage of Apollo iOS for modular code bases in a format this is highly configurable and agnostic of the dependency management and build system used. This should be achieved while maintaining the streamlined process for the default usage in unified code bases. +The `@defer` directive enables your queries to receive data for specific fields asynchronously. This is helpful whenever some fields in a query take much longer to resolve than others. [Apollo Kotlin](https://www.apollographql.com/docs/kotlin/fetching/defer/) and [Apollo Client (web)](https://www.apollographql.com/docs/react/data/defer/) currently support this syntax, so if you're interested in learning more check out their documentation. Apollo iOS has released a preview version of this feature in the `preview-defer.1` branch. This will be released as an experimental feature in an upcoming `1.x` minor version. -See Github [1.0 Beta Milestone](https://github.com/apollographql/apollo-ios/milestone/62) for more details. +### [Improvements to code generation configuration and performance](https://github.com/apollographql/apollo-ios/milestone/67) -## 2.0 +_Approximate Date: to be released incrementally_ + +- This effort encompasses several smaller features: + - ✅ Make codegen support Swift concurrency (`async`/`await`): available in v1.7.0 + - Add configuration for disabling merging of fragment fields + - (in progress) Fix retain cycles and memory issues causing code generation to take very long on certain large, complex schemas with deeply nested fragment composition + +### [Reduce generated schema types](https://github.com/apollographql/apollo-ios/milestone/71) + +_Approximate Date: 2024-04-30_ + +- Right now we are naively generating schema types that we don't always need. A smarter algorithm can reduce generated code for certain large schemas that are currently having every type in their schema generated +- Create configuration for manually indicating schema types you would like to have schema types and TestMocks generated for + +### Swift 6 compatibility + +_Approximate Date: 2024-05-17_ + +- [`Sendable` types](https://github.com/apollographql/apollo-ios/issues/3291) +- [`ExistentialAny` upcoming feature](https://github.com/apollographql/apollo-ios/issues/3205) + +### [Configuration to rename generated models for schema types](https://github.com/apollographql/apollo-ios/issues/3283) + +_Approximate Date: 2024-05-29_ + +- Allow client-side users to override the names of schema types in the generated models. +- This will allow user's to improve the quality and expressiveness of client side APIs when schema type names are not appropriate for client usage. +- This also allows workarounds for issues when names of schema types conflict with Swift types. + +### [Mutable generated reponse models](https://github.com/apollographql/apollo-ios/issues/3246) + +_Approximate Date: TBD_ + +- Provide a mechanism for making generated reponse models mutable. +- This will allow mutability on an opt-in basis per selection set or definition. + +### [Support codegen of operations without response models](https://github.com/apollographql/apollo-ios/issues/3165) + +_Approximate Date: TBD_ + +- Support generating models that expose only the minimal necessary data for operation execution (networking and caching). + - This would remove the generated response models, exposing response data as a simple `JSONObject` (ie. [String: AnyHashable]). +- This feature is useful for projects that want to use their own custom data models or have binary size constraints. + +### Declarative caching + +_Approximate Date: TBD_ + +- Similar to Apollo Kotlin [declarative caching](https://www.apollographql.com/docs/kotlin/caching/declarative-ids) via the `@typePolicy` directive +- Provide ability to configure cache keys using directives on schema types as an alternative to programmatic cache key configuration + +## [Apollo iOS Pagination](https://github.com/apollographql/apollo-ios-pagination) + +Version 0.1 of this module was released in March 2024. We are iterating quickly based on user feedback - please see the project's Issues and PRs for up-to-date information. We expect the API to become more stable over time and will consider a v1 release when appropriate. + +## [2.0](https://github.com/apollographql/apollo-ios/milestone/60) + +_Approximate Date: TBD_ These are the major initiatives planned for 2.0/2.x: - **Networking Stack Improvements**: The goal is to simplify and stabilise the networking stack. - - The [updated network stack](https://github.com/apollographql/apollo-ios/issues/1340) solved a number of long standing issues with the old barebones NetworkTransport but still has limitations and is complicated to use. Adopting patterns that have proven useful for the web client, such as Apollo Link, will provide more flexibility and give developers full control over the steps that are invoked to satisfy requests. - - We would love to bring some of the new Swift concurrency features, such as async/await, to Apollo iOS but that depends on the Swift team's work for backwards deployment of the concurrency library. It may involve Apollo iOS dropping support for macOS 10.14 and iOS 12. - -See Github [2.0 Milestone](https://github.com/apollographql/apollo-ios/milestone/60) for more details. + - The [updated network stack](https://github.com/apollographql/apollo-ios/issues/1340) solved a number of long standing issues with the old barebones NetworkTransport but still has limitations and is complicated to use. Adopting patterns that have proven useful for the web client, such as Apollo Link, will provide more flexibility and give developers full control over the steps that are invoked to satisfy requests. + - We will support some of the new Swift concurrency features, such as async/await, in Apollo iOS. It may involve Apollo iOS dropping support for macOS 10.14 and iOS 12. ## 3.0 +_Approximate Date: TBD_ + These are the major initiatives planned for 3.0/3.x: - **Cache Improvements**: Here we are looking at bringing across some features inspired by Apollo Client 3 and Apollo Kotlin - - Better pagination support. Better support for caching and updating paginated lists of objects. - - Reducing over-normalization. Only separating out results into individual records when something that can identify them is present - - Real cache eviction & dangling reference collection. There's presently a way to manually remove objects for a given key or pattern, but Apollo Client 3 has given us a roadmap for how to handle some of this stuff much more thoroughly and safely. - - Cache metadata. Ability to add per-field metadata if needed, to allow for TTL and time-based invalidation, etc. + - Better pagination support. Better support for caching and updating paginated lists of objects. + - Result model improvements + - Reducing over-normalization. Only separating out results into individual records when something that can identify them is present + - Real cache eviction & dangling reference collection. There's presently a way to manually remove objects for a given key or pattern, but Apollo Client 3 has given us a roadmap for how to handle some of this stuff much more thoroughly and safely. + - Cache metadata. Ability to add per-field metadata if needed, to allow for TTL and time-based invalidation, etc. This major release is still in pre-planning, more details will come in the future. - -## Future - -These are subject to change and anything that dramatically changes APIs or breaks backwards compatibility with versions will be reserved for the next major version. - -- **Wrapper libraries**. A very highly voted suggestion in our fall 2019 developer survey was wrapper libraries for concurrency helpers like RxSwift, Combine, PromiseKit, etc. - - Note that we are **not** locked into any particular set of other dependencies to support yet, but we anticipate these will be wrappers in a separate repository that have Apollo as a dependency. As individual wrappers move into nearer-term work, we'll outline which specific ones we'll be supporting. diff --git a/SimpleUploadServer/.gitignore b/SimpleUploadServer/.gitignore deleted file mode 100644 index 98f86d8507..0000000000 --- a/SimpleUploadServer/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -uploads -node_modules -db.json \ No newline at end of file diff --git a/SimpleUploadServer/.nvmrc b/SimpleUploadServer/.nvmrc deleted file mode 100644 index 7814f7d060..0000000000 --- a/SimpleUploadServer/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v12.22.10 \ No newline at end of file diff --git a/SimpleUploadServer/file-utils.js b/SimpleUploadServer/file-utils.js deleted file mode 100644 index 4ec0a29268..0000000000 --- a/SimpleUploadServer/file-utils.js +++ /dev/null @@ -1,50 +0,0 @@ -const fs = require("fs"); -const lowdb = require("lowdb"); -const FileSync = require("lowdb/adapters/FileSync"); -const mkdirp = require("mkdirp"); -const shortid = require("shortid"); - -const UPLOAD_DIR = "./uploads"; -const db = lowdb(new FileSync("db.json")); - -// Seed an empty DB. -db.defaults({ uploads: [] }).write(); - -// Ensure upload directory exists. -mkdirp.sync(UPLOAD_DIR); - -const storeFS = ({ stream, filename }) => { - const id = shortid.generate(); - const path = `${UPLOAD_DIR}/${id}-${filename}`; - return new Promise((resolve, reject) => - stream - .on("error", error => { - if (stream.truncated) - // Delete the truncated file. - fs.unlinkSync(path); - reject(error); - }) - .pipe(fs.createWriteStream(path)) - .on("error", error => reject(error)) - .on("finish", () => resolve({ id, path })) - ); -}; - -const storeDB = file => - db - .get("uploads") - .push(file) - .last() - .write(); - -const processUpload = async upload => { - const { createReadStream, filename, mimetype } = await upload; - const stream = createReadStream(); - const { id, path } = await storeFS({ stream, filename }); - return storeDB({ id, filename, mimetype, path }); -}; - -module.exports = { - db, - processUpload -}; diff --git a/SimpleUploadServer/index.js b/SimpleUploadServer/index.js deleted file mode 100644 index fed3f0b44c..0000000000 --- a/SimpleUploadServer/index.js +++ /dev/null @@ -1,71 +0,0 @@ -const { ApolloServer, gql, GraphQLUpload } = require("apollo-server"); -const promisesAll = require("promises-all"); -const { db, processUpload } = require("./file-utils"); - -const typeDefs = gql` - type File { - id: ID! - path: String! - filename: String! - mimetype: String! - } - type Query { - uploads: [File] - } - type Mutation { - singleUpload(file: Upload!): File! - multipleUpload(files: [Upload!]!): [File!]! - multipleParameterUpload(singleFile: Upload!, multipleFiles: [Upload!]!): [File!]! - } -`; - -const resolvers = { - Upload: GraphQLUpload, - Query: { - uploads: () => db.get("uploads").value() - }, - Mutation: { - singleUpload: (obj, { file }) => processUpload(file), - async multipleUpload(obj, { files }) { - const { resolve, reject } = await promisesAll.all( - files.map(processUpload) - ); - - if (reject.length) - reject.forEach(({ name, message }) => - // eslint-disable-next-line no-console - console.error(`${name}: ${message}`) - ); - - return resolve; - }, - async multipleParameterUpload(obj, { singleFile, multipleFiles }) { - const { resolve, reject } = await promisesAll.all( - [singleFile, ...multipleFiles].map(processUpload) - ); - - if (reject.length) - reject.forEach(({ name, message }) => - // eslint-disable-next-line no-console - console.error(`${name}: ${message}`) - ); - - return resolve; - } - } -}; - -const server = new ApolloServer({ - typeDefs, - resolvers, - uploads: { - maxFileSize: 10000000, // 10 MB - maxFiles: 20 - } -}); - -server.listen({ - port: 4001 -}).then(({ url }) => { - console.info(`Upload server started at ${url}`); -}); diff --git a/SimpleUploadServer/package-lock.json b/SimpleUploadServer/package-lock.json deleted file mode 100644 index 4810a5dd72..0000000000 --- a/SimpleUploadServer/package-lock.json +++ /dev/null @@ -1,1615 +0,0 @@ -{ - "name": "uploads", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - }, - "dependencies": { - "@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" - } - } - }, - "@apollographql/apollo-tools": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.2.tgz", - "integrity": "sha512-KxZiw0Us3k1d0YkJDhOpVH5rJ+mBfjXcgoRoCcslbgirjgLotKMzOcx4PZ7YTEvvEROmvG7X3Aon41GvMmyGsw==" - }, - "@apollographql/graphql-playground-html": { - "version": "1.6.27", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.27.tgz", - "integrity": "sha512-tea2LweZvn6y6xFV11K0KC8ETjmm52mQrW+ezgB2O/aTQf8JGyFmMcRPFgUaQZeHbWdm8iisDC6EjOKsXu0nfw==", - "requires": { - "xss": "^1.0.8" - } - }, - "@apollographql/graphql-upload-8-fork": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-upload-8-fork/-/graphql-upload-8-fork-8.1.3.tgz", - "integrity": "sha512-ssOPUT7euLqDXcdVv3Qs4LoL4BPtfermW1IOouaqEmj36TpHYDmYDIbKoSQxikd9vtMumFnP87OybH7sC9fJ6g==", - "requires": { - "@types/express": "*", - "@types/fs-capacitor": "*", - "@types/koa": "*", - "busboy": "^0.3.1", - "fs-capacitor": "^2.0.4", - "http-errors": "^1.7.3", - "object-path": "^0.11.4" - } - }, - "@josephg/resolvable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", - "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@types/accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==" - }, - "@types/cookies": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.7.tgz", - "integrity": "sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==", - "requires": { - "@types/connect": "*", - "@types/express": "*", - "@types/keygrip": "*", - "@types/node": "*" - } - }, - "@types/cors": { - "version": "2.8.10", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", - "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/fs-capacitor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz", - "integrity": "sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/http-assert": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.3.tgz", - "integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==" - }, - "@types/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q==" - }, - "@types/keygrip": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", - "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==" - }, - "@types/koa": { - "version": "2.13.4", - "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.13.4.tgz", - "integrity": "sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==", - "requires": { - "@types/accepts": "*", - "@types/content-disposition": "*", - "@types/cookies": "*", - "@types/http-assert": "*", - "@types/http-errors": "*", - "@types/keygrip": "*", - "@types/koa-compose": "*", - "@types/node": "*" - } - }, - "@types/koa-compose": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.5.tgz", - "integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==", - "requires": { - "@types/koa": "*" - } - }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/node": { - "version": "16.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", - "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", - "requires": { - "@types/node": "*" - } - }, - "@wry/equality": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz", - "integrity": "sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA==", - "requires": { - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "apollo-cache-control": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.14.0.tgz", - "integrity": "sha512-qN4BCq90egQrgNnTRMUHikLZZAprf3gbm8rC5Vwmc6ZdLolQ7bFsa769Hqi6Tq/lS31KLsXBLTOsRbfPHph12w==", - "requires": { - "apollo-server-env": "^3.1.0", - "apollo-server-plugin-base": "^0.13.0" - } - }, - "apollo-datasource": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.9.0.tgz", - "integrity": "sha512-y8H99NExU1Sk4TvcaUxTdzfq2SZo6uSj5dyh75XSQvbpH6gdAXIW9MaBcvlNC7n0cVPsidHmOcHOWxJ/pTXGjA==", - "requires": { - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - }, - "apollo-graphql": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.9.5.tgz", - "integrity": "sha512-RGt5k2JeBqrmnwRM0VOgWFiGKlGJMfmiif/4JvdaEqhMJ+xqe/9cfDYzXfn33ke2eWixsAbjEbRfy8XbaN9nTw==", - "requires": { - "core-js-pure": "^3.10.2", - "lodash.sortby": "^4.7.0", - "sha.js": "^2.4.11" - } - }, - "apollo-link": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz", - "integrity": "sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg==", - "requires": { - "apollo-utilities": "^1.3.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.9.3", - "zen-observable-ts": "^0.8.21" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha512-B3XmnkH6Y458iV6OsA7AhfwvTgeZnFq9nPVjbxmLKnvfkEl8hYADtz724uPa0WeBiD7DSFcnLtqg9yGmCkBohg==", - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/apollo-server/-/apollo-server-2.25.3.tgz", - "integrity": "sha512-+eUY2//DLkU7RkJLn6CTl1P89/ZMHuUQnWqv8La2iJ2hLT7Me+nMx+hgHl3LqlT/qDstQ8qA45T85FuCayplmQ==", - "requires": { - "apollo-server-core": "^2.25.3", - "apollo-server-express": "^2.25.3", - "express": "^4.0.0", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.8", - "stoppable": "^1.1.0" - } - }, - "apollo-server-caching": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz", - "integrity": "sha512-MsVCuf/2FxuTFVhGLK13B+TZH9tBd2qkyoXKKILIiGcZ5CDUEBO14vIV63aNkMkS1xxvK2U4wBcuuNj/VH2Mkw==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "apollo-server-core": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.3.tgz", - "integrity": "sha512-Midow3uZoJ9TjFNeCNSiWElTVZlvmB7G7tG6PPoxIR9Px90/v16Q6EzunDIO0rTJHRC3+yCwZkwtf8w2AcP0sA==", - "requires": { - "@apollographql/apollo-tools": "^0.5.0", - "@apollographql/graphql-playground-html": "1.6.27", - "@apollographql/graphql-upload-8-fork": "^8.1.3", - "@josephg/resolvable": "^1.0.0", - "@types/ws": "^7.0.0", - "apollo-cache-control": "^0.14.0", - "apollo-datasource": "^0.9.0", - "apollo-graphql": "^0.9.0", - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0", - "apollo-server-errors": "^2.5.0", - "apollo-server-plugin-base": "^0.13.0", - "apollo-server-types": "^0.9.0", - "apollo-tracing": "^0.15.0", - "async-retry": "^1.2.1", - "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "^0.15.0", - "graphql-tag": "^2.11.0", - "graphql-tools": "^4.0.8", - "loglevel": "^1.6.7", - "lru-cache": "^6.0.0", - "sha.js": "^2.4.11", - "subscriptions-transport-ws": "^0.9.19", - "uuid": "^8.0.0" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha512-iGdZgEOAuVop3vb0F2J3+kaBVi4caMoxefHosxmgzAbbSpvWehB8Y1QiSyyMeouYC38XNVk5wnZl+jdGSsWsIQ==", - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-errors": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz", - "integrity": "sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA==" - }, - "apollo-server-express": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.25.3.tgz", - "integrity": "sha512-tTFYn0oKH2qqLwVj7Ez2+MiKleXACODiGh5IxsB7VuYCPMAi9Yl8iUSlwTjQUvgCWfReZjnf0vFL2k5YhDlrtQ==", - "requires": { - "@apollographql/graphql-playground-html": "1.6.27", - "@types/accepts": "^1.3.5", - "@types/body-parser": "1.19.0", - "@types/cors": "2.8.10", - "@types/express": "^4.17.12", - "@types/express-serve-static-core": "^4.17.21", - "accepts": "^1.3.5", - "apollo-server-core": "^2.25.3", - "apollo-server-types": "^0.9.0", - "body-parser": "^1.18.3", - "cors": "^2.8.5", - "express": "^4.17.1", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.8", - "parseurl": "^1.3.2", - "subscriptions-transport-ws": "^0.9.19", - "type-is": "^1.6.16" - }, - "dependencies": { - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - } - } - }, - "apollo-server-plugin-base": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.13.0.tgz", - "integrity": "sha512-L3TMmq2YE6BU6I4Tmgygmd0W55L+6XfD9137k+cWEBFu50vRY4Re+d+fL5WuPkk5xSPKd/PIaqzidu5V/zz8Kg==", - "requires": { - "apollo-server-types": "^0.9.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha512-qk9tg4Imwpk732JJHBkhW0jzfG0nFsLqK2DY6UhvJf7jLnRePYsPxWfPiNkxni27pLE2tiNlCwoDFSeWqpZyBg==", - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - }, - "apollo-tracing": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.15.0.tgz", - "integrity": "sha512-UP0fztFvaZPHDhIB/J+qGuy6hWO4If069MGC98qVs0I8FICIGu4/8ykpX3X3K6RtaQ56EDAWKykCxFv4ScxMeA==", - "requires": { - "apollo-server-env": "^3.1.0", - "apollo-server-plugin-base": "^0.13.0" - } - }, - "apollo-utilities": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz", - "integrity": "sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig==", - "requires": { - "@wry/equality": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "async-retry": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", - "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", - "requires": { - "retry": "0.13.1" - } - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" - }, - "bluebird": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", - "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "busboy": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", - "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", - "requires": { - "dicer": "0.3.0" - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-js-pure": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz", - "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "cssfilter": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", - "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "deprecated-decorator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", - "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "dicer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", - "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", - "requires": { - "streamsearch": "0.1.2" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-capacitor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz", - "integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "graceful-fs": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", - "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==" - }, - "graphql": { - "version": "14.7.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.7.0.tgz", - "integrity": "sha512-l0xWZpoPKpppFzMfvVyFmp9vLN7w/ZZJPefUicMCepfJeQ8sMcztloGYY9DfjVPo6tIUDzU5Hw3MUbIjj9AVVA==", - "requires": { - "iterall": "^1.2.2" - } - }, - "graphql-extensions": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.15.0.tgz", - "integrity": "sha512-bVddVO8YFJPwuACn+3pgmrEg6I8iBuYLuwvxiE+lcQQ7POotVZxm2rgGw0PvVYmWWf3DT7nTVDZ5ROh/ALp8mA==", - "requires": { - "@apollographql/apollo-tools": "^0.5.0", - "apollo-server-env": "^3.1.0", - "apollo-server-types": "^0.9.0" - } - }, - "graphql-subscriptions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz", - "integrity": "sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g==", - "requires": { - "iterall": "^1.3.0" - } - }, - "graphql-tag": { - "version": "2.12.6", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", - "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", - "requires": { - "tslib": "^2.1.0" - } - }, - "graphql-tools": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.8.tgz", - "integrity": "sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg==", - "requires": { - "apollo-link": "^1.2.14", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - } - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "requires": { - "call-bind": "^1.0.0" - } - }, - "iterall": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lowdb": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz", - "integrity": "sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==", - "requires": { - "graceful-fs": "^4.1.3", - "is-promise": "^2.1.0", - "lodash": "4", - "pify": "^3.0.0", - "steno": "^0.4.1" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" - }, - "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "requires": { - "mime-db": "1.50.0" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-path": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==" - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "promises-all": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/promises-all/-/promises-all-1.0.0.tgz", - "integrity": "sha1-pDGMuNRWifZzkE4hVg8DI5cCgg8=", - "requires": { - "bluebird": "^3.4.7" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shortid": { - "version": "2.2.15", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.15.tgz", - "integrity": "sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==", - "requires": { - "nanoid": "^2.1.0" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "steno": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz", - "integrity": "sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs=", - "requires": { - "graceful-fs": "^4.1.3" - } - }, - "stoppable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==" - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "subscriptions-transport-ws": { - "version": "0.9.19", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz", - "integrity": "sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw==", - "requires": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - } - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "ts-invariant": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz", - "integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==", - "requires": { - "tslib": "^1.9.3" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "util.promisify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.1.tgz", - "integrity": "sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "for-each": "^0.3.3", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.1" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" - }, - "xss": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.10.tgz", - "integrity": "sha512-qmoqrRksmzqSKvgqzN0055UFWY7OKx1/9JWeRswwEVX9fCG5jcYRxa/A2DHcmZX6VJvjzHRQ2STeeVcQkrmLSw==", - "requires": { - "commander": "^2.20.3", - "cssfilter": "0.0.10" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "zen-observable": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", - "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" - }, - "zen-observable-ts": { - "version": "0.8.21", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz", - "integrity": "sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg==", - "requires": { - "tslib": "^1.9.3", - "zen-observable": "^0.8.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } - } - } - } -} diff --git a/SimpleUploadServer/package.json b/SimpleUploadServer/package.json deleted file mode 100644 index 5c6a5f40ad..0000000000 --- a/SimpleUploadServer/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "uploads", - "version": "1.0.0", - "description": "", - "main": "index.js", - "dependencies": { - "apollo-server": "^2.16.1", - "graphql": "^14.7.0", - "lowdb": "^1.0.0", - "mkdirp": "^0.5.5", - "promises-all": "^1.0.0", - "shortid": "^2.2.15" - }, - "devDependencies": {}, - "scripts": { - "start": "node index.js" - }, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/Sources/Apollo/Apollo.h b/Sources/Apollo/Apollo.h deleted file mode 100644 index efcebde284..0000000000 --- a/Sources/Apollo/Apollo.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -//! Project version number for Apollo. -FOUNDATION_EXPORT double ApolloVersionNumber; - -//! Project version string for Apollo. -FOUNDATION_EXPORT const unsigned char ApolloVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Sources/Apollo/ApolloStore.swift b/Sources/Apollo/ApolloStore.swift deleted file mode 100644 index 93f923590c..0000000000 --- a/Sources/Apollo/ApolloStore.swift +++ /dev/null @@ -1,322 +0,0 @@ -import Foundation - -/// A function that returns a cache key for a particular result object. If it returns `nil`, a default cache key based on the field path will be used. -public typealias CacheKeyForObject = (_ object: JSONObject) -> JSONValue? -public typealias DidChangeKeysFunc = (Set, UUID?) -> Void - -func rootCacheKey(for operation: Operation) -> String { - switch operation.operationType { - case .query: - return "QUERY_ROOT" - case .mutation: - return "MUTATION_ROOT" - case .subscription: - return "SUBSCRIPTION_ROOT" - } -} - -protocol ApolloStoreSubscriber: AnyObject { - - /// A callback that can be received by subscribers when keys are changed within the database - /// - /// - Parameters: - /// - store: The store which made the changes - /// - changedKeys: The list of changed keys - /// - contextIdentifier: [optional] A unique identifier for the request that kicked off this change, to assist in de-duping cache hits for watchers. - func store(_ store: ApolloStore, - didChangeKeys changedKeys: Set, - contextIdentifier: UUID?) -} - -/// The `ApolloStore` class acts as a local cache for normalized GraphQL results. -public final class ApolloStore { - public var cacheKeyForObject: CacheKeyForObject? - - private let queue: DispatchQueue - - private let cache: NormalizedCache - - private var subscribers: [ApolloStoreSubscriber] = [] - - /// Designated initializer - /// - /// - Parameter cache: An instance of `normalizedCache` to use to cache results. Defaults to an `InMemoryNormalizedCache`. - public init(cache: NormalizedCache = InMemoryNormalizedCache()) { - self.cache = cache - queue = DispatchQueue(label: "com.apollographql.ApolloStore", attributes: .concurrent) - } - - fileprivate func didChangeKeys(_ changedKeys: Set, identifier: UUID?) { - for subscriber in self.subscribers { - subscriber.store(self, didChangeKeys: changedKeys, contextIdentifier: identifier) - } - } - - /// Clears the instance of the cache. Note that a cache can be shared across multiple `ApolloClient` objects, so clearing that underlying cache will clear it for all clients. - /// - /// - Parameters: - /// - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. - /// - completion: [optional] A completion block to be called after records are merged into the cache. - public func clearCache(callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) { - queue.async(flags: .barrier) { - let result = Result { try self.cache.clear() } - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: result) - } - } - - /// Merges a `RecordSet` into the normalized cache. - /// - Parameters: - /// - records: The records to be merged into the cache. - /// - identifier: [optional] A unique identifier for the request that kicked off this change, - /// to assist in de-duping cache hits for watchers. - /// - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. - /// - completion: [optional] A completion block to be called after records are merged into the cache. - public func publish(records: RecordSet, identifier: UUID? = nil, callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) { - queue.async(flags: .barrier) { - do { - let changedKeys = try self.cache.merge(records: records) - self.didChangeKeys(changedKeys, identifier: identifier) - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .success(())) - } catch { - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .failure(error)) - } - } - } - - func subscribe(_ subscriber: ApolloStoreSubscriber) { - queue.async(flags: .barrier) { - self.subscribers.append(subscriber) - } - } - - func unsubscribe(_ subscriber: ApolloStoreSubscriber) { - queue.async(flags: .barrier) { - self.subscribers = self.subscribers.filter({ $0 !== subscriber }) - } - } - - /// Performs an operation within a read transaction - /// - /// - Parameters: - /// - body: The body of the operation to perform. - /// - callbackQueue: [optional] The callback queue to use to perform the completion block on. Will perform on the current queue if not provided. Defaults to nil. - /// - completion: [optional] The completion block to perform when the read transaction completes. Defaults to nil. - public func withinReadTransaction(_ body: @escaping (ReadTransaction) throws -> T, - callbackQueue: DispatchQueue? = nil, - completion: ((Result) -> Void)? = nil) { - self.queue.async { - do { - let returnValue = try body(ReadTransaction(store: self)) - - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .success(returnValue)) - } catch { - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .failure(error)) - } - } - } - - /// Performs an operation within a read-write transaction - /// - /// - Parameters: - /// - body: The body of the operation to perform - /// - callbackQueue: [optional] a callback queue to perform the action on. Will perform on the current queue if not provided. Defaults to nil. - /// - completion: [optional] a completion block to fire when the read-write transaction completes. Defaults to nil. - public func withinReadWriteTransaction(_ body: @escaping (ReadWriteTransaction) throws -> T, - callbackQueue: DispatchQueue? = nil, - completion: ((Result) -> Void)? = nil) { - self.queue.async(flags: .barrier) { - do { - let returnValue = try body(ReadWriteTransaction(store: self)) - - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .success(returnValue)) - } catch { - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .failure(error)) - } - } - } - - /// Loads the results for the given query from the cache. - /// - /// - Parameters: - /// - query: The query to load results for - /// - resultHandler: The completion handler to execute on success or error - public func load(query: Operation, callbackQueue: DispatchQueue? = nil, resultHandler: @escaping GraphQLResultHandler) { - withinReadTransaction({ transaction in - let mapper = GraphQLSelectionSetMapper() - let dependencyTracker = GraphQLDependencyTracker() - - let (data, dependentKeys) = try transaction.execute(selections: Operation.Data.selections, - onObjectWithKey: rootCacheKey(for: query), - variables: query.variables, - accumulator: zip(mapper, dependencyTracker)) - - return GraphQLResult(data: data, - extensions: nil, - errors: nil, - source:.cache, - dependentKeys: dependentKeys) - }, callbackQueue: callbackQueue, completion: resultHandler) - } - - public class ReadTransaction { - fileprivate let cache: NormalizedCache - fileprivate let cacheKeyForObject: CacheKeyForObject? - - fileprivate lazy var loader: DataLoader = DataLoader(self.cache.loadRecords) - - fileprivate init(store: ApolloStore) { - self.cache = store.cache - self.cacheKeyForObject = store.cacheKeyForObject - } - - public func read(query: Query) throws -> Query.Data { - return try readObject(ofType: Query.Data.self, - withKey: rootCacheKey(for: query), - variables: query.variables) - } - - public func readObject(ofType type: SelectionSet.Type, - withKey key: CacheKey, - variables: GraphQLMap? = nil) throws -> SelectionSet { - let mapper = GraphQLSelectionSetMapper() - return try execute(selections: type.selections, - onObjectWithKey: key, - variables: variables, - accumulator: mapper) - } - - fileprivate func execute(selections: [GraphQLSelection], onObjectWithKey key: CacheKey, variables: GraphQLMap?, accumulator: Accumulator) throws -> Accumulator.FinalResult { - let object = try loadObject(forKey: key).get() - - let executor = GraphQLExecutor { object, info in - return object[info.cacheKeyForField] - } resolveReference: { reference in - self.loadObject(forKey: reference.key) - } - - executor.cacheKeyForObject = self.cacheKeyForObject - - return try executor.execute(selections: selections, - on: object, - withKey: key, - variables: variables, - accumulator: accumulator) - } - - private final func loadObject(forKey key: CacheKey) -> PossiblyDeferred { - self.loader[key].map { record in - guard let record = record else { throw JSONDecodingError.missingValue } - return record.fields - } - } - } - - public final class ReadWriteTransaction: ReadTransaction { - - fileprivate var updateChangedKeysFunc: DidChangeKeysFunc? - - override init(store: ApolloStore) { - self.updateChangedKeysFunc = store.didChangeKeys - super.init(store: store) - } - - public func update(query: Query, _ body: (inout Query.Data) throws -> Void) throws { - var data = try read(query: query) - try body(&data) - try write(data: data, forQuery: query) - } - - public func updateObject(ofType type: SelectionSet.Type, - withKey key: CacheKey, - variables: GraphQLMap? = nil, - _ body: (inout SelectionSet) throws -> Void) throws { - var object = try readObject(ofType: type, - withKey: key, - variables: variables) - try body(&object) - try write(object: object, withKey: key, variables: variables) - } - - /// Removes the object for the specified cache key. Does not cascade - /// or allow removal of only certain fields. Does nothing if an object - /// does not exist for the given key. - /// - /// - Parameters: - /// - key: The cache key to remove the object for - public func removeObject(for key: CacheKey) throws { - try self.cache.removeRecord(for: key) - } - - /// Removes records with keys that match the specified pattern. This method will only - /// remove whole records, it does not perform cascading deletes. This means only the - /// records with matched keys will be removed, and not any references to them. Key - /// matching is case-insensitive. - /// - /// If you attempt to pass a cache path for a single field, this method will do nothing - /// since it won't be able to locate a record to remove based on that path. - /// - /// - Note: This method can be very slow depending on the number of records in the cache. - /// It is recommended that this method be called in a background queue. - /// - /// - Parameters: - /// - pattern: The pattern that will be applied to find matching keys. - public func removeObjects(matching pattern: CacheKey) throws { - try self.cache.removeRecords(matching: pattern) - } - - public func write(data: Query.Data, forQuery query: Query) throws { - try write(object: data, - withKey: rootCacheKey(for: query), - variables: query.variables) - } - - public func write(object: GraphQLSelectionSet, - withKey key: CacheKey, - variables: GraphQLMap? = nil) throws { - try write(object: object.jsonObject, - forSelections: type(of: object).selections, - withKey: key, variables: variables) - } - - private func write(object: JSONObject, - forSelections selections: [GraphQLSelection], - withKey key: CacheKey, - variables: GraphQLMap?) throws { - let normalizer = GraphQLResultNormalizer() - let executor = GraphQLExecutor { object, info in - return object[info.responseKeyForField] - } - - executor.cacheKeyForObject = self.cacheKeyForObject - - let records = try executor.execute(selections: selections, - on: object, - withKey: key, - variables: variables, - accumulator: normalizer) - let changedKeys = try self.cache.merge(records: records) - - // Remove cached records, so subsequent reads - // within the same transaction will reload the updated value. - loader.removeAll() - - if let didChangeKeysFunc = self.updateChangedKeysFunc { - didChangeKeysFunc(changedKeys, nil) - } - } - } -} diff --git a/Sources/Apollo/AutomaticPersistedQueryInterceptor.swift b/Sources/Apollo/AutomaticPersistedQueryInterceptor.swift deleted file mode 100644 index 062e961bb9..0000000000 --- a/Sources/Apollo/AutomaticPersistedQueryInterceptor.swift +++ /dev/null @@ -1,78 +0,0 @@ -import Foundation - -public struct AutomaticPersistedQueryInterceptor: ApolloInterceptor { - - public enum APQError: LocalizedError { - case noParsedResponse - case persistedQueryRetryFailed(operationName: String) - - public var errorDescription: String? { - switch self { - case .noParsedResponse: - return "The Automatic Persisted Query Interceptor was called before a response was received. Double-check the order of your interceptors." - case .persistedQueryRetryFailed(let operationName): - return "Persisted query retry failed for operation \"\(operationName)\"." - } - } - } - - /// Designated initializer - public init() {} - - public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - guard - let jsonRequest = request as? JSONRequest, - jsonRequest.autoPersistQueries else { - // Not a request that handles APQs, continue along - chain.proceedAsync(request: request, - response: response, - completion: completion) - return - } - - guard let result = response?.parsedResponse else { - // This is in the wrong order - this needs to be parsed before we can check it. - chain.handleErrorAsync(APQError.noParsedResponse, - request: request, - response: response, - completion: completion) - return - } - - guard let errors = result.errors else { - // No errors were returned so no retry is necessary, continue along. - chain.proceedAsync(request: request, - response: response, - completion: completion) - return - } - - let errorMessages = errors.compactMap { $0.message } - guard errorMessages.contains("PersistedQueryNotFound") else { - // The errors were not APQ errors, continue along. - chain.proceedAsync(request: request, - response: response, - completion: completion) - return - } - - guard !jsonRequest.isPersistedQueryRetry else { - // We already retried this and it didn't work. - chain.handleErrorAsync(APQError.persistedQueryRetryFailed(operationName: jsonRequest.operation.operationName), - request: jsonRequest, - response: response, - completion: completion) - return - } - - // We need to retry this query with the full body. - jsonRequest.isPersistedQueryRetry = true - chain.retry(request: jsonRequest, - completion: completion) - } -} diff --git a/Sources/Apollo/CacheReadInterceptor.swift b/Sources/Apollo/CacheReadInterceptor.swift deleted file mode 100644 index dc57503a63..0000000000 --- a/Sources/Apollo/CacheReadInterceptor.swift +++ /dev/null @@ -1,100 +0,0 @@ -import Foundation - -/// An interceptor that reads data from the cache for queries, following the `HTTPRequest`'s `cachePolicy`. -public struct CacheReadInterceptor: ApolloInterceptor { - - private let store: ApolloStore - - /// Designated initializer - /// - /// - Parameter store: The store to use when reading from the cache. - public init(store: ApolloStore) { - self.store = store - } - - public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - switch request.operation.operationType { - case .mutation, - .subscription: - // Mutations and subscriptions don't need to hit the cache. - chain.proceedAsync(request: request, - response: response, - completion: completion) - case .query: - switch request.cachePolicy { - case .fetchIgnoringCacheCompletely, - .fetchIgnoringCacheData: - // Don't bother with the cache, just keep going - chain.proceedAsync(request: request, - response: response, - completion: completion) - case .returnCacheDataAndFetch: - self.fetchFromCache(for: request, chain: chain) { cacheFetchResult in - switch cacheFetchResult { - case .failure: - // Don't return a cache miss error, just keep going - break - case .success(let graphQLResult): - chain.returnValueAsync(for: request, - value: graphQLResult, - completion: completion) - } - - // In either case, keep going asynchronously - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - case .returnCacheDataElseFetch: - self.fetchFromCache(for: request, chain: chain) { cacheFetchResult in - switch cacheFetchResult { - case .failure: - // Cache miss, proceed to network without returning error - chain.proceedAsync(request: request, - response: response, - completion: completion) - case .success(let graphQLResult): - // Cache hit! We're done. - chain.returnValueAsync(for: request, - value: graphQLResult, - completion: completion) - } - } - case .returnCacheDataDontFetch: - self.fetchFromCache(for: request, chain: chain) { cacheFetchResult in - switch cacheFetchResult { - case .failure(let error): - // Cache miss - don't hit the network, just return the error. - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) - case .success(let result): - chain.returnValueAsync(for: request, - value: result, - completion: completion) - } - } - } - } - } - - private func fetchFromCache( - for request: HTTPRequest, - chain: RequestChain, - completion: @escaping (Result, Error>) -> Void) { - - self.store.load(query: request.operation) { loadResult in - guard chain.isNotCancelled else { - return - } - - completion(loadResult) - } - } -} diff --git a/Sources/Apollo/CacheReference.swift b/Sources/Apollo/CacheReference.swift deleted file mode 100644 index 3833f94592..0000000000 --- a/Sources/Apollo/CacheReference.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation - -/// A reference to a cache record. -public struct CacheReference { - public let key: String - - public init(key: String) { - self.key = key - } -} - -extension CacheReference: Equatable { - public static func ==(lhs: CacheReference, rhs: CacheReference) -> Bool { - return lhs.key == rhs.key - } -} - -extension CacheReference: CustomStringConvertible { - public var description: String { - return "-> #\(key)" - } -} diff --git a/Sources/Apollo/Collection+Helpers.swift b/Sources/Apollo/Collection+Helpers.swift deleted file mode 100644 index 9046b4b950..0000000000 --- a/Sources/Apollo/Collection+Helpers.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation - -// MARK: - Unzipping -// MARK: Arrays of tuples to tuples of arrays - -public func unzip(_ array: [(Element1, Element2)]) -> ([Element1], [Element2]) { - var array1: [Element1] = [] - var array2: [Element2] = [] - - for element in array { - array1.append(element.0) - array2.append(element.1) - } - - return (array1, array2) -} - -public func unzip(_ array: [(Element1, Element2, Element3)]) -> ([Element1], [Element2], [Element3]) { - var array1: [Element1] = [] - var array2: [Element2] = [] - var array3: [Element3] = [] - - for element in array { - array1.append(element.0) - array2.append(element.1) - array3.append(element.2) - } - - return (array1, array2, array3) -} diff --git a/Sources/Apollo/Decoding.swift b/Sources/Apollo/Decoding.swift deleted file mode 100644 index 1ed5c7f08b..0000000000 --- a/Sources/Apollo/Decoding.swift +++ /dev/null @@ -1,181 +0,0 @@ -import Foundation - -private typealias GroupedFields = GroupedSequence - -func decode(selectionSet: SelectionSet.Type, - from object: JSONObject, - variables: GraphQLMap? = nil) throws -> SelectionSet { - var groupedFields = GroupedFields() - let runtimeType = object["__typename"] as? String - try collectFields(from: selectionSet.selections, - forRuntimeType: runtimeType, - into: &groupedFields, - variables: variables) - let resultMap = try decode(groupedFields: groupedFields, - from: object, - path: [], - variables: variables) - - return SelectionSet.init(unsafeResultMap: resultMap) -} - -private func decode(groupedFields: GroupedFields, - from object: JSONObject, - path: ResponsePath, - variables: GraphQLMap?) throws -> ResultMap { - var fieldEntries: [(String, Any?)] = [] - fieldEntries.reserveCapacity(groupedFields.keys.count) - - for (responseName, fields) in groupedFields { - let fieldEntry = try decode(fields: fields, - from: object, - path: path + responseName, - variables: variables) - fieldEntries.append((responseName, fieldEntry)) - } - - return ResultMap(fieldEntries, uniquingKeysWith: { (_, last) in last }) -} - -/// Before execution, the selection set is converted to a grouped field set. Each entry in the grouped field set is a list of fields that share a response key. This ensures all fields with the same response key (alias or field name) included via referenced fragments are executed at the same time. -private func collectFields(from selections: [GraphQLSelection], - forRuntimeType runtimeType: String? = nil, - into groupedFields: inout GroupedFields, - variables: GraphQLMap?) throws { - for selection in selections { - switch selection { - case let field as GraphQLField: - _ = groupedFields.append(value: field, forKey: field.responseKey) - case let booleanCondition as GraphQLBooleanCondition: - guard let value = variables?[booleanCondition.variableName] else { - throw GraphQLError("Variable \(booleanCondition.variableName) was not provided.") - } - if value as? Bool == !booleanCondition.inverted { - try collectFields(from: booleanCondition.selections, - forRuntimeType: runtimeType, - into: &groupedFields, - variables: variables) - } - case let fragmentSpread as GraphQLFragmentSpread: - let fragment = fragmentSpread.fragment - - if let runtimeType = runtimeType, fragment.possibleTypes.contains(runtimeType) { - try collectFields(from: fragment.selections, - forRuntimeType: runtimeType, - into: &groupedFields, - variables: variables) - } - case let typeCase as GraphQLTypeCase: - let selections: [GraphQLSelection] - if let runtimeType = runtimeType { - selections = typeCase.variants[runtimeType] ?? typeCase.default - } else { - selections = typeCase.default - } - try collectFields(from: selections, - forRuntimeType: runtimeType, - into: &groupedFields, - variables: variables) - default: - preconditionFailure() - } - } -} - -/// Each field requested in the grouped field set that is defined on the selected objectType will result in an entry in the response map. Field execution first coerces any provided argument values, then resolves a value for the field, and finally completes that value either by recursively executing another selection set or coercing a scalar value. -private func decode(fields: [GraphQLField], - from object: JSONObject, - path: ResponsePath, - variables: GraphQLMap?) throws -> Any? { - // GraphQL validation makes sure all fields sharing the same response key have the same arguments and are of the same type, so we only need to resolve one field. - let firstField = fields[0] - - do { - guard let value = object[firstField.responseKey] else { - throw JSONDecodingError.missingValue - } - - return try complete(value: value, - ofType: firstField.type, - fields: fields, - path: path, - variables: variables) - } catch { - if !(error is GraphQLResultError) { - throw GraphQLResultError(path: path, underlying: error) - } else { - throw error - } - } -} - -/// After resolving the value for a field, it is completed by ensuring it adheres to the expected return type. If the return type is another Object type, then the field execution process continues recursively. -private func complete(value: JSONValue, - ofType returnType: GraphQLOutputType, - fields: [GraphQLField], - path: ResponsePath, - variables: GraphQLMap?) throws -> Any? { - if case .nonNull(let innerType) = returnType { - if value is NSNull { - throw JSONDecodingError.nullValue - } - - return try complete(value: value, - ofType: innerType, - fields: fields, - path: path, - variables: variables) - } - - if value is NSNull { - return nil - } - - switch returnType { - case .scalar(let decodable): - return try decodable.init(jsonValue: value) - case .list(let innerType): - guard let array = value as? [JSONValue] else { throw JSONDecodingError.wrongType } - - return try array.enumerated().map { index, element -> Any? in - var path = path - path.append(String(index)) - return try complete(value: element, - ofType: innerType, - fields: fields, - path: path, - variables: variables) - } - case .object: - guard let object = value as? JSONObject else { throw JSONDecodingError.wrongType } - guard let runtimeType = object["__typename"] as? String else { - throw GraphQLResultError(path: path + "__typename", underlying: JSONDecodingError.missingValue) - } - // The merged selection set is a list of fields from all sub‐selection sets of the original fields. - let subFields = try collectSubfields(from: fields, - forRuntimeType: runtimeType, - variables: variables) - // We execute the merged selection set on the object to complete the value. This is the recursive step in the GraphQL execution model. - return try decode(groupedFields: subFields, - from: object, - path: path, - variables: variables) - default: - preconditionFailure() - } -} - -private func collectSubfields(from fields: [GraphQLField], - forRuntimeType runtimeType: String, - variables: GraphQLMap?) throws -> GroupedFields { - var groupedFields = GroupedFields() - for field in fields { - if case let .object(subSelections) = field.type.namedType { - try collectFields(from: subSelections, - forRuntimeType: runtimeType, - into: &groupedFields, - variables: variables) - } - } - return groupedFields -} diff --git a/Sources/Apollo/GraphQLDependencyTracker.swift b/Sources/Apollo/GraphQLDependencyTracker.swift deleted file mode 100644 index 0d966804c5..0000000000 --- a/Sources/Apollo/GraphQLDependencyTracker.swift +++ /dev/null @@ -1,26 +0,0 @@ -final class GraphQLDependencyTracker: GraphQLResultAccumulator { - private var dependentKeys: Set = Set() - - func accept(scalar: JSONValue, info: GraphQLResolveInfo) { - dependentKeys.insert(info.cachePath.joined) - } - - func acceptNullValue(info: GraphQLResolveInfo) { - dependentKeys.insert(info.cachePath.joined) - } - - func accept(list: [Void], info: GraphQLResolveInfo) { - dependentKeys.insert(info.cachePath.joined) - } - - func accept(fieldEntry: Void, info: GraphQLResolveInfo) { - dependentKeys.insert(info.cachePath.joined) - } - - func accept(fieldEntries: [Void], info: GraphQLResolveInfo) { - } - - func finish(rootValue: Void, info: GraphQLResolveInfo) -> Set { - return dependentKeys - } -} diff --git a/Sources/Apollo/GraphQLExecutor.swift b/Sources/Apollo/GraphQLExecutor.swift deleted file mode 100644 index a59f2acc79..0000000000 --- a/Sources/Apollo/GraphQLExecutor.swift +++ /dev/null @@ -1,358 +0,0 @@ -import Foundation -#if !COCOAPODS -import ApolloUtils -#endif - -/// A field resolver is responsible for resolving a value for a field. -typealias GraphQLFieldResolver = (_ object: JSONObject, _ info: GraphQLResolveInfo) -> JSONValue? -/// A reference resolver is responsible for resolving an object based on its key. These references are -/// used in normalized records, and data for these objects has to be loaded from the cache for execution to continue. -/// Because data may be loaded from a database, these loads are batched for performance reasons. -/// By returning a `PossiblyDeferred` wrapper, we allow `ApolloStore` to use a `DataLoader` that -/// will defer loading the next batch of records from the cache until they are needed. -typealias ReferenceResolver = (CacheReference) -> PossiblyDeferred - -struct GraphQLResolveInfo { - let variables: GraphQLMap? - - var responsePath: ResponsePath = [] - var responseKeyForField: String = "" - - var cachePath: ResponsePath = [] - var cacheKeyForField: String = "" - - var fields: [GraphQLField] = [] - - init(rootKey: CacheKey?, variables: GraphQLMap?) { - self.variables = variables - - if let rootKey = rootKey { - cachePath = [rootKey] - } - } -} - -/// An error which has occurred in processing a GraphQLResult -public struct GraphQLResultError: Error, LocalizedError { - let path: ResponsePath - - public var pathString: String { path.description } - - /// The error that occurred during parsing. - public let underlying: Error - - /// A description of the error which includes the path where the error occurred. - public var errorDescription: String? { - return "Error at path \"\(path))\": \(underlying)" - } -} - -/// A GraphQL executor is responsible for executing a selection set and generating a result. It is initialized with a resolver closure that gets called repeatedly to resolve field values. -/// -/// An executor is used both to parse a response received from the server, and to read from the normalized cache. It can also be configured with a accumulator that receives events during execution, and these execution events are used by `GraphQLResultNormalizer` to normalize a response into a flat set of records and by `GraphQLDependencyTracker` keep track of dependent keys. -/// -/// The methods in this class closely follow the [execution algorithm described in the GraphQL specification](https://facebook.github.io/graphql/#sec-Execution), but an important difference is that execution returns a value for every selection in a selection set, not the merged fields. This means we get a separate result for every fragment, even though all fields that share a response key are still executed at the same time for efficiency. -/// -/// So given the following query: -/// -/// ``` -/// query HeroAndFriendsNames { -/// hero { -/// name -/// friends { -/// name -/// } -/// ...FriendsAppearsIn -/// } -/// } -/// -/// fragment FriendsAppearsIn on Character { -/// friends { -/// appearsIn -/// } -/// } -/// ``` -/// -/// A server would return a response with `name` and `appearsIn` merged into one object: -/// -/// ``` -/// ... -/// { -/// "name": "R2-D2", -/// "friends": [ -/// { -/// "name": "Luke Skywalker", -/// "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"] -/// } -/// } -/// ... -/// ``` -/// -/// The executor on the other hand, will return a separate value for every selection: -/// -/// - `String` -/// - `[HeroAndFriendsNames.Data.Hero.Friend]` -/// - `FriendsAppearsIn` -/// - `[FriendsAppearsIn.Friend]` -/// -/// These values then get passed into a generated `GraphQLMappable` initializer, and this is how type safe results get built up. -/// -final class GraphQLExecutor { - private let fieldResolver: GraphQLFieldResolver - private let resolveReference: ReferenceResolver? - - var cacheKeyForObject: CacheKeyForObject? - var shouldComputeCachePath = true - - /// Creates a GraphQLExecutor that resolves field values by calling the provided resolver. If provided, it will also resolve references by calling - /// the reference resolver. - init(resolver: @escaping GraphQLFieldResolver, resolveReference: ReferenceResolver? = nil) { - self.fieldResolver = resolver - self.resolveReference = resolveReference - } - - private func runtimeType(of object: JSONObject) -> String? { - return object["__typename"] as? String - } - - private func cacheKey(for object: JSONObject) -> String? { - guard let value = cacheKeyForObject?(object) else { return nil } - - if let array = value as? [Any?] { - return array.compactMap { String(describing: $0) }.joined(separator: "_") - } else { - return String(describing: value) - } - } - - // MARK: - Execution - - func execute(selections: [GraphQLSelection], - on object: JSONObject, - withKey key: CacheKey? = nil, - variables: GraphQLMap? = nil, - accumulator: Accumulator) throws -> Accumulator.FinalResult { - let info = GraphQLResolveInfo(rootKey: key, variables: variables) - - let rootValue = execute(selections: selections, - on: object, - info: info, - accumulator: accumulator) - - return try accumulator.finish(rootValue: try rootValue.get(), info: info) - } - - private func execute(selections: [GraphQLSelection], - on object: JSONObject, - info: GraphQLResolveInfo, - accumulator: Accumulator) -> PossiblyDeferred { - var groupedFields = GroupedSequence() - - do { - try collectFields(selections: selections, - forRuntimeType: runtimeType(of: object), - into: &groupedFields, - info: info) - } catch { - return .immediate(.failure(error)) - } - - var fieldEntries: [PossiblyDeferred] = [] - fieldEntries.reserveCapacity(groupedFields.keys.count) - - for (_, fields) in groupedFields { - let fieldEntry = execute(fields: fields, - on: object, - info: info, - accumulator: accumulator) - fieldEntries.append(fieldEntry) - } - - return lazilyEvaluateAll(fieldEntries).map { - try accumulator.accept(fieldEntries: $0, info: info) - } - } - - /// Before execution, the selection set is converted to a grouped field set. Each entry in the grouped field set is a list of fields that share a response key. This ensures all fields with the same response key (alias or field name) included via referenced fragments are executed at the same time. - private func collectFields(selections: [GraphQLSelection], - forRuntimeType runtimeType: String?, - into groupedFields: inout GroupedSequence, - info: GraphQLResolveInfo) throws { - for selection in selections { - switch selection { - case let field as GraphQLField: - _ = groupedFields.append(value: field, forKey: field.responseKey) - case let booleanCondition as GraphQLBooleanCondition: - guard let value = info.variables?[booleanCondition.variableName] else { - throw GraphQLError("Variable \(booleanCondition.variableName) was not provided.") - } - if value as? Bool == !booleanCondition.inverted { - try collectFields(selections: booleanCondition.selections, - forRuntimeType: runtimeType, - into: &groupedFields, - info: info) - } - case let fragmentSpread as GraphQLFragmentSpread: - let fragment = fragmentSpread.fragment - - if let runtimeType = runtimeType, fragment.possibleTypes.contains(runtimeType) { - try collectFields(selections: fragment.selections, - forRuntimeType: runtimeType, - into: &groupedFields, - info: info) - } - case let typeCase as GraphQLTypeCase: - let selections: [GraphQLSelection] - if let runtimeType = runtimeType { - selections = typeCase.variants[runtimeType] ?? typeCase.default - } else { - selections = typeCase.default - } - try collectFields(selections: selections, - forRuntimeType: runtimeType, - into: &groupedFields, - info: info) - default: - preconditionFailure() - } - } - } - - /// Each field requested in the grouped field set that is defined on the selected objectType will result in an entry in the response map. Field execution first coerces any provided argument values, then resolves a value for the field, and finally completes that value either by recursively executing another selection set or coercing a scalar value. - private func execute(fields: [GraphQLField], - on object: JSONObject, - info: GraphQLResolveInfo, - accumulator: Accumulator) -> PossiblyDeferred { - // GraphQL validation makes sure all fields sharing the same response key have the same arguments and are of the same type, so we only need to resolve one field. - let firstField = fields[0] - - var info = info - - let responseKey = firstField.responseKey - info.responseKeyForField = responseKey - info.responsePath.append(responseKey) - - if shouldComputeCachePath { - do { - let cacheKey = try firstField.cacheKey(with: info.variables) - info.cacheKeyForField = cacheKey - info.cachePath.append(cacheKey) - } catch { - return .immediate(.failure(error)) - } - } - - // We still need all fields to complete the value, because they may have different selection sets. - info.fields = fields - - return PossiblyDeferred { - guard let value = fieldResolver(object, info) else { - throw JSONDecodingError.missingValue - } - return value - }.flatMap { - return self.complete(value: $0, - ofType: firstField.type, - info: info, - accumulator: accumulator) - }.map { - try accumulator.accept(fieldEntry: $0, info: info) - }.mapError { error in - if !(error is GraphQLResultError) { - return GraphQLResultError(path: info.responsePath, underlying: error) - } else { - return error - } - } - } - - /// After resolving the value for a field, it is completed by ensuring it adheres to the expected return type. If the return type is another Object type, then the field execution process continues recursively. - private func complete(value: JSONValue, - ofType returnType: GraphQLOutputType, - info: GraphQLResolveInfo, - accumulator: Accumulator) -> PossiblyDeferred { - if case .nonNull(let innerType) = returnType { - if value is NSNull { - return .immediate(.failure(JSONDecodingError.nullValue)) - } - - return complete(value: value, - ofType: innerType, - info: info, - accumulator: accumulator) - } - - if value is NSNull { - return PossiblyDeferred { try accumulator.acceptNullValue(info: info) } - } - - switch returnType { - case .scalar: - return PossiblyDeferred { try accumulator.accept(scalar: value, info: info) } - case .list(let innerType): - guard let array = value as? [JSONValue] else { - return .immediate(.failure(JSONDecodingError.wrongType)) - } - - let completedArray = array.enumerated().map { index, element -> PossiblyDeferred in - var info = info - - let indexSegment = String(index) - info.responsePath.append(indexSegment) - - if shouldComputeCachePath { - info.cachePath.append(indexSegment) - } - - return self.complete(value: element, - ofType: innerType, - info: info, - accumulator: accumulator) - } - - return lazilyEvaluateAll(completedArray).map { - try accumulator.accept(list: $0, info: info) - } - case .object: - if let reference = value as? CacheReference, let resolveReference = resolveReference { - return resolveReference(reference).flatMap { - self.complete(value: $0, - ofType: returnType, - info: info, - accumulator: accumulator) - } - } - - guard let object = value as? JSONObject else { - return .immediate(.failure(JSONDecodingError.wrongType)) - } - - // The merged selection set is a list of fields from all sub‐selection sets of the original fields. - let selections = mergeSelectionSets(for: info.fields) - - var info = info - if shouldComputeCachePath, let cacheKeyForObject = self.cacheKey(for: object) { - info.cachePath = [cacheKeyForObject] - } - - // We execute the merged selection set on the object to complete the value. This is the recursive step in the GraphQL execution model. - return self.execute(selections: selections, - on: object, - info: info, - accumulator: accumulator).map { $0 as! Accumulator.PartialResult } - default: - preconditionFailure() - } - } - - /// When fields are selected multiple times, their selection sets are merged together when completing the value in order to continue execution of the sub‐selection sets. - private func mergeSelectionSets(for fields: [GraphQLField]) -> [GraphQLSelection] { - var selections: [GraphQLSelection] = [] - for field in fields { - if case let .object(fieldSelections) = field.type.namedType { - selections.append(contentsOf: fieldSelections) - } - } - return selections - } -} diff --git a/Sources/Apollo/GraphQLMap.swift b/Sources/Apollo/GraphQLMap.swift deleted file mode 100644 index f18d80392f..0000000000 --- a/Sources/Apollo/GraphQLMap.swift +++ /dev/null @@ -1,19 +0,0 @@ -public typealias GraphQLMap = [String: JSONEncodable?] - -fileprivate extension Dictionary where Key == String, Value == JSONEncodable? { - var withNilValuesRemoved: Dictionary { - filter { $0.value != nil } - } -} - -public protocol GraphQLMapConvertible: JSONEncodable { - var graphQLMap: GraphQLMap { get } -} - -public extension GraphQLMapConvertible { - var jsonValue: JSONValue { - return graphQLMap.withNilValuesRemoved.jsonValue - } -} - -public typealias GraphQLID = String diff --git a/Sources/Apollo/GraphQLOperation.swift b/Sources/Apollo/GraphQLOperation.swift deleted file mode 100644 index 6be6b6a1c0..0000000000 --- a/Sources/Apollo/GraphQLOperation.swift +++ /dev/null @@ -1,53 +0,0 @@ -public enum GraphQLOperationType { - case query - case mutation - case subscription -} - -public protocol GraphQLOperation: AnyObject { - var operationType: GraphQLOperationType { get } - - var operationDefinition: String { get } - var operationIdentifier: String? { get } - var operationName: String { get } - - var queryDocument: String { get } - - var variables: GraphQLMap? { get } - - associatedtype Data: GraphQLSelectionSet -} - -public extension GraphQLOperation { - var queryDocument: String { - return operationDefinition - } - - var operationIdentifier: String? { - return nil - } - - var variables: GraphQLMap? { - return nil - } -} - -public protocol GraphQLQuery: GraphQLOperation {} -public extension GraphQLQuery { - var operationType: GraphQLOperationType { return .query } -} - -public protocol GraphQLMutation: GraphQLOperation {} -public extension GraphQLMutation { - var operationType: GraphQLOperationType { return .mutation } -} - -public protocol GraphQLSubscription: GraphQLOperation {} -public extension GraphQLSubscription { - var operationType: GraphQLOperationType { return .subscription } -} - -public protocol GraphQLFragment: GraphQLSelectionSet { - static var fragmentDefinition: String { get } - static var possibleTypes: [String] { get } -} diff --git a/Sources/Apollo/GraphQLResponse.swift b/Sources/Apollo/GraphQLResponse.swift deleted file mode 100644 index 3b1dc8881a..0000000000 --- a/Sources/Apollo/GraphQLResponse.swift +++ /dev/null @@ -1,105 +0,0 @@ -import Foundation - -/// Represents a GraphQL response received from a server. -public final class GraphQLResponse { - - public let body: JSONObject - - private var rootKey: String - private var variables: GraphQLMap? - - public init(operation: Operation, body: JSONObject) where Operation.Data == Data { - self.body = body - rootKey = rootCacheKey(for: operation) - variables = operation.variables - } - - func setupOperation (_ operation: Operation) { - self.rootKey = rootCacheKey(for: operation) - self.variables = operation.variables - } - - /// Parses a response into a `GraphQLResult` and a `RecordSet`. - /// The result can be sent to a completion block for a request. - /// The `RecordSet` can be merged into a local cache. - /// - Parameter cacheKeyForObject: See `CacheKeyForObject` - /// - Returns: A `GraphQLResult` and a `RecordSet`. - public func parseResult(cacheKeyForObject: CacheKeyForObject? = nil) throws -> (GraphQLResult, RecordSet?) { - let errors: [GraphQLError]? - - if let errorsEntry = body["errors"] as? [JSONObject] { - errors = errorsEntry.map(GraphQLError.init) - } else { - errors = nil - } - - let extensions = body["extensions"] as? JSONObject - - if let dataEntry = body["data"] as? JSONObject { - let executor = GraphQLExecutor { object, info in - return object[info.responseKeyForField] - } - - executor.cacheKeyForObject = cacheKeyForObject - - let mapper = GraphQLSelectionSetMapper() - let normalizer = GraphQLResultNormalizer() - let dependencyTracker = GraphQLDependencyTracker() - - let (data, records, dependentKeys) = try executor.execute(selections: Data.selections, - on: dataEntry, - withKey: rootKey, - variables: variables, - accumulator: zip(mapper, normalizer, dependencyTracker)) - - return ( - GraphQLResult(data: data, - extensions: extensions, - errors: errors, - source: .server, - dependentKeys: dependentKeys), - records - ) - } else { - return ( - GraphQLResult(data: nil, - extensions: extensions, - errors: errors, - source: .server, - dependentKeys: nil), - nil - ) - } - } - - public func parseErrorsOnlyFast() -> [GraphQLError]? { - guard let errorsEntry = self.body["errors"] as? [JSONObject] else { - return nil - } - - return errorsEntry.map(GraphQLError.init) - } - - public func parseResultFast() throws -> GraphQLResult { - let errors = self.parseErrorsOnlyFast() - let extensions = body["extensions"] as? JSONObject - - if let dataEntry = body["data"] as? JSONObject { - let data = try decode(selectionSet: Data.self, - from: dataEntry, - variables: variables) - - return GraphQLResult(data: data, - extensions: extensions, - errors: errors, - source: .server, - dependentKeys: nil) - } else { - return GraphQLResult(data: nil, - extensions: extensions, - errors: errors, - source: .server, - dependentKeys: nil) - } - } -} diff --git a/Sources/Apollo/GraphQLResponseGenerator.swift b/Sources/Apollo/GraphQLResponseGenerator.swift deleted file mode 100644 index 07d2e33cd2..0000000000 --- a/Sources/Apollo/GraphQLResponseGenerator.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation - -final class GraphQLResponseGenerator: GraphQLResultAccumulator { - func accept(scalar: JSONValue, info: GraphQLResolveInfo) -> JSONValue { - return scalar - } - - func acceptNullValue(info: GraphQLResolveInfo) -> JSONValue { - return NSNull() - } - - func accept(list: [JSONValue], info: GraphQLResolveInfo) -> JSONValue { - return list - } - - func accept(fieldEntry: JSONValue, info: GraphQLResolveInfo) -> (key: String, value: JSONValue) { - return (info.responseKeyForField, fieldEntry) - } - - func accept(fieldEntries: [(key: String, value: JSONValue)], info: GraphQLResolveInfo) -> JSONValue { - return JSONObject(fieldEntries, uniquingKeysWith: { (_, last) in last }) - } - - func finish(rootValue: JSONValue, info: GraphQLResolveInfo) throws -> JSONObject { - return rootValue as! JSONObject - } -} diff --git a/Sources/Apollo/GraphQLResult.swift b/Sources/Apollo/GraphQLResult.swift deleted file mode 100644 index 596d81c9eb..0000000000 --- a/Sources/Apollo/GraphQLResult.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Foundation - -/// Represents the result of a GraphQL operation. -public struct GraphQLResult { - - /// The typed result data, or `nil` if an error was encountered that prevented a valid response. - public let data: Data? - /// A list of errors, or `nil` if the operation completed without encountering any errors. - public let errors: [GraphQLError]? - /// A dictionary which services can use however they see fit to provide additional information to clients. - public let extensions: [String: Any]? - - /// Represents source of data - public enum Source { - case cache - case server - } - /// Source of data - public let source: Source - - let dependentKeys: Set? - - public init(data: Data?, - extensions: [String: Any]?, - errors: [GraphQLError]?, - source: Source, - dependentKeys: Set?) { - self.data = data - self.extensions = extensions - self.errors = errors - self.source = source - self.dependentKeys = dependentKeys - } -} diff --git a/Sources/Apollo/GraphQLResultAccumulator.swift b/Sources/Apollo/GraphQLResultAccumulator.swift deleted file mode 100644 index 361f41907d..0000000000 --- a/Sources/Apollo/GraphQLResultAccumulator.swift +++ /dev/null @@ -1,110 +0,0 @@ -protocol GraphQLResultAccumulator: AnyObject { - associatedtype PartialResult - associatedtype FieldEntry - associatedtype ObjectResult - associatedtype FinalResult - - func accept(scalar: JSONValue, info: GraphQLResolveInfo) throws -> PartialResult - func acceptNullValue(info: GraphQLResolveInfo) throws -> PartialResult - func accept(list: [PartialResult], info: GraphQLResolveInfo) throws -> PartialResult - - func accept(fieldEntry: PartialResult, info: GraphQLResolveInfo) throws -> FieldEntry - func accept(fieldEntries: [FieldEntry], info: GraphQLResolveInfo) throws -> ObjectResult - - func finish(rootValue: ObjectResult, info: GraphQLResolveInfo) throws -> FinalResult -} - -func zip(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2) -> Zip2Accumulator { - return Zip2Accumulator(accumulator1, accumulator2) -} - -func zip(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2, _ accumulator3: Accumulator3) -> Zip3Accumulator { - return Zip3Accumulator(accumulator1, accumulator2, accumulator3) -} - -final class Zip2Accumulator: GraphQLResultAccumulator { - typealias PartialResult = (Accumulator1.PartialResult, Accumulator2.PartialResult) - typealias FieldEntry = (Accumulator1.FieldEntry, Accumulator2.FieldEntry) - typealias ObjectResult = (Accumulator1.ObjectResult, Accumulator2.ObjectResult) - typealias FinalResult = (Accumulator1.FinalResult, Accumulator2.FinalResult) - - private let accumulator1: Accumulator1 - private let accumulator2: Accumulator2 - - fileprivate init(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2) { - self.accumulator1 = accumulator1 - self.accumulator2 = accumulator2 - } - - func accept(scalar: JSONValue, info: GraphQLResolveInfo) throws -> PartialResult { - return (try accumulator1.accept(scalar: scalar, info: info), try accumulator2.accept(scalar: scalar, info: info)) - } - - func acceptNullValue(info: GraphQLResolveInfo) throws -> PartialResult { - return (try accumulator1.acceptNullValue(info: info), try accumulator2.acceptNullValue(info: info)) - } - - func accept(list: [PartialResult], info: GraphQLResolveInfo) throws -> PartialResult { - let (list1, list2) = unzip(list) - return (try accumulator1.accept(list: list1, info: info), try accumulator2.accept(list: list2, info: info)) - } - - func accept(fieldEntry: PartialResult, info: GraphQLResolveInfo) throws -> FieldEntry { - return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info), try accumulator2.accept(fieldEntry: fieldEntry.1, info: info)) - } - - func accept(fieldEntries: [FieldEntry], info: GraphQLResolveInfo) throws -> ObjectResult { - let (fieldEntries1, fieldEntries2) = unzip(fieldEntries) - return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info), try accumulator2.accept(fieldEntries: fieldEntries2, info: info)) - } - - func finish(rootValue: ObjectResult, info: GraphQLResolveInfo) throws -> FinalResult { - return (try accumulator1.finish(rootValue: rootValue.0, info: info), try accumulator2.finish(rootValue: rootValue.1, info: info)) - } -} - -final class Zip3Accumulator: GraphQLResultAccumulator { - typealias PartialResult = (Accumulator1.PartialResult, Accumulator2.PartialResult, Accumulator3.PartialResult) - typealias FieldEntry = (Accumulator1.FieldEntry, Accumulator2.FieldEntry, Accumulator3.FieldEntry) - typealias ObjectResult = (Accumulator1.ObjectResult, Accumulator2.ObjectResult, Accumulator3.ObjectResult) - typealias FinalResult = (Accumulator1.FinalResult, Accumulator2.FinalResult, Accumulator3.FinalResult) - - private let accumulator1: Accumulator1 - private let accumulator2: Accumulator2 - private let accumulator3: Accumulator3 - - - fileprivate init(_ accumulator1: Accumulator1, - _ accumulator2: Accumulator2, - _ accumulator3: Accumulator3) { - self.accumulator1 = accumulator1 - self.accumulator2 = accumulator2 - self.accumulator3 = accumulator3 - } - - func accept(scalar: JSONValue, info: GraphQLResolveInfo) throws -> PartialResult { - return (try accumulator1.accept(scalar: scalar, info: info), try accumulator2.accept(scalar: scalar, info: info), try accumulator3.accept(scalar: scalar, info: info)) - } - - func acceptNullValue(info: GraphQLResolveInfo) throws -> PartialResult { - return (try accumulator1.acceptNullValue(info: info), try accumulator2.acceptNullValue(info: info), try accumulator3.acceptNullValue(info: info)) - } - - func accept(list: [PartialResult], info: GraphQLResolveInfo) throws -> PartialResult { - let (list1, list2, list3) = unzip(list) - return (try accumulator1.accept(list: list1, info: info), try accumulator2.accept(list: list2, info: info), try accumulator3.accept(list: list3, info: info)) - } - - func accept(fieldEntry: PartialResult, info: GraphQLResolveInfo) throws -> FieldEntry { - return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info), try accumulator2.accept(fieldEntry: fieldEntry.1, info: info), try accumulator3.accept(fieldEntry: fieldEntry.2, info: info)) - } - - func accept(fieldEntries: [FieldEntry], info: GraphQLResolveInfo) throws -> ObjectResult { - let (fieldEntries1, fieldEntries2, fieldEntries3) = unzip(fieldEntries) - return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info), try accumulator2.accept(fieldEntries: fieldEntries2, info: info), try accumulator3.accept(fieldEntries: fieldEntries3, info: info)) - } - - func finish(rootValue: ObjectResult, info: GraphQLResolveInfo) throws -> FinalResult { - return (try accumulator1.finish(rootValue: rootValue.0, info: info), try accumulator2.finish(rootValue: rootValue.1, info: info), try accumulator3.finish(rootValue: rootValue.2, info: info)) - } -} diff --git a/Sources/Apollo/GraphQLResultNormalizer.swift b/Sources/Apollo/GraphQLResultNormalizer.swift deleted file mode 100644 index 0326f9832b..0000000000 --- a/Sources/Apollo/GraphQLResultNormalizer.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Foundation - -final class GraphQLResultNormalizer: GraphQLResultAccumulator { - private var records: RecordSet = [:] - - func accept(scalar: JSONValue, info: GraphQLResolveInfo) -> JSONValue { - return scalar - } - - func acceptNullValue(info: GraphQLResolveInfo) -> JSONValue { - return NSNull() - } - - func accept(list: [JSONValue], info: GraphQLResolveInfo) -> JSONValue { - return list - } - - func accept(fieldEntry: JSONValue, info: GraphQLResolveInfo) -> (key: String, value: JSONValue) { - return (info.cacheKeyForField, fieldEntry) - } - - func accept(fieldEntries: [(key: String, value: JSONValue)], info: GraphQLResolveInfo) throws -> JSONValue { - let cachePath = info.cachePath.joined - - let object = JSONObject(fieldEntries, uniquingKeysWith: { (_, last) in last }) - records.merge(record: Record(key: cachePath, object)) - - return CacheReference(key: cachePath) - } - - func finish(rootValue: JSONValue, info: GraphQLResolveInfo) throws -> RecordSet { - return records - } -} diff --git a/Sources/Apollo/GraphQLSelectionSet.swift b/Sources/Apollo/GraphQLSelectionSet.swift deleted file mode 100644 index 779a1a62af..0000000000 --- a/Sources/Apollo/GraphQLSelectionSet.swift +++ /dev/null @@ -1,160 +0,0 @@ -#if !COCOAPODS -import ApolloAPI -#endif - -public typealias ResultMap = [String: Any?] - -public protocol GraphQLSelectionSet { - static var selections: [GraphQLSelection] { get } - - var resultMap: ResultMap { get } - init(unsafeResultMap: ResultMap) -} - -public extension GraphQLSelectionSet { - init(jsonObject: JSONObject, variables: GraphQLMap? = nil) throws { - self = try decode(selectionSet: Self.self, - from: jsonObject, - variables: variables) - } - - var jsonObject: JSONObject { - return resultMap.jsonObject - } -} - -extension GraphQLSelectionSet { - public init(_ selectionSet: GraphQLSelectionSet) throws { - try self.init(jsonObject: selectionSet.jsonObject) - } -} - -/// For backwards compatibility with legacy codegen. -/// The `GraphQLVariable` class has been replaced by `InputValue.variable` -public func GraphQLVariable(_ name: String) -> InputValue { - return .variable(name) -} - -public protocol GraphQLSelection { -} - -public struct GraphQLField: GraphQLSelection { - let name: String - let alias: String? - let arguments: FieldArguments? - - var responseKey: String { - return alias ?? name - } - - let type: GraphQLOutputType - - public init(_ name: String, - alias: String? = nil, - arguments: FieldArguments? = nil, - type: GraphQLOutputType) { - self.name = name - self.alias = alias - - self.arguments = arguments - - self.type = type - } - - public func cacheKey(with variables: [String: JSONEncodable]?) throws -> String { - if - let argumentValues = try arguments?.evaluate(with: variables), - argumentValues.apollo.isNotEmpty { - let argumentsKey = orderIndependentKey(for: argumentValues) - return "\(name)(\(argumentsKey))" - } else { - return name - } - } -} - -public struct FieldArguments: ExpressibleByDictionaryLiteral { - let arguments: InputValue - - public init(dictionaryLiteral elements: (String, InputValue)...) { - arguments = .object(Dictionary(elements, uniquingKeysWith: { (_, last) in last })) - } - - public func evaluate(with variables: [String: JSONEncodable]?) throws -> JSONValue { - return try arguments.evaluate(with: variables) - } - - public func evaluate(with variables: [String: JSONEncodable]?) throws -> JSONObject { - return try arguments.evaluate(with: variables) as! JSONObject - } -} - -public indirect enum GraphQLOutputType { - case scalar(JSONDecodable.Type) - case object([GraphQLSelection]) - case nonNull(GraphQLOutputType) - case list(GraphQLOutputType) - - var namedType: GraphQLOutputType { - switch self { - case .nonNull(let innerType), .list(let innerType): - return innerType.namedType - case .scalar, .object: - return self - } - } -} - -private func orderIndependentKey(for object: JSONObject) -> String { - return object.sorted { $0.key < $1.key }.map { - if let object = $0.value as? JSONObject { - return "[\($0.key):\(orderIndependentKey(for: object))]" - } else if let array = $0.value as? [JSONObject] { - return "\($0.key):[\(array.map { orderIndependentKey(for: $0) }.joined(separator: ","))]" - } else { - return "\($0.key):\($0.value)" - } - }.joined(separator: ",") -} - -public struct GraphQLBooleanCondition: GraphQLSelection { - let variableName: String - let inverted: Bool - let selections: [GraphQLSelection] - - public init(variableName: String, - inverted: Bool, - selections: [GraphQLSelection]) { - self.variableName = variableName - self.inverted = inverted; - self.selections = selections; - } -} - -public struct GraphQLTypeCondition: GraphQLSelection { - let possibleTypes: [String] - let selections: [GraphQLSelection] - - public init(possibleTypes: [String], selections: [GraphQLSelection]) { - self.possibleTypes = possibleTypes - self.selections = selections; - } -} - -public struct GraphQLFragmentSpread: GraphQLSelection { - let fragment: GraphQLFragment.Type - - public init(_ fragment: GraphQLFragment.Type) { - self.fragment = fragment - } -} - -public struct GraphQLTypeCase: GraphQLSelection { - let variants: [String: [GraphQLSelection]] - let `default`: [GraphQLSelection] - - public init(variants: [String: [GraphQLSelection]], default: [GraphQLSelection]) { - self.variants = variants - self.default = `default`; - } -} diff --git a/Sources/Apollo/GraphQLSelectionSetMapper.swift b/Sources/Apollo/GraphQLSelectionSetMapper.swift deleted file mode 100644 index 9a5eea2995..0000000000 --- a/Sources/Apollo/GraphQLSelectionSetMapper.swift +++ /dev/null @@ -1,27 +0,0 @@ -final class GraphQLSelectionSetMapper: GraphQLResultAccumulator { - func accept(scalar: JSONValue, info: GraphQLResolveInfo) throws -> Any? { - guard case .scalar(let decodable) = info.fields[0].type.namedType else { preconditionFailure() } - // This will convert a JSON value to the expected value type, which could be a custom scalar or an enum. - return try decodable.init(jsonValue: scalar) - } - - func acceptNullValue(info: GraphQLResolveInfo) -> Any? { - return nil - } - - func accept(list: [Any?], info: GraphQLResolveInfo) -> Any? { - return list - } - - func accept(fieldEntry: Any?, info: GraphQLResolveInfo) -> (key: String, value: Any?) { - return (info.responseKeyForField, fieldEntry) - } - - func accept(fieldEntries: [(key: String, value: Any?)], info: GraphQLResolveInfo) throws -> ResultMap { - return ResultMap(fieldEntries, uniquingKeysWith: { (_, last) in last }) - } - - func finish(rootValue: ResultMap, info: GraphQLResolveInfo) -> SelectionSet { - return SelectionSet.init(unsafeResultMap: rootValue) - } -} diff --git a/Sources/Apollo/GroupedSequence.swift b/Sources/Apollo/GroupedSequence.swift deleted file mode 100644 index 94d91c1f46..0000000000 --- a/Sources/Apollo/GroupedSequence.swift +++ /dev/null @@ -1,41 +0,0 @@ -struct GroupedSequence { - private(set) var keys: [Key] = [] - fileprivate var groupsForKeys: [[Value]] = [] - - mutating func append(value: Value, forKey key: Key) -> (Int, Int) { - if let index = keys.firstIndex(where: { $0 == key }) { - groupsForKeys[index].append(value) - return (index, groupsForKeys[index].endIndex - 1) - } else { - keys.append(key) - groupsForKeys.append([value]) - return (keys.endIndex - 1, 0) - } - } -} - -extension GroupedSequence: Sequence { - func makeIterator() -> GroupedSequenceIterator { - return GroupedSequenceIterator(base: self) - } -} - -struct GroupedSequenceIterator: IteratorProtocol { - private var base: GroupedSequence - - private var keyIterator: EnumeratedSequence>.Iterator - - init(base: GroupedSequence) { - self.base = base - keyIterator = base.keys.enumerated().makeIterator() - } - - mutating func next() -> (Key, [Value])? { - if let (index, key) = keyIterator.next() { - let values = base.groupsForKeys[index] - return (key, values) - } else { - return nil - } - } -} diff --git a/Sources/Apollo/HTTPURLResponse+Helpers.swift b/Sources/Apollo/HTTPURLResponse+Helpers.swift deleted file mode 100644 index 00616ce689..0000000000 --- a/Sources/Apollo/HTTPURLResponse+Helpers.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -#if !COCOAPODS -import ApolloUtils -#endif - -extension HTTPURLResponse: ApolloCompatible {} - -extension ApolloExtension where Base == HTTPURLResponse { - var isSuccessful: Bool { - return (200..<300).contains(base.statusCode) - } - - var statusCodeDescription: String { - return HTTPURLResponse.localizedString(forStatusCode: base.statusCode) - } -} diff --git a/Sources/Apollo/Info.plist b/Sources/Apollo/Info.plist deleted file mode 100644 index 0e600e67e7..0000000000 --- a/Sources/Apollo/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/Apollo/InputValue+Evaluation.swift b/Sources/Apollo/InputValue+Evaluation.swift deleted file mode 100644 index 2e73474463..0000000000 --- a/Sources/Apollo/InputValue+Evaluation.swift +++ /dev/null @@ -1,54 +0,0 @@ -#if !COCOAPODS -import ApolloAPI -#endif -import Foundation - -extension InputValue { - func evaluate(with variables: [String: JSONEncodable]?) throws -> JSONValue { - switch self { - case .scalar(let scalar as JSONEncodable): - return scalar.jsonValue - - case .scalar(let scalar): - throw GraphQLError("Scalar value \(scalar) is not JSONEncodable.") - - case .variable(let name): - guard let value = variables?[name] else { - throw GraphQLError("Variable \(name) was not provided.") - } - return value.jsonValue - - case .list(let array): - return try evaluate(values: array, with: variables) - - case .object(let dictionary): - return try evaluate(values: dictionary, with: variables) - - case .none: - return NSNull() - } - } - - private func evaluate(values: [InputValue], with variables: [String: JSONEncodable]?) throws -> JSONValue { - return try evaluate(values: values, with: variables) as [JSONValue] - } - - private func evaluate(values: [InputValue], with variables: [String: JSONEncodable]?) throws -> [JSONValue] { - try values.map { try $0.evaluate(with: variables) } - } - - private func evaluate(values: [String: InputValue], with variables: [String: JSONEncodable]?) throws -> JSONValue { - return try evaluate(values: values, with: variables) as JSONObject - } - - private func evaluate(values: [String: InputValue], with variables: [String: JSONEncodable]?) throws -> JSONObject { - var jsonObject = JSONObject(minimumCapacity: values.count) - for (key, value) in values { - let evaluatedValue = try value.evaluate(with: variables) - if !(evaluatedValue is NSNull) { - jsonObject[key] = evaluatedValue - } - } - return jsonObject - } -} diff --git a/Sources/Apollo/JSON.swift b/Sources/Apollo/JSON.swift deleted file mode 100644 index 49c8b8c6c0..0000000000 --- a/Sources/Apollo/JSON.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation - -public typealias JSONValue = Any - -public typealias JSONObject = [String: JSONValue] - -public protocol JSONDecodable { - init(jsonValue value: JSONValue) throws -} - -public protocol JSONEncodable { - var jsonValue: JSONValue { get } -} - -public enum JSONDecodingError: Error, LocalizedError { - case missingValue - case nullValue - case wrongType - case couldNotConvert(value: Any, to: Any.Type) - - public var errorDescription: String? { - switch self { - case .missingValue: - return "Missing value" - case .nullValue: - return "Unexpected null value" - case .wrongType: - return "Wrong type" - case .couldNotConvert(let value, let expectedType): - return "Could not convert \"\(value)\" to \(expectedType)" - } - } -} - -// MARK: Helpers - -public struct JSONValueMatcher { - - public static func equals(_ lhs: Any, _ rhs: Any) -> Bool { - if let lhs = lhs as? CacheReference, let rhs = rhs as? CacheReference { - return lhs == rhs - } - - if let lhs = lhs as? Array, let rhs = rhs as? Array { - return lhs == rhs - } - - let lhs = lhs as AnyObject, rhs = rhs as AnyObject - return lhs.isEqual(rhs) - } - -} diff --git a/Sources/Apollo/JSONStandardTypeConversions.swift b/Sources/Apollo/JSONStandardTypeConversions.swift deleted file mode 100644 index 2ead5a9a63..0000000000 --- a/Sources/Apollo/JSONStandardTypeConversions.swift +++ /dev/null @@ -1,180 +0,0 @@ -import Foundation - -extension String: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - switch value { - case let string as String: - self = string - case let int as Int: - self = String(int) - default: - throw JSONDecodingError.couldNotConvert(value: value, to: String.self) - } - } - - public var jsonValue: JSONValue { - return self - } -} - -extension Int: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - guard let number = value as? NSNumber else { - throw JSONDecodingError.couldNotConvert(value: value, to: Int.self) - } - self = number.intValue - } - - public var jsonValue: JSONValue { - return self - } -} - -extension Float: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - guard let number = value as? NSNumber else { - throw JSONDecodingError.couldNotConvert(value: value, to: Float.self) - } - self = number.floatValue - } - - public var jsonValue: JSONValue { - return self - } -} - -extension Double: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - guard let number = value as? NSNumber else { - throw JSONDecodingError.couldNotConvert(value: value, to: Double.self) - } - self = number.doubleValue - } - - public var jsonValue: JSONValue { - return self - } -} - -extension Bool: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - guard let bool = value as? Bool else { - throw JSONDecodingError.couldNotConvert(value: value, to: Bool.self) - } - self = bool - } - - public var jsonValue: JSONValue { - return self - } -} - -extension RawRepresentable where RawValue: JSONDecodable { - public init(jsonValue value: JSONValue) throws { - let rawValue = try RawValue(jsonValue: value) - if let tempSelf = Self(rawValue: rawValue) { - self = tempSelf - } else { - throw JSONDecodingError.couldNotConvert(value: value, to: Self.self) - } - } -} - -extension RawRepresentable where RawValue: JSONEncodable { - public var jsonValue: JSONValue { - return rawValue.jsonValue - } -} - -extension Optional where Wrapped: JSONDecodable { - public init(jsonValue value: JSONValue) throws { - if value is NSNull { - self = .none - } else { - self = .some(try Wrapped(jsonValue: value)) - } - } -} - -// Once [conditional conformances](https://github.com/apple/swift-evolution/blob/master/proposals/0143-conditional-conformances.md) have been implemented, we should be able to replace these runtime type checks with proper static typing - -extension Optional: JSONEncodable { - public var jsonValue: JSONValue { - switch self { - case .none: - return NSNull() - case .some(let wrapped as JSONEncodable): - return wrapped.jsonValue - default: - fatalError("Optional is only JSONEncodable if Wrapped is") - } - } -} - -extension NSDictionary: JSONEncodable { - public var jsonValue: JSONValue { self } -} - -extension NSNull: JSONEncodable { - public var jsonValue: JSONValue { self } -} - -extension Dictionary: JSONEncodable { - public var jsonValue: JSONValue { - return jsonObject - } - - public var jsonObject: JSONObject { - var jsonObject = JSONObject(minimumCapacity: count) - for (key, value) in self { - if case let (key as String, value as JSONEncodable) = (key, value) { - jsonObject[key] = value.jsonValue - } else { - fatalError("Dictionary is only JSONEncodable if Value is (and if Key is String)") - } - } - return jsonObject - } -} - -extension Dictionary: JSONDecodable { - public init(jsonValue value: JSONValue) throws { - guard let dictionary = value as? Dictionary else { - throw JSONDecodingError.couldNotConvert(value: value, to: Dictionary.self) - } - - self = dictionary - } -} - -extension Array: JSONEncodable { - public var jsonValue: JSONValue { - return map { element -> JSONValue in - if case let element as JSONEncodable = element { - return element.jsonValue - } else { - fatalError("Array is only JSONEncodable if Element is") - } - } - } -} - -// Example custom scalar - -extension URL: JSONDecodable, JSONEncodable { - public init(jsonValue value: JSONValue) throws { - guard let string = value as? String else { - throw JSONDecodingError.couldNotConvert(value: value, to: URL.self) - } - - if let url = URL(string: string) { - self = url - } else { - throw JSONDecodingError.couldNotConvert(value: value, to: URL.self) - } - } - - public var jsonValue: JSONValue { - return self.absoluteString - } -} diff --git a/Sources/Apollo/RequestBodyCreator.swift b/Sources/Apollo/RequestBodyCreator.swift deleted file mode 100644 index 2692c2d4cf..0000000000 --- a/Sources/Apollo/RequestBodyCreator.swift +++ /dev/null @@ -1,64 +0,0 @@ -import Foundation -#if !COCOAPODS -import ApolloUtils -#endif - -public protocol RequestBodyCreator { - /// Creates a `GraphQLMap` out of the passed-in operation - /// - /// - Parameters: - /// - operation: The operation to use - /// - sendOperationIdentifiers: Whether or not to send operation identifiers. Should default to `false`. - /// - sendQueryDocument: Whether or not to send the full query document. Should default to `true`. - /// - autoPersistQuery: Whether to use auto-persisted query information. Should default to `false`. - /// - Returns: The created `GraphQLMap` - func requestBody(for operation: Operation, - sendOperationIdentifiers: Bool, - sendQueryDocument: Bool, - autoPersistQuery: Bool) -> GraphQLMap -} - -// MARK: - Default Implementation - -extension RequestBodyCreator { - - public func requestBody(for operation: Operation, - sendOperationIdentifiers: Bool, - sendQueryDocument: Bool, - autoPersistQuery: Bool) -> GraphQLMap { - var body: GraphQLMap = [ - "variables": operation.variables, - "operationName": operation.operationName, - ] - - if sendOperationIdentifiers { - guard let operationIdentifier = operation.operationIdentifier else { - preconditionFailure("To send operation identifiers, Apollo types must be generated with operationIdentifiers") - } - - body["id"] = operationIdentifier - } - - if sendQueryDocument { - body["query"] = operation.queryDocument - } - - if autoPersistQuery { - guard let operationIdentifier = operation.operationIdentifier else { - preconditionFailure("To enable `autoPersistQueries`, Apollo types must be generated with operationIdentifiers") - } - - body["extensions"] = [ - "persistedQuery" : ["sha256Hash": operationIdentifier, "version": 1] - ] - } - - return body - } -} - -// Helper struct to create requests independently of HTTP operations. -public struct ApolloRequestBodyCreator: RequestBodyCreator { - // Internal init methods cannot be used in public methods - public init() { } -} diff --git a/Sources/Apollo/ResponsePath.swift b/Sources/Apollo/ResponsePath.swift deleted file mode 100644 index 286f7cfc57..0000000000 --- a/Sources/Apollo/ResponsePath.swift +++ /dev/null @@ -1,56 +0,0 @@ -/// A response path is stored as a linked list because using an array turned out to be -/// a performance bottleneck during decoding/execution. -struct ResponsePath: ExpressibleByArrayLiteral { - typealias Key = String - - private final class Node { - let previous: Node? - let key: Key - - init(previous: Node?, key: Key) { - self.previous = previous - self.key = key - } - - lazy var joined: String = { - if let previous = previous { - return previous.joined + ".\(key)" - } else { - return key - } - }() - } - - private var head: Node? - var joined: String { - return head?.joined ?? "" - } - - init(arrayLiteral segments: Key...) { - for segment in segments { - append(segment) - } - } - - mutating func append(_ key: Key) { - head = Node(previous: head, key: key) - } - - static func + (lhs: ResponsePath, rhs: Key) -> ResponsePath { - var lhs = lhs - lhs.append(rhs) - return lhs - } -} - -extension ResponsePath: CustomStringConvertible { - var description: String { - return joined - } -} - -extension ResponsePath: Equatable { - static func == (lhs: ResponsePath, rhs: ResponsePath) -> Bool { - return lhs.joined == rhs.joined - } -} diff --git a/Sources/ApolloAPI/AnyHashableConvertible.swift b/Sources/ApolloAPI/AnyHashableConvertible.swift new file mode 100644 index 0000000000..4325c1684b --- /dev/null +++ b/Sources/ApolloAPI/AnyHashableConvertible.swift @@ -0,0 +1,26 @@ +/// A helper protocol to enable `AnyHashable` conversion for types that do not have automatic +/// `AnyHashable` conversion implemented. +/// +/// For most types that conform to `Hashable`, Swift automatically wraps them in an `AnyHashable` +/// when they are cast to or stored in a property of the `AnyHashable` type. This does not happen +/// automatically for containers with conditional `Hashable` conformance such as +/// `Optional`, `Array`, and `Dictionary`. +public protocol AnyHashableConvertible { + /// Converts the type to an `AnyHashable`. + var _asAnyHashable: AnyHashable { get } +} + +extension AnyHashableConvertible where Self: Hashable { + /// Converts the type to an `AnyHashable` by casting self. + /// + /// This utilizes Swift's automatic `AnyHashable` conversion functionality. + @inlinable public var _asAnyHashable: AnyHashable { self } +} + +extension AnyHashable: AnyHashableConvertible {} + +extension Optional: AnyHashableConvertible where Wrapped: Hashable {} + +extension Dictionary: AnyHashableConvertible where Key: Hashable, Value: Hashable {} + +extension Array: AnyHashableConvertible where Element: Hashable {} diff --git a/Sources/ApolloAPI/CacheKeyInfo.swift b/Sources/ApolloAPI/CacheKeyInfo.swift new file mode 100644 index 0000000000..a4a819d91d --- /dev/null +++ b/Sources/ApolloAPI/CacheKeyInfo.swift @@ -0,0 +1,119 @@ +/// Contains the information needed to resolve a ``CacheReference`` in a `NormalizedCache`. +/// +/// You can create and return a ``CacheKeyInfo`` from your implementation of the +/// ``SchemaConfiguration/cacheKeyInfo(for:object:)`` function to configure the cache key +/// resolution for the types in the schema, which is used by `NormalizedCache` mechanisms. +/// +/// ## Cache Key Resolution +/// You can use the ``init(jsonValue:uniqueKeyGroup:)`` convenience initializer in the +/// implementation of your ``SchemaConfiguration/cacheKeyInfo(for:object:)`` function to +/// easily resolve the cache key for an object. +/// +/// For an object of the type `Dog` with a unique id represented by an `id` field, you may +/// implement cache key resolution with: +/// ```swift +/// enum SchemaConfiguration: ApolloAPI.SchemaConfiguration { +/// static func cacheKeyInfo(for type: Object, object: JSONObject) -> CacheKeyInfo? { +/// switch type { +/// case Objects.Dog: +/// return try? CacheKeyInfo(jsonValue: object["id"]) +/// default: +/// return nil +/// } +/// } +/// } +/// ``` +/// +/// ### Resolving Cache Keys by Interfaces +/// If you have multiple objects that conform to an ``Interface`` with the same cache id resolution +/// strategy, you can resolve the id based on the ``Interface``. +/// +/// For example, for a schema with `Dog` and `Cat` ``Object`` types that implement a `Pet` +/// ``Interface``, you may implement cache key resolution with: +/// ```swift +/// enum SchemaConfiguration: ApolloAPI.SchemaConfiguration { +/// static func cacheKeyInfo(for type: Object, object: JSONObject) -> CacheKeyInfo? { +/// if type.implements(Interfaces.Pet) { +/// return try? CacheKeyInfo(jsonValue: object["id"]) +/// } +/// +/// return nil +/// } +/// } +/// ``` +/// +/// ### Grouping Cached Objects by Interfaces +/// If your keys are guaranteed to be unique across all ``Object`` types that implement an +/// ``Interface``, you may want to group them together in the cache. See ``uniqueKeyGroup`` for +/// more information on the benefits of grouping cached objects. +/// ```swift +/// enum SchemaConfiguration: ApolloAPI.SchemaConfiguration { +/// static func cacheKeyInfo(for type: Object, object: JSONObject) -> CacheKeyInfo? { +/// if type.implements(Interfaces.Pet) { +/// return try? CacheKeyInfo(jsonValue: object["id"], uniqueKeyGroup: Interfaces.Pet.name) +/// } +/// +/// return nil +/// } +/// } +/// ``` +public struct CacheKeyInfo { + /// The unique cache id for the response object for the ``CacheKeyInfo``. + /// + /// > Important: The ``id`` must be deterministic and unique for all objects with the same + /// ``Object/typename`` or ``uniqueKeyGroup``. That is, the ``id`` will be the same + /// every time for a response object representing the same entity in the `NormalizedCache` and + /// the same ``id`` will never be used for reponse objects representing different objects that + /// also have the same ``Object/typename`` or ``uniqueKeyGroup``. + public let id: String + + /// An optional identifier for a group of objects that should be grouped together in the + /// `NormalizedCache`. + /// + /// By default, objects are grouped in the `NormalizedCache` by their ``Object/typename``. If + /// multiple distinct types can be grouped together in the cache, the ``CacheKeyInfo`` for each + /// ``Object`` should have the same ``uniqueKeyGroup``. + /// + /// > Tip: By grouping objects together, their resolved keys in the `NormalizedCache` will have the + /// same prefix. This allows you to search for cached objects in the same group by their cache + /// key. + /// + /// In the future ``uniqueKeyGroup``s may be used for more advanced cache optimizations + /// and operations. + /// + /// > Important: All objects with the same ``uniqueKeyGroup`` must have unique `key`s across all + /// types. + public let uniqueKeyGroup: String? + + /// A convenience initializer for creating a ``CacheKeyInfo`` from the value of a field on a + /// ``JSONObject`` dictionary representing a GraphQL response object. + /// + /// This function reads the value of the provided field, converting it to a `String` suitable + /// for use as a cache ``id``. + /// + /// - Throws: A `JSONDecodingError` if the `jsonValue` provided is `nil`. + /// + /// - Parameters: + /// - jsonValue: The value of a field on a ``JSONObject`` to use as the cache ``id``. + /// This must be a scalar type to be used as a cache id. + /// - uniqueKeyGroup: An optional ``uniqueKeyGroup`` for the ``CacheKeyInfo``. + /// Defaults to `nil`. + @inlinable public init(jsonValue: (any ScalarType)?, uniqueKeyGroup: String? = nil) throws { + guard let jsonValue = jsonValue else { + throw JSONDecodingError.missingValue + } + + self.init(id: try String(_jsonValue: jsonValue._asAnyHashable), uniqueKeyGroup: uniqueKeyGroup) + } + + /// The Designated Initializer + /// + /// - Parameters: + /// - id: The unique cache key for the response object for the ``CacheKeyInfo``. + /// - uniqueKeyGroup: An optional identifier for a group of objects that should be grouped + /// together in the `NormalizedCache`. + public init(id: String, uniqueKeyGroup: String? = nil) { + self.id = id + self.uniqueKeyGroup = uniqueKeyGroup + } +} diff --git a/Sources/ApolloAPI/CacheReference.swift b/Sources/ApolloAPI/CacheReference.swift new file mode 100644 index 0000000000..abad8c8513 --- /dev/null +++ b/Sources/ApolloAPI/CacheReference.swift @@ -0,0 +1,74 @@ +/// Represents a reference to a record for a GraphQL object in the cache. +/// +/// ``CacheReference`` is just a wrapper around a `String`. But when the value for a key in a cache +/// `Record` is a `String`, we treat the string as the value. When the value for the key is a +/// ``CacheReference``, the reference's ``key`` is the cache key for another referenced object +/// that is the value. +public struct CacheReference: Hashable { + + /// A CacheReference referencing the root query object. + public static let RootQuery: CacheReference = CacheReference("QUERY_ROOT") + + /// A CacheReference referencing the root mutation object. + public static let RootMutation: CacheReference = CacheReference("MUTATION_ROOT") + + /// A CacheReference referencing the root subscription object. + public static let RootSubscription: CacheReference = CacheReference("SUBSCRIPTION_ROOT") + + /// Helper function that returns the cache's root ``CacheReference`` for the given + /// ``GraphQLOperationType``. + /// + /// The Apollo `NormalizedCache` stores all objects that are not normalized + /// (ie. don't have a unique cache key provided by the ``SchemaConfiguration``) + /// with a ``CacheReference`` computed as the field path to the object from + /// the root of the parent operation type. + /// + /// For example, given the operation: + /// ```graphql + /// query { + /// animals { + /// owner { + /// name + /// } + /// } + /// } + /// ``` + /// The ``CacheReference`` for the `owner` object of the third animal in the `animals` list would + /// have a ``CacheReference/key`` of `"QUERY_ROOT.animals.2.owner`. + /// + /// - Parameter operationType: A ``GraphQLOperationType`` + /// - Returns: The cache's root ``CacheReference`` for the given ``GraphQLOperationType`` + public static func rootCacheReference( + for operationType: GraphQLOperationType + ) -> CacheReference { + switch operationType { + case .query: + return RootQuery + case .mutation: + return RootMutation + case .subscription: + return RootSubscription + } + } + + /// The unique identifier for the referenced object. + /// + /// # See Also + /// ``CacheKeyInfo`` + public let key: String + + /// Designated Initializer + /// + /// - Parameters: + /// - key: The unique identifier for the referenced object. + public init(_ key: String) { + self.key = key + } + +} + +extension CacheReference: CustomStringConvertible { + @inlinable public var description: String { + return "-> #\(key)" + } +} diff --git a/Sources/ApolloAPI/CodegenV1/FragmentProtocols.swift b/Sources/ApolloAPI/CodegenV1/FragmentProtocols.swift deleted file mode 100644 index 5049ad3969..0000000000 --- a/Sources/ApolloAPI/CodegenV1/FragmentProtocols.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ResponseDataProtocols.swift -// CodegenProposalFramework -// -// Created by Anthony Miller on 2/16/21. -// - -// MARK: - Fragment - -/// A protocol representing a fragment that a `ResponseObject` object may be converted to. -/// -/// A `ResponseObject` that conforms to `HasFragments` can be converted to -/// any `Fragment` included in it's `Fragments` object via its `fragments` property. -/// -/// - SeeAlso: `HasFragments`, `ToFragments` -public protocol Fragment: SelectionSet { } - -// MARK: - HasFragments - -/// A protocol that a `ResponseObject` that contains fragments should conform to. -public protocol HasFragments: SelectionSet { - - /// A type representing all of the fragments contained on the `ResponseObject`. - associatedtype Fragments: ResponseObject -} - -extension HasFragments { - /// A `FieldData` object that contains accessors for all of the fragments - /// the object can be converted to. - var fragments: Fragments { Fragments(data: data) } -} diff --git a/Sources/ApolloAPI/CodegenV1/GraphQLEnum.swift b/Sources/ApolloAPI/CodegenV1/GraphQLEnum.swift deleted file mode 100644 index 692fc5a95e..0000000000 --- a/Sources/ApolloAPI/CodegenV1/GraphQLEnum.swift +++ /dev/null @@ -1,82 +0,0 @@ -/// A generic enum that wraps a generated enum from a GraphQL Schema. -/// -/// `GraphQLEnum` provides an `__unknown` case that is used when the response returns a value that -/// is not recognized as a valid enum case. This is usually caused by future cases added to the enum -/// on the schema after code generation. -public enum GraphQLEnum: CaseIterable, Equatable, RawRepresentable -where T: RawRepresentable & CaseIterable, T.RawValue == String { - public typealias RawValue = String - - /// A recognized case of the wrapped enum. - case `case`(T) - - /// An unrecognized value for the enum. - /// The associated value exposes the raw `String` data from the response. - case __unknown(String) - - public init(_ caseValue: T) { - self = .case(caseValue) - } - - public init(rawValue: String) { - guard let caseValue = T(rawValue: rawValue) else { - self = .__unknown(rawValue) - return - } - self = .case(caseValue) - } - - /// The underlying enum case. If the value is `__unknown`, this will be `nil`. - public var value: T? { - switch self { - case .case(let value): return value - default: return nil - } - } - - public var rawValue: String { - switch self { - case .case(let value): return value.rawValue - case .__unknown(let value): return value - } - } - - /// A collection of all known values of the wrapped enum. - /// This collection does not include the `__unknown` case. - public static var allCases: [GraphQLEnum] { - return T.allCases.map { .case($0) } - } -} - -/// Equatable -extension GraphQLEnum { - public static func ==(lhs: GraphQLEnum, rhs: GraphQLEnum) -> Bool { - return lhs.rawValue == rhs.rawValue - } - - public static func ==(lhs: GraphQLEnum, rhs: T) -> Bool { - return lhs.rawValue == rhs.rawValue - } - - public static func !=(lhs: GraphQLEnum, rhs: T) -> Bool { - return lhs.rawValue != rhs.rawValue - } -} - -public func ==(lhs: GraphQLEnum?, rhs: T) -> Bool -where T.RawValue == String { - return lhs?.rawValue == rhs.rawValue -} - -public func !=(lhs: GraphQLEnum?, rhs: T) -> Bool -where T.RawValue == String { - return lhs?.rawValue != rhs.rawValue -} - -public func ~=(lhs: T, rhs: GraphQLEnum) -> Bool { - switch rhs { - case let .case(rhs) where rhs == lhs: return true - case let .__unknown(rhsRawValue) where rhsRawValue == lhs.rawValue: return true - default: return false - } -} diff --git a/Sources/ApolloAPI/CodegenV1/GraphQLOptional.swift b/Sources/ApolloAPI/CodegenV1/GraphQLOptional.swift deleted file mode 100644 index 7e756a56e8..0000000000 --- a/Sources/ApolloAPI/CodegenV1/GraphQLOptional.swift +++ /dev/null @@ -1,64 +0,0 @@ -import Foundation - -public enum GraphQLOptional { - case notPresent - case nullValue - case value(T) -} - -extension GraphQLOptional: Hashable where T: Hashable { - - public func hash(into hasher: inout Hasher) { - switch self { - case .notPresent, - .nullValue: - // no-op - break - case .value(let hashableType): - hashableType.hash(into: &hasher) - } - } -} - -extension GraphQLOptional: Equatable where T: Equatable { - public static func ==(lhs: GraphQLOptional, rhs: GraphQLOptional) -> Bool { - switch (lhs, rhs) { - case (.notPresent, .notPresent), - (.nullValue, .nullValue): - return true - case (.value(let lhsValue), .value(let rhsValue)): - return lhsValue == rhsValue - default: - return false - } - } -} - -public extension KeyedEncodingContainer { - - mutating func encodeGraphQLOptional(_ optional: GraphQLOptional, forKey key: K) throws { - switch optional { - case .notPresent: - break - case .nullValue: - try self.encodeNil(forKey: key) - case .value(let value): - try self.encode(value, forKey: key) - } - } -} - -public extension KeyedDecodingContainer { - - func decodeGraphQLOptional(forKey key: K) throws -> GraphQLOptional { - if self.contains(key) { - if let value = try? self.decode(T.self, forKey: key) { - return .value(value) - } else { - return .nullValue - } - } else { - return .notPresent - } - } -} diff --git a/Sources/ApolloAPI/CodegenV1/GraphQLSchema.swift b/Sources/ApolloAPI/CodegenV1/GraphQLSchema.swift deleted file mode 100644 index 34d73bd1f0..0000000000 --- a/Sources/ApolloAPI/CodegenV1/GraphQLSchema.swift +++ /dev/null @@ -1,32 +0,0 @@ -/// A protocol that a generated GraphQL Schema should conform to. -/// -/// A `GraphQLSchema` contains information on the types within a schema and their relationships -/// to other types. This information is used to verify that a `SelectionSet` can be converted to -/// a given type condition. -public protocol GraphQLSchema { - associatedtype ObjectType: SchemaObjectType where ObjectType.Interface == Self.Interface - associatedtype Union: SchemaUnion where Union.ObjectType == Self.ObjectType - associatedtype Interface -} - -public protocol SchemaTypeEnum: RawRepresentable, Equatable where RawValue == String {} - -public protocol SchemaObjectType: SchemaTypeEnum { - associatedtype Interface: SchemaTypeEnum - - static var unknownCase: Self { get } - - var implementedInterfaces: [Interface] { get } -} - -extension SchemaObjectType { - func implements(_ interface: Interface) -> Bool { - implementedInterfaces.contains(interface) - } -} - -public protocol SchemaUnion: SchemaTypeEnum { - associatedtype ObjectType - - var possibleTypes: [ObjectType] { get } -} diff --git a/Sources/ApolloAPI/CodegenV1/ResponseDict.swift b/Sources/ApolloAPI/CodegenV1/ResponseDict.swift deleted file mode 100644 index fd8d208754..0000000000 --- a/Sources/ApolloAPI/CodegenV1/ResponseDict.swift +++ /dev/null @@ -1,38 +0,0 @@ -/// A structure that wraps the underlying data dictionary used by `SelectionSet`s. -public struct ResponseDict { - - let data: [String: Any] - - public subscript(_ key: String) -> T { - data[key] as! T - } - - public subscript(_ key: String) -> T? { - data[key] as? T - } - - public subscript(_ key: String) -> T { - let entityData = data[key] as! [String: Any] - return T.init(data: ResponseDict(data: entityData)) - } - - public subscript(_ key: String) -> T? { - guard let entityData = data[key] as? [String: Any] else { return nil } - return T.init(data: ResponseDict(data: entityData)) - } - - public subscript(_ key: String) -> [T] { - let entityData = data[key] as! [[String: Any]] - return entityData.map { T.init(data: ResponseDict(data: $0)) } - } - - public subscript(_ key: String) -> GraphQLEnum { - let entityData = data[key] as! String - return GraphQLEnum(rawValue: entityData) - } - - public subscript(_ key: String) -> GraphQLEnum? { - guard let entityData = data[key] as? String else { return nil } - return GraphQLEnum(rawValue: entityData) - } -} diff --git a/Sources/ApolloAPI/CodegenV1/Selection.swift b/Sources/ApolloAPI/CodegenV1/Selection.swift deleted file mode 100644 index af6ab6a804..0000000000 --- a/Sources/ApolloAPI/CodegenV1/Selection.swift +++ /dev/null @@ -1,87 +0,0 @@ -import Foundation - -public enum Selection { - case field(Field) - case booleanCondition(BooleanCondition) - case typeCase(TypeCase) - case fragmentSpread(FragmentSpread) - - public struct Field { - let name: String - let alias: String? - let arguments: Arguments? - let type: OutputType - - var responseKey: String { - return alias ?? name - } - - public init(_ name: String, - alias: String? = nil, - arguments: Arguments? = nil, - type: OutputType) { - self.name = name - self.alias = alias - - self.arguments = arguments - - self.type = type - } - - public struct Arguments: ExpressibleByDictionaryLiteral { - let arguments: InputValue - - public init(dictionaryLiteral elements: (String, InputValue)...) { - arguments = .object(Dictionary(elements, uniquingKeysWith: { (_, last) in last })) - } - } - - public indirect enum OutputType { - case scalar(Any.Type) - case object([Selection]) - case nonNull(OutputType) - case list(OutputType) - - var namedType: OutputType { - switch self { - case .nonNull(let innerType), .list(let innerType): - return innerType.namedType - case .scalar, .object: - return self - } - } - } - } - - public struct BooleanCondition { - let variableName: String - let inverted: Bool - let selections: [Selection] - - public init(variableName: String, - inverted: Bool, - selections: [Selection]) { - self.variableName = variableName - self.inverted = inverted; - self.selections = selections; - } - } - - public struct FragmentSpread { - let fragment: AnySelectionSet.Type - - public init(_ fragment: AnySelectionSet.Type) { - self.fragment = fragment - } - } - - public struct TypeCase { - let variants: [String: [Selection]] - let `default`: [Selection] - - public init(variants: [String: [Selection]], default: [Selection]) { - self.variants = variants - self.default = `default`; - } - } -} diff --git a/Sources/ApolloAPI/CodegenV1/SelectionSet.swift b/Sources/ApolloAPI/CodegenV1/SelectionSet.swift deleted file mode 100644 index de7e3a4df5..0000000000 --- a/Sources/ApolloAPI/CodegenV1/SelectionSet.swift +++ /dev/null @@ -1,71 +0,0 @@ -public enum SelectionSetType { - case ObjectType(S.ObjectType) - case Interface(S.Interface) - case Union(S.Union) -} - -public protocol AnySelectionSet: ResponseObject { - static var selections: [Selection] { get } -} - -public protocol SelectionSet: ResponseObject, Equatable { - - associatedtype Schema: GraphQLSchema - - /// The GraphQL type for the `SelectionSet`. - /// - /// This may be a concrete type (`ConcreteType`) or an abstract type (`Interface`). - static var __parentType: SelectionSetType { get } -} - -extension SelectionSet { - - var __objectType: Schema.ObjectType { Schema.ObjectType(rawValue: __typename) ?? .unknownCase } - - var __typename: String { data["__typename"] } - - /// Verifies if a `SelectionSet` may be converted to a different `SelectionSet` and performs - /// the conversion. - /// - /// - Warning: This function is not supported for use outside of generated call sites. - /// Generated call sites are guaranteed by the GraphQL compiler to be safe. - /// Unsupported usage may result in unintended consequences including crashes. - func _asType() -> T? where T.Schema == Schema { - guard case let __objectType = __objectType, __objectType != .unknownCase else { return nil } - - switch T.__parentType { - case .ObjectType(let type): - guard __objectType == type else { return nil } - - case .Interface(let interface): - guard __objectType.implements(interface) else { return nil } - - case .Union(let union): - guard union.possibleTypes.contains(__objectType) else { return nil } - } - - return T.init(data: data) - } -} - -func ==(lhs: T, rhs: T) -> Bool { - return true // TODO: Unit test & implement this -} - -public protocol ResponseObject { - var data: ResponseDict { get } - - init(data: ResponseDict) -} - -extension ResponseObject { - - /// Converts a `SelectionSet` to a `Fragment` given a generic fragment type. - /// - /// - Warning: This function is not supported for use outside of generated call sites. - /// Generated call sites are guaranteed by the GraphQL compiler to be safe. - /// Unsupported usage may result in unintended consequences including crashes. - func _toFragment() -> T { - return T.init(data: data) - } -} diff --git a/Sources/ApolloAPI/DataDict.swift b/Sources/ApolloAPI/DataDict.swift new file mode 100644 index 0000000000..539ca45f52 --- /dev/null +++ b/Sources/ApolloAPI/DataDict.swift @@ -0,0 +1,246 @@ +import Foundation + +/// A structure that wraps the underlying data for a ``SelectionSet``. +public struct DataDict: Hashable { + @usableFromInline var _storage: _Storage + + /// The underlying data for a `SelectionSet`. + /// + /// - Warning: This is not identical to the JSON response from a GraphQL network request. + /// The data should be normalized for consumption by a ``SelectionSet``. This means: + /// + /// * Values for entity fields are represented by ``DataDict`` values + /// * Custom scalars are serialized and converted to their concrete types. + /// + /// The process of converting a JSON response into a ``SelectionSet`` is done by using a + /// `GraphQLExecutor` with a`GraphQLSelectionSetMapper`. This can be performed manually + /// by using `SelectionSet.init(data: JSONObject, variables: GraphQLOperation.Variables?)` in + /// the `Apollo` library. + @inlinable public var _data: [String: AnyHashable] { + get { _storage.data } + set { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _storage.copy() + } + _storage.data = newValue + } + _modify { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _storage.copy() + } + var data = _storage.data + defer { _storage.data = data } + yield &data + } + } + + /// The set of fragments types that are fulfilled by the data of the ``SelectionSet``. + /// + /// During GraphQL execution, the fragments which have had their selections executed are tracked. + /// This allows conversion of a ``SelectionSet`` to its fragment models to be done safely. + /// + /// Each `ObjectIdentifier` in the set corresponds to a specific `SelectionSet` type. + @inlinable public var _fulfilledFragments: Set { + _storage.fulfilledFragments + } + + @inlinable public var _deferredFragments: Set { + _storage.deferredFragments + } + + public init( + data: [String: AnyHashable], + fulfilledFragments: Set, + deferredFragments: Set = [] + ) { + self._storage = .init( + data: data, + fulfilledFragments: fulfilledFragments, + deferredFragments: deferredFragments + ) + } + + @inlinable public subscript(_ key: String) -> T { + get { + if DataDict._AnyHashableCanBeCoerced { + return _data[key] as! T + } else { + let value = _data[key] + if value == DataDict._NullValue { + return (Optional.none as Any) as! T + } else { + return (value?.base as? T) ?? (value._asAnyHashable as! T) + } + } + } + set { + _data[key] = newValue + } + _modify { + var value = _data[key] as! T + defer { _data[key] = value } + yield &value + } + } + + @inlinable public subscript(_ key: String) -> T { + get { T.init(_fieldData: _data[key]) } + set { + _data[key] = newValue._fieldData + } + _modify { + var value = T.init(_fieldData: _data[key]) + defer { _data[key] = value._fieldData } + yield &value + } + } + + @inlinable public func hash(into hasher: inout Hasher) { + hasher.combine(_data) + } + + @inlinable public static func ==(lhs: DataDict, rhs: DataDict) -> Bool { + lhs._data == rhs._data + } + + @usableFromInline func fragmentIsFulfilled(_ type: T.Type) -> Bool { + let id = ObjectIdentifier(T.self) + return _fulfilledFragments.contains(id) + } + + @usableFromInline func fragmentsAreFulfilled(_ types: [any SelectionSet.Type]) -> Bool { + let typeIds = types.lazy.map(ObjectIdentifier.init) + return _fulfilledFragments.isSuperset(of: typeIds) + } + + // MARK: - DataDict._Storage + @usableFromInline class _Storage: Hashable { + @usableFromInline var data: [String: AnyHashable] + @usableFromInline let fulfilledFragments: Set + @usableFromInline let deferredFragments: Set + + init( + data: [String: AnyHashable], + fulfilledFragments: Set, + deferredFragments: Set + ) { + self.data = data + self.fulfilledFragments = fulfilledFragments + self.deferredFragments = deferredFragments + } + + @usableFromInline static func ==(lhs: DataDict._Storage, rhs: DataDict._Storage) -> Bool { + lhs.data == rhs.data && + lhs.fulfilledFragments == rhs.fulfilledFragments && + lhs.deferredFragments == rhs.deferredFragments + } + + @usableFromInline func hash(into hasher: inout Hasher) { + hasher.combine(data) + hasher.combine(fulfilledFragments) + hasher.combine(deferredFragments) + } + + @usableFromInline func copy() -> _Storage { + _Storage( + data: self.data, + fulfilledFragments: self.fulfilledFragments, + deferredFragments: self.deferredFragments + ) + } + } +} + +// MARK: - Null Value Definition +extension DataDict { + /// A common value used to represent a null value in a `DataDict`. + /// + /// This value can be cast to `NSNull` and will bridge automatically. + public static let _NullValue = { + if DataDict._AnyHashableCanBeCoerced { + return AnyHashable(Optional.none) + } else { + return NSNull() + } + }() + + /// Indicates if `AnyHashable` can be coerced via casting into its underlying type. + /// + /// In iOS versions 14.4 and lower, `AnyHashable` coercion does not work. On these platforms, + /// we need to do some additional unwrapping and casting of the values to avoid crashes and other + /// run time bugs. + public static let _AnyHashableCanBeCoerced: Bool = { + if #available(iOS 14.5, *) { + return true + } else { + return false + } + }() + +} + +// MARK: - Value Conversion Helpers + +public protocol SelectionSetEntityValue { + /// - Warning: This function is not supported for external use. + /// Unsupported usage may result in unintended consequences including crashes. + /// + /// The `_fieldData` should be the underlying `DataDict` for an entity value. + /// This is represented as `AnyHashable` because for `Optional` and `Array` you will have an + /// `Optional` and `[DataDict]` respectively. + init(_fieldData: AnyHashable?) + var _fieldData: AnyHashable { get } +} + +extension RootSelectionSet { + /// - Warning: This function is not supported for external use. + /// Unsupported usage may result in unintended consequences including crashes. + @inlinable public init(_fieldData data: AnyHashable?) { + guard let dataDict = data as? DataDict else { + fatalError("\(Self.self) expected DataDict for entity, got \(type(of: data)).") + } + self.init(_dataDict: dataDict) + } + + @inlinable public var _fieldData: AnyHashable { __data } +} + +extension Optional: SelectionSetEntityValue where Wrapped: SelectionSetEntityValue { + /// - Warning: This function is not supported for external use. + /// Unsupported usage may result in unintended consequences including crashes. + @inlinable public init(_fieldData data: AnyHashable?) { + switch data { + case .none: + self = .none + case .some(let hashable): + if !DataDict._AnyHashableCanBeCoerced && hashable == DataDict._NullValue { + self = .none + } else if let optional = hashable.base as? Optional, optional == nil { + self = .none + } else { + self = .some(Wrapped.init(_fieldData: data)) + } + } + } + + @inlinable public var _fieldData: AnyHashable { map(\._fieldData) } +} + +extension Array: SelectionSetEntityValue where Element: SelectionSetEntityValue { + /// - Warning: This function is not supported for external use. + /// Unsupported usage may result in unintended consequences including crashes. + @inlinable public init(_fieldData data: AnyHashable?) { + guard let data = data as? [AnyHashable?] else { + fatalError("\(Self.self) expected list of data for entity.") + } + self = data.map { + if DataDict._AnyHashableCanBeCoerced { + return Element.init(_fieldData:$0) + } else { + return Element.init(_fieldData:$0?.base as? AnyHashable) + } + } + } + + @inlinable public var _fieldData: AnyHashable { map(\._fieldData) } +} diff --git a/Sources/ApolloAPI/Deferred.swift b/Sources/ApolloAPI/Deferred.swift new file mode 100644 index 0000000000..e9310c8d11 --- /dev/null +++ b/Sources/ApolloAPI/Deferred.swift @@ -0,0 +1,40 @@ +public protocol Deferrable: SelectionSet { } + +/// Wraps a deferred selection set (either an inline fragment or fragment spread) to expose the +/// fulfilled value as well as the fulfilled state through the projected value. +@propertyWrapper +public struct Deferred { + public enum State { + /// The deferred selection set has not been received yet. + case pending + /// The deferred value can never be fulfilled, such as in the case of a type case mismatch. + case notExecuted + /// The deferred value has been received. + case fulfilled(Fragment) + } + + public init(_dataDict: DataDict) { + __data = _dataDict + } + + public var state: State { + let fragment = ObjectIdentifier(Fragment.self) + if __data._fulfilledFragments.contains(fragment) { + return .fulfilled(Fragment.init(_dataDict: __data)) + } + else if __data._deferredFragments.contains(fragment) { + return .pending + } else { + return .notExecuted + } + } + + private let __data: DataDict + public var projectedValue: State { state } + public var wrappedValue: Fragment? { + guard case let .fulfilled(value) = state else { + return nil + } + return value + } +} diff --git a/Sources/ApolloAPI/Documentation.docc/Documentation.md b/Sources/ApolloAPI/Documentation.docc/Documentation.md new file mode 100644 index 0000000000..2b5bcd1151 --- /dev/null +++ b/Sources/ApolloAPI/Documentation.docc/Documentation.md @@ -0,0 +1,32 @@ +# ``ApolloAPI`` + +The internal models shared by the [`Apollo`](/documentation/apollo) client and the models generated by [`ApolloCodegenLib`](/documentation/apollocodegenlib) + +## Overview + +This library allows you to use your generated models without importing the full [``Apollo``](/documentation/apollo) client. The generated models import ``ApolloAPI`` and expose the necessary functionality. For most use cases, *you should not need to import ``ApolloAPI`` into your code.* + +## Topics + +### Schema Types + +- ``Object`` +- ``Interface`` +- ``Union`` +- ``InputObject`` +- ``EnumType`` + +### Scalar Types + +- ``AnyScalarType`` +- ``ScalarType`` +- ``CustomScalarType`` + +### JSON Conversion + +- ``JSONValue`` +- ``JSONObject`` +- ``JSONEncodable`` +- ``JSONEncodableDictionary`` +- ``JSONDecodable`` +- ``JSONDecodingError`` diff --git a/Sources/ApolloAPI/Documentation.docc/GraphQLEnum.md b/Sources/ApolloAPI/Documentation.docc/GraphQLEnum.md new file mode 100644 index 0000000000..2b7b878e6c --- /dev/null +++ b/Sources/ApolloAPI/Documentation.docc/GraphQLEnum.md @@ -0,0 +1,14 @@ +# ``ApolloAPI/GraphQLEnum`` + +## Topics + +### Operators + +- ``==(_:_:)-n7qo`` +- ``==(_:_:)-88en`` +- ``==(_:_:)`` +@Comment("Adds the ==(lhs: GraphQLEnum?, rhs: T) operator to the documentation page.") +- ``!=(_:_:)-4co00`` +- ``!=(_:_:)-9dudu`` +- ``!=(_:_:)`` +- ``~=(_:_:)`` diff --git a/Sources/ApolloAPI/Documentation.docc/GraphQLNullable.md b/Sources/ApolloAPI/Documentation.docc/GraphQLNullable.md new file mode 100644 index 0000000000..d98c4d863c --- /dev/null +++ b/Sources/ApolloAPI/Documentation.docc/GraphQLNullable.md @@ -0,0 +1,14 @@ +# ``ApolloAPI/GraphQLNullable`` + +## Topics + +### Enumeration Cases + +- ``none`` +- ``null`` +- ``some(_:)`` + +### Operators + +- ``__(_:_:)`` +@Comment("Adds the ?? operator to the documentation page.") diff --git a/Sources/ApolloAPI/FragmentProtocols.swift b/Sources/ApolloAPI/FragmentProtocols.swift new file mode 100644 index 0000000000..34267ce569 --- /dev/null +++ b/Sources/ApolloAPI/FragmentProtocols.swift @@ -0,0 +1,108 @@ +// MARK: - Fragment + +/// A protocol representing a fragment that a ``SelectionSet`` object may be converted to. +/// +/// A ``SelectionSet`` can be converted to any ``Fragment`` included in it's +/// `Fragments` object via its ``SelectionSet/fragments-swift.property`` property. +public protocol Fragment: SelectionSet, Deferrable { + /// The definition of the fragment in GraphQL syntax. + static var fragmentDefinition: StaticString { get } +} + +/// Extension providing default implementation for the ``Fragment`` protocol. +extension Fragment { + // Default implementation for the `fragmentDefinition` variable + public static var fragmentDefinition: StaticString { + return "" + } +} + +/// A protocol representing a container for the fragments on a generated ``SelectionSet``. +/// +/// A generated ``FragmentContainer`` includes generated properties for converting the +/// ``SelectionSet`` into any generated ``Fragment`` that it includes. +/// +/// # Code Generation +/// +/// The ``FragmentContainer`` protocol is only conformed to by generated `Fragments` structs. +/// Given a query: +/// ```graphql +/// fragment FragmentA on Animal { +/// species +/// } +/// +/// query { +/// animals { +/// ...FragmentA +/// } +/// } +/// ``` +/// The generated `Animal` ``SelectionSet`` will include the ``FragmentContainer``: +/// ```swift +/// public struct Animal: API.SelectionSet { +/// // ... +/// public struct Fragments: FragmentContainer { +/// public let __data: DataDict +/// public init(data: DataDict) { __data = data } +/// +/// public var fragmentA: FragmentA { _toFragment() } +/// } +/// } +/// ``` +/// +/// # Converting a SelectionSet to a Fragment +/// +/// With the generated code above, you can conver the `Animal` ``SelectionSet`` to the generated +/// `FragmentA` ``Fragment``: +/// ```swift +/// let fragmentA: FragmentA = animal.fragments.fragmentA +/// ``` +public protocol FragmentContainer { + /// The data of the underlying GraphQL object represented by the parent ``SelectionSet`` + var __data: DataDict { get } + + /// Designated Initializer + /// - Parameter dataDict: The data of the underlying GraphQL object represented by the parent ``SelectionSet`` + init(_dataDict: DataDict) +} + +extension FragmentContainer { + + /// Converts a ``SelectionSet`` to a ``Fragment`` given a generic fragment type. + /// + /// > Warning: This function is not supported for use outside of generated call sites. + /// Generated call sites are guaranteed by the GraphQL compiler to be safe. + /// Unsupported usage may result in unintended consequences including crashes. + /// + /// - Returns: The ``Fragment`` the ``SelectionSet`` has been converted to + @inlinable public func _toFragment() -> T { + _convertToFragment() + } + + @usableFromInline func _convertToFragment()-> T { + return T.init(_dataDict: __data) + } + + /// Converts a ``SelectionSet`` to a ``Fragment`` given a generic fragment type if the fragment + /// was fulfilled. + /// + /// A fragment may not be fulfilled if it is condtionally included useing an `@include/@skip` + /// directive. For more information on `@include/@skip` conditions, see ``Selection/Conditions`` + /// + /// > Warning: This function is not supported for use outside of generated call sites. + /// Generated call sites are guaranteed by the GraphQL compiler to be safe. + /// Unsupported usage may result in unintended consequences including crashes. + /// + /// - Returns: The ``Fragment`` the ``SelectionSet`` has been converted to, or `nil` if the + /// fragment was not fulfilled. + @inlinable public func _toFragment() -> T? { + guard __data.fragmentIsFulfilled(T.self) else { return nil } + return T.init(_dataDict: __data) + } + +} + +/// A ``FragmentContainer`` to be used by ``SelectionSet``s that have no fragments. +/// This is the default ``FragmentContainer`` for a ``SelectionSet`` that does not specify a +/// `Fragments` type. +public enum NoFragments {} diff --git a/Sources/ApolloAPI/GraphQLEnum.swift b/Sources/ApolloAPI/GraphQLEnum.swift new file mode 100644 index 0000000000..ee46986247 --- /dev/null +++ b/Sources/ApolloAPI/GraphQLEnum.swift @@ -0,0 +1,140 @@ +/// A generic enum type that wraps an ``EnumType`` from a generated GraphQL schema. +/// +/// ``GraphQLEnum`` provides an ``unknown(_:)`` case that is used when the response returns a value +/// that is not recognized as a valid enum case. This is usually caused by future cases added to +/// the enum on the schema after code generation. +public enum GraphQLEnum: CaseIterable, Hashable, RawRepresentable { + public typealias RawValue = String + + /// A recognized case of the wrapped enum. + case `case`(T) + + /// An unrecognized value for the enum. + /// The associated value exposes the raw `String` name of the unknown enum case. + case unknown(String) + + /// Initializer for use with a value of the wrapped ``EnumType`` + /// + /// - Parameter caseValue: A value of the wrapped ``EnumType`` + @inlinable public init(_ caseValue: T) { + self = .case(caseValue) + } + + /// Initializer for use with a raw value `String`. This initializer is used for initializing an + /// enum from a GraphQL response value. + /// + /// The `rawValue` should represent a raw value for a case of the wrapped ``EnumType``, or an + /// ``unknown(_:)`` case with the `rawValue` will be returned. + /// + /// - Parameter rawValue: The `String` value representing the enum value in a GraphQL response + @inlinable public init(rawValue: String) { + guard let caseValue = T(rawValue: rawValue) else { + self = .unknown(rawValue) + return + } + self = .case(caseValue) + } + + /// Convenience initializer for use with a raw value `String`. This initializer is used for + /// initializing an enum from a GraphQL response value. + /// + /// The `rawValue` should represent a raw value for a case of the wrapped ``EnumType``, or an + /// `unknown` case with the `rawValue` will be returned. + /// + /// - Parameter rawValue: The `String` value representing the enum value in a GraphQL response + @inlinable public init(_ rawValue: String) { + self.init(rawValue: rawValue) + } + + /// The underlying enum case. If the value is ``unknown(_:)``, this will be `nil`. + @inlinable public var value: T? { + switch self { + case let .case(value): return value + default: return nil + } + } + + /// The `String` value representing the enum value in a GraphQL response. + @inlinable public var rawValue: String { + switch self { + case let .case(value): return value.rawValue + case let .unknown(value): return value + } + } + + /// A collection of all known values of the wrapped enum. + /// This collection does not include the `unknown` case. + @inlinable public static var allCases: [GraphQLEnum] { + return T.allCases.map { .case($0) } + } + +} + +// MARK: CustomScalarType +extension GraphQLEnum: CustomScalarType { + @inlinable public init(_jsonValue: JSONValue) throws { + guard let stringData = _jsonValue as? String else { + throw JSONDecodingError.couldNotConvert(value: _jsonValue, to: String.self) + } + self.init(rawValue: stringData) + } +} + +// MARK: Equatable +extension GraphQLEnum { + @inlinable public static func ==(lhs: GraphQLEnum, rhs: GraphQLEnum) -> Bool { + return lhs.rawValue == rhs.rawValue + } + + @inlinable public static func ==(lhs: GraphQLEnum, rhs: T) -> Bool { + return lhs.rawValue == rhs.rawValue + } + + @inlinable public static func !=(lhs: GraphQLEnum, rhs: T) -> Bool { + return lhs.rawValue != rhs.rawValue + } +} + +// MARK: Optional> Equatable + +@inlinable public func ==(lhs: GraphQLEnum?, rhs: T) -> Bool +where T.RawValue == String { + return lhs?.rawValue == rhs.rawValue +} + +@inlinable public func !=(lhs: GraphQLEnum?, rhs: T) -> Bool +where T.RawValue == String { + return lhs?.rawValue != rhs.rawValue +} + +// MARK: Pattern Matching +extension GraphQLEnum { + /// Pattern Matching Operator overload for ``GraphQLEnum`` + /// + /// This operator allows for a ``GraphQLEnum`` to be matched against a `case` on the wrapped + /// ``EnumType``. + /// + /// > Note: Because this is not a synthesized pattern, the Swift compiler cannot determine + /// switch case exhaustiveness. When used in a switch statement, you will be required to provide + /// a `default` case. + /// + /// ```swift + /// let enumValue: GraphQLEnum = .case(.NEWHOPE) + /// + /// switch enumValue { + /// case .NEWHOPE: + /// print("Success") + /// case .RETURN, .EMPIRE: + /// print("Fail") + /// default: + /// print("Fail") // This default case will never be executed but is required. + /// } + /// ``` + @inlinable public static func ~=(lhs: T, rhs: GraphQLEnum) -> Bool { + switch rhs { + case let .case(rhs) where rhs == lhs: return true + case let .unknown(rhsRawValue) where rhsRawValue == lhs.rawValue: return true + default: return false + } + } +} diff --git a/Sources/ApolloAPI/GraphQLNullable.swift b/Sources/ApolloAPI/GraphQLNullable.swift new file mode 100644 index 0000000000..0df0899a7e --- /dev/null +++ b/Sources/ApolloAPI/GraphQLNullable.swift @@ -0,0 +1,276 @@ +/// Indicates the presence of a value, supporting both `nil` and `null` values. +/// +/// ``GraphQLNullable`` is generally only used for setting input values on generated ``GraphQLOperation`` objects. +/// +/// In GraphQL, explicitly providing a `null` value for an input value to a field argument is +/// semantically different from not providing a value at all (`nil`). This enum allows you to +/// distinguish your input values between `null` and `nil`. +/// +/// # Usage +/// +/// ``GraphQLNullable`` provides a similar interface to Swift's `Optional`, however in addition to +/// the `.some(Wrapped)` and `.none` cases, it provides an additional `.null` case. The `.null` +/// case parallels `NSNull`, while `.none` paralells `nil`. This requires you to specify either +/// a `.null` or an omitted (`.none`) value when constructing the query object. The `nil` literal +/// also translates to the `.none` case. +/// +/// ```swift +/// public init(inputValue: GraphQLNullable) +/// +/// // Null Value: +/// .init(episode: .null) +/// +/// // Nil Value: +/// .init(episode: .none) or .init(episode: nil) +/// ``` +/// +/// ### Literals, Enums, and InputObjects +/// For Swift scalar types that have an `ExpressibleBy...Literal` protocol, ``GraphQLNullable`` +/// can be initialized with a literal value. +/// +/// ```swift +/// // String +/// public init(inputValue: GraphQLNullable) +/// +/// .init(inputValue: "InputValueString") +/// +/// // Integer Array +/// public init(inputValue: GraphQLNullable<[Int]>) +/// +/// .init(inputValue: [1, 2, 4, 5, 3, 6]) // The best order for watching the Star Wars movies. +/// ``` +/// To provide a value for a ``GraphQLEnum`` or ``InputObject`` value, you need to wrap it in a +/// ``GraphQLNullable``, either with the provided convenience initializer, or by using the `.some` +/// case. +/// +/// ```swift +/// /// Enum +/// public init(episode: GraphQLNullable>) +/// +/// .init(episode: GraphQLNullable(.empire)) +/// or +/// .init(episode: .some(.empire)) +/// +/// // Input Object +/// public init(inputValue: GraphQLNullable) +/// +/// .init(inputValue: GraphQLNullable(CustomInputObject())) +/// or +/// .init(inputValue: .some(CustomInputObject())) +/// ``` +/// ### Optional Values with the Nil Coalescing Operator +/// +/// You can initialize a ``GraphQLNullable`` with an optional value, but you'll need to indicate +/// the default value to use if the optional is `nil`. Usually this value is either +/// ``none`` or ``null``. +/// ```swift +/// let optionalValue: String? +/// +/// .init(inputValue: optionalValue ?? .none) +/// or +/// .init(inputValue: optionalValue ?? .null) +/// ``` +/// +/// ### Accessing Properties on Wrapped Objects +/// +/// ``GraphQLNullable`` uses `@dynamicMemberLookup` to provide access to properties on the wrapped +/// object without unwrapping. +/// +/// ```swift +/// let nullableString: GraphQLNullable = "MyString" +/// print(nullableString.count) // 8 +/// ``` +/// You can also unwrap the wrapped value to access it directly. +/// ```swift +/// let nullableString: GraphQLNullable = "MyString" +/// if let string = nullableString.unwrapped { +/// print(string.count) // 8 +/// } +/// ``` +/// # See Also +/// [GraphQLSpec - Input Values - Null Value](http://spec.graphql.org/October2021/#sec-Null-Value) +@dynamicMemberLookup +public enum GraphQLNullable { + + /// The absence of a value. + /// Functionally equivalent to `nil`. + case none + + /// The presence of an explicity null value. + /// Functionally equivalent to `NSNull` + case null + + /// The presence of a value, stored as `Wrapped` + case some(Wrapped) + + /// The wrapped value if one exists, `nil` if the receiver is ``none`` or ``null``. + /// + /// This property can be used to use a `GraphQLNullable` as you would an `Optional`. + /// ```swift + /// let childProperty: String? = nullableInputObject.unwrapped?.childProperty + /// ``` + @inlinable public var unwrapped: Wrapped? { + guard case let .some(wrapped) = self else { return nil } + return wrapped + } + + /// Subscript for `@dynamicMemberLookup`. Accesses values on the wrapped type. + /// Will return `nil` if the receiver is ``none`` or ``null``. + /// + /// This dynamic member subscript allows you to optionally access properties of the wrapped value. + /// ```swift + /// let childProperty: String? = nullableInputObject.childProperty + /// ``` + @inlinable public subscript(dynamicMember path: KeyPath) -> T? { + unwrapped?[keyPath: path] + } + +} + +// MARK: - ExpressibleBy Literal Extensions + +extension GraphQLNullable: ExpressibleByNilLiteral { + /// The `ExpressibleByNilLiteral` Initializer. Initializes as ``none``. + /// + /// This initializer allows you to initialize a ``GraphQLNullable`` by assigning `nil`. + /// ```swift + /// let GraphQLNullable = nil // .none + /// ``` + @inlinable public init(nilLiteral: ()) { + self = .none + } +} + +extension GraphQLNullable: ExpressibleByUnicodeScalarLiteral +where Wrapped: ExpressibleByUnicodeScalarLiteral { + @inlinable public init(unicodeScalarLiteral value: Wrapped.UnicodeScalarLiteralType) { + self = .some(Wrapped(unicodeScalarLiteral: value)) + } +} + +extension GraphQLNullable: ExpressibleByExtendedGraphemeClusterLiteral +where Wrapped: ExpressibleByExtendedGraphemeClusterLiteral { + @inlinable public init(extendedGraphemeClusterLiteral value: Wrapped.ExtendedGraphemeClusterLiteralType) { + self = .some(Wrapped(extendedGraphemeClusterLiteral: value)) + } +} + +extension GraphQLNullable: ExpressibleByStringLiteral +where Wrapped: ExpressibleByStringLiteral { + @inlinable public init(stringLiteral value: Wrapped.StringLiteralType) { + self = .some(Wrapped(stringLiteral: value)) + } +} + +extension GraphQLNullable: ExpressibleByIntegerLiteral +where Wrapped: ExpressibleByIntegerLiteral { + @inlinable public init(integerLiteral value: Wrapped.IntegerLiteralType) { + self = .some(Wrapped(integerLiteral: value)) + } +} + +extension GraphQLNullable: ExpressibleByFloatLiteral +where Wrapped: ExpressibleByFloatLiteral { + @inlinable public init(floatLiteral value: Wrapped.FloatLiteralType) { + self = .some(Wrapped(floatLiteral: value)) + } +} + +extension GraphQLNullable: ExpressibleByBooleanLiteral +where Wrapped: ExpressibleByBooleanLiteral { + @inlinable public init(booleanLiteral value: Wrapped.BooleanLiteralType) { + self = .some(Wrapped(booleanLiteral: value)) + } +} + +extension GraphQLNullable: ExpressibleByArrayLiteral +where Wrapped: _InitializableByArrayLiteralElements { + @inlinable public init(arrayLiteral elements: Wrapped.ArrayLiteralElement...) { + self = .some(Wrapped(elements)) + } +} + +extension GraphQLNullable: ExpressibleByDictionaryLiteral +where Wrapped: _InitializableByDictionaryLiteralElements { + @inlinable public init(dictionaryLiteral elements: (Wrapped.Key, Wrapped.Value)...) { + self = .some(Wrapped(elements)) + } +} + +/// A helper protocol used to enable wrapper types to conform to `ExpressibleByArrayLiteral`. +/// Used by ``GraphQLNullable/init(arrayLiteral:)`` +public protocol _InitializableByArrayLiteralElements: ExpressibleByArrayLiteral { + init(_ array: [ArrayLiteralElement]) +} +extension Array: _InitializableByArrayLiteralElements {} + +/// A helper protocol used to enable wrapper types to conform to `ExpressibleByDictionaryLiteral`. +/// Used by ``GraphQLNullable/init(dictionaryLiteral:)`` +public protocol _InitializableByDictionaryLiteralElements: ExpressibleByDictionaryLiteral { + init(_ elements: [(Key, Value)]) +} + +extension Dictionary: _InitializableByDictionaryLiteralElements { + @inlinable public init(_ elements: [(Key, Value)]) { + self.init(uniqueKeysWithValues: elements) + } +} + +// MARK: - Custom Type Initialization + +public extension GraphQLNullable { + /// Initializer for use with a ``GraphQLEnum`` value. + /// + /// This initializer enables easier creation of the ``GraphQLNullable`` and ``GraphQLEnum``. + /// ```swift + /// let value: GraphQLNullable> + /// + /// value = .init(.NEWHOPE) + /// // Instead of + /// value = .init(.case(.NEWHOPE)) + /// ``` + /// - Parameter caseValue: A case of a generated ``EnumType`` to initialize a + /// `GraphQLNullable` with. + @inlinable init(_ caseValue: T) where Wrapped == GraphQLEnum { + self = .some(Wrapped(caseValue)) + } + + /// Intializer for use with an ``InputObject`` value. + /// - Parameter object: The ``InputObject`` to initalize a ``GraphQLNullable`` with. + @inlinable init(_ object: Wrapped) where Wrapped: InputObject { + self = .some(object) + } +} + +// MARK: - Nil Coalescing Operator + +/// Nil Coalescing Operator overload for ``GraphQLNullable`` +/// +/// This operator allows for optional variables to easily be used with ``GraphQLNullable`` +/// parameters and a default value. +/// +/// ```swift +/// class MyQuery: GraphQLQuery { +/// +/// var myVar: GraphQLNullable +/// +/// init(myVar: GraphQLNullable) { ... } +/// // ... +/// } +/// +/// let optionalString: String? +/// let query = MyQuery(myVar: optionalString ?? .none) +/// ``` +@_disfavoredOverload +@inlinable public func ??(lhs: T?, rhs: GraphQLNullable) -> GraphQLNullable { + if let lhs = lhs { + return .some(lhs) + } + return rhs +} + + +// MARK: - Hashable/Equatable Conformance + +extension GraphQLNullable: Equatable where Wrapped: Equatable {} +extension GraphQLNullable: Hashable where Wrapped: Hashable {} diff --git a/Sources/ApolloAPI/GraphQLOperation.swift b/Sources/ApolloAPI/GraphQLOperation.swift new file mode 100644 index 0000000000..8cd6ca5d1d --- /dev/null +++ b/Sources/ApolloAPI/GraphQLOperation.swift @@ -0,0 +1,193 @@ +import Foundation + +public enum GraphQLOperationType: Hashable { + case query + case mutation + case subscription +} + +/// The means of providing the operation document that includes the definition of the operation +/// over network transport. +/// +/// This data represents the `Document` as defined in the GraphQL Spec. +/// - See: [GraphQLSpec - Document](https://spec.graphql.org/draft/#Document) +/// +/// The Apollo Code Generation Engine will generate the ``OperationDocument`` on each generated +/// ``GraphQLOperation``. You can configure the the code generation engine to include the +/// ``OperationDefinition``, ``operationIdentifier``, or both using the `OperationDocumentFormat` +/// options in your `ApolloCodegenConfiguration`. +public struct OperationDocument: Sendable { + public let operationIdentifier: String? + public let definition: OperationDefinition? + + public init( + operationIdentifier: String? = nil, + definition: OperationDefinition? = nil + ) { + precondition(operationIdentifier != nil || definition != nil) + self.operationIdentifier = operationIdentifier + self.definition = definition + } +} + +/// The definition of an operation to be provided over network transport. +/// +/// This data represents the `Definition` for a `Document` as defined in the GraphQL Spec. +/// In the case of the Apollo client, the definition will always be an `ExecutableDefinition`. +/// - See: [GraphQLSpec - Document](https://spec.graphql.org/draft/#Document) +public struct OperationDefinition: Sendable { + let operationDefinition: String + let fragments: [any Fragment.Type]? + + public init(_ definition: String, fragments: [any Fragment.Type]? = nil) { + self.operationDefinition = definition + self.fragments = fragments + } + + public var queryDocument: String { + var document = operationDefinition + fragments?.forEach { + document.append("\n" + $0.fragmentDefinition.description) + } + return document + } +} + +public protocol GraphQLOperation: AnyObject, Hashable { + typealias Variables = [String: GraphQLOperationVariableValue] + + static var operationName: String { get } + static var operationType: GraphQLOperationType { get } + static var operationDocument: OperationDocument { get } + static var hasDeferredFragments: Bool { get } + + var __variables: Variables? { get } + + associatedtype Data: RootSelectionSet +} + +public extension GraphQLOperation { + var __variables: Variables? { + return nil + } + + /// `True` if any selection set, or nested selection set, within the operation contains any + /// fragment marked with the `@defer` directive. + static var hasDeferredFragments: Bool { + false + } + + static var definition: OperationDefinition? { + operationDocument.definition + } + + static var operationIdentifier: String? { + operationDocument.operationIdentifier + } + + static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.__variables?._jsonEncodableValue?._jsonValue == rhs.__variables?._jsonEncodableValue?._jsonValue + } + + func hash(into hasher: inout Hasher) { + hasher.combine(__variables?._jsonEncodableValue?._jsonValue) + } +} + +public protocol GraphQLQuery: GraphQLOperation {} +public extension GraphQLQuery { + @inlinable static var operationType: GraphQLOperationType { return .query } +} + +public protocol GraphQLMutation: GraphQLOperation {} +public extension GraphQLMutation { + @inlinable static var operationType: GraphQLOperationType { return .mutation } +} + +public protocol GraphQLSubscription: GraphQLOperation {} +public extension GraphQLSubscription { + @inlinable static var operationType: GraphQLOperationType { return .subscription } +} + +// MARK: - GraphQLOperationVariableValue + +public protocol GraphQLOperationVariableValue { + var _jsonEncodableValue: (any JSONEncodable)? { get } +} + +extension Array: GraphQLOperationVariableValue +where Element: GraphQLOperationVariableValue & Hashable {} + +extension Dictionary: GraphQLOperationVariableValue +where Key == String, Value == GraphQLOperationVariableValue { + @inlinable public var _jsonEncodableValue: (any JSONEncodable)? { _jsonEncodableObject } + @inlinable public var _jsonEncodableObject: JSONEncodableDictionary { + compactMapValues { $0._jsonEncodableValue } + } +} + +extension GraphQLNullable: GraphQLOperationVariableValue +where Wrapped: GraphQLOperationVariableValue { + @inlinable public var _jsonEncodableValue: (any JSONEncodable)? { + switch self { + case .none: return nil + case .null: return NSNull() + case let .some(value): return value._jsonEncodableValue + } + } +} + +extension Optional: GraphQLOperationVariableValue where Wrapped: GraphQLOperationVariableValue { + @inlinable public var _jsonEncodableValue: (any JSONEncodable)? { + switch self { + case .none: return nil + case let .some(value): return value._jsonEncodableValue + } + } +} + +extension JSONEncodable where Self: GraphQLOperationVariableValue { + @inlinable public var _jsonEncodableValue: (any JSONEncodable)? { self } +} + +// MARK: - Deprecations + +@available(*, deprecated, renamed: "OperationDocument") +public enum DocumentType { + /// The traditional way of providing the operation `Document`. + /// The `Document` is sent with every operation request. + case notPersisted(definition: OperationDefinition) + + /// Automatically persists your operations using Apollo Server's + /// [APQs](https://www.apollographql.com/docs/apollo-server/performance/apq). + /// + /// This allow the operation definition to be persisted using an `operationIdentifier` instead of + /// being sent with every operation request. If the server does not recognize the + /// `operationIdentifier`, the network transport can send the provided definition to + /// "automatically persist" the operation definition. + case automaticallyPersisted(operationIdentifier: String, definition: OperationDefinition) + + /// Provides only the `operationIdentifier` for operations that have been previously persisted + /// to an Apollo Server using + /// [APQs](https://www.apollographql.com/docs/apollo-server/performance/apq). + /// + /// If the server does not recognize the `operationIdentifier`, the operation will fail. This + /// method should only be used if you are manually persisting your queries to an Apollo Server. + case persistedOperationsOnly(operationIdentifier: String) +} + +extension GraphQLOperation { + @available(*, deprecated, renamed: "operationDocument") + static public var document: DocumentType { + switch (operationDocument.definition, operationDocument.operationIdentifier) { + case let (definition?, id?): + return .automaticallyPersisted(operationIdentifier: id, definition: definition) + case let (definition?, .none): + return .notPersisted(definition: definition) + case let (.none, id?): + return .persistedOperationsOnly(operationIdentifier: id) + default: + preconditionFailure("operationDocument must have either a definition or an identifier.") + } + } +} diff --git a/Sources/ApolloAPI/Info.plist b/Sources/ApolloAPI/Info.plist deleted file mode 100644 index 0e600e67e7..0000000000 --- a/Sources/ApolloAPI/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/ApolloAPI/InputValue.swift b/Sources/ApolloAPI/InputValue.swift index 453384af4b..d879917d48 100644 --- a/Sources/ApolloAPI/InputValue.swift +++ b/Sources/ApolloAPI/InputValue.swift @@ -1,34 +1,39 @@ -import Foundation - -/// Represents an input value to an argument on a `GraphQLField`'s `FieldArguments`. +/// Represents an input value to an argument on a ``Selection/Field``'s ``Selection/Field/arguments``. /// -/// - See: [GraphQLSpec - Input Values](http://spec.graphql.org/June2018/#sec-Input-Values) +/// # See Also +/// [GraphQLSpec - Input Values](http://spec.graphql.org/October2021/#sec-Input-Values) public indirect enum InputValue { /// A direct input value, valid types are `String`, `Int` `Float` and `Bool`. /// For enum input values, the enum cases's `rawValue` as a `String` should be used. - case scalar(ScalarType) + case scalar(any ScalarType) - /// A variable input value to be evaluated using the operation's `variables` dictionary at runtime. + /// A variable input value to be evaluated using the operation's variables dictionary at runtime. + /// See ``GraphQLOperation``. + /// + /// `.variable` should only be used as the value for an argument in a ``Selection/Field``. + /// A `.variable` value should not be included in an operation's variables dictionary. See + /// ``GraphQLOperation``. case variable(String) - /// A GraphQL "List" input value. - /// - See: [GraphQLSpec - Input Values - List Value](http://spec.graphql.org/June2018/#sec-List-Value) + /// A GraphQL "`List`" input value. + /// # See Also + /// [GraphQLSpec - Input Values - List Value](http://spec.graphql.org/October2021/#sec-List-Value) case list([InputValue]) - /// A GraphQL "InputObject" input value. Represented as a dictionary of input values. - /// - See: [GraphQLSpec - Input Values - Input Object Values](http://spec.graphql.org/June2018/#sec-Input-Object-Values) + /// A GraphQL "`InputObject`" input value. Represented as a dictionary of input values. + /// # See Also + /// [GraphQLSpec - Input Values - Input Object Values](http://spec.graphql.org/October2021/#sec-Input-Object-Values) case object([String: InputValue]) /// A null input value. - /// - See: [GraphQLSpec - Input Values - Null Value](http://spec.graphql.org/June2018/#sec-Null-Value) - case none + /// + /// A null input value indicates an intentional inclusion of a value for a field argument as null. + /// # See Also + /// [GraphQLSpec - Input Values - Null Value](http://spec.graphql.org/October2021/#sec-Null-Value) + case null } -extension InputValue: ExpressibleByNilLiteral { - @inlinable public init(nilLiteral: ()) { - self = .none - } -} +// MARK: - ExpressibleBy Literal Extensions extension InputValue: ExpressibleByStringLiteral { @inlinable public init(stringLiteral value: StringLiteralType) { @@ -56,12 +61,44 @@ extension InputValue: ExpressibleByBooleanLiteral { extension InputValue: ExpressibleByArrayLiteral { @inlinable public init(arrayLiteral elements: InputValue...) { - self = .list(Array(elements)) + self = .list(Array(elements.map { $0 })) } } extension InputValue: ExpressibleByDictionaryLiteral { - public init(dictionaryLiteral elements: (String, InputValue)...) { - self = .object(Dictionary(elements, uniquingKeysWith: { (_, last) in last })) + @inlinable public init(dictionaryLiteral elements: (String, InputValue)...) { + self = .object(Dictionary(elements.map{ ($0.0, $0.1) }, + uniquingKeysWith: { (_, last) in last })) + } +} + +// MARK: Hashable Conformance + +extension InputValue: Hashable { + public static func == (lhs: InputValue, rhs: InputValue) -> Bool { + switch (lhs, rhs) { + case let (.variable(lhsValue), .variable(rhsValue)), + let (.scalar(lhsValue as String), .scalar(rhsValue as String)): + return lhsValue == rhsValue + case let (.scalar(lhsValue as Bool), .scalar(rhsValue as Bool)): + return lhsValue == rhsValue + case let (.scalar(lhsValue as Int), .scalar(rhsValue as Int)): + return lhsValue == rhsValue + case let (.scalar(lhsValue as Float), .scalar(rhsValue as Float)): + return lhsValue == rhsValue + case let (.scalar(lhsValue as Double), .scalar(rhsValue as Double)): + return lhsValue == rhsValue + case let (.list(lhsValue), .list(rhsValue)): + return lhsValue.elementsEqual(rhsValue) + case let (.object(lhsValue), .object(rhsValue)): + return lhsValue.elementsEqual(rhsValue, by: { $0.key == $1.key && $0.value == $1.value }) + case (.null, .null): + return true + default: return false + } + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(self) } } diff --git a/Sources/ApolloAPI/JSON.swift b/Sources/ApolloAPI/JSON.swift new file mode 100644 index 0000000000..d6921e1274 --- /dev/null +++ b/Sources/ApolloAPI/JSON.swift @@ -0,0 +1,50 @@ +/// Represents a value in a ``JSONObject`` +/// +/// Making ``JSONValue`` an `AnyHashable` enables comparing ``JSONObject``s +/// in `Equatable` conformances. +public typealias JSONValue = AnyHashable + +/// Represents a JSON Dictionary +public typealias JSONObject = [String: JSONValue] + +/// Represents a Dictionary that can be converted into a ``JSONObject`` +/// +/// To convert to a ``JSONObject``: +/// ```swift +/// dictionary.compactMapValues { $0.jsonValue } +/// ``` +public typealias JSONEncodableDictionary = [String: any JSONEncodable] + +/// A protocol for a type that can be initialized from a ``JSONValue``. +/// +/// This is used to interoperate between the type-safe Swift models and the `JSON` in a +/// GraphQL network response/request or the `NormalizedCache`. +public protocol JSONDecodable: AnyHashableConvertible { + + /// Intializes the conforming type from a ``JSONValue``. + /// + /// > Important: For a type that conforms to both ``JSONEncodable`` and ``JSONDecodable``, + /// the `jsonValue` passed to this initializer should be equal to the value returned by the + /// initialized entity's ``JSONEncodable/jsonValue`` property. + /// + /// - Parameter value: The ``JSONValue`` to convert to the ``JSONDecodable`` type. + /// + /// - Throws: A ``JSONDecodingError`` if the `jsonValue` cannot be converted to the receiver's + /// type. + init(_jsonValue value: JSONValue) throws +} + +/// A protocol for a type that can be converted into a ``JSONValue``. +/// +/// This is used to interoperate between the type-safe Swift models and the `JSON` in a +/// GraphQL network response/request or the `NormalizedCache`. +public protocol JSONEncodable { + + /// Converts the type into a ``JSONValue`` that can be sent in a GraphQL network request or + /// stored in the `NormalizedCache`. + /// + /// > Important: For a type that conforms to both ``JSONEncodable`` and ``JSONDecodable``, + /// the return value of this function, when passed to ``JSONDecodable/init(jsonValue:)`` should + /// initialize a value equal to the receiver. + var _jsonValue: JSONValue { get } +} diff --git a/Sources/ApolloAPI/JSONDecodingError.swift b/Sources/ApolloAPI/JSONDecodingError.swift new file mode 100644 index 0000000000..000dfa427f --- /dev/null +++ b/Sources/ApolloAPI/JSONDecodingError.swift @@ -0,0 +1,52 @@ +import Foundation + +/// An error thrown while decoding `JSON`. +/// +/// This error should be thrown when a ``JSONDecodable`` initialization fails. +/// `GraphQLExecutor` and `ApolloStore` may also throw this error when decoding a `JSON` fails. +public enum JSONDecodingError: Error, LocalizedError, Hashable { + /// A value that is expected to be present is missing from the ``JSONObject``. + case missingValue + /// A value that is non-null has a `null`value. + case nullValue + /// A value in a ``JSONObject`` was not of the expected `JSON` type. + /// (eg. An object instead of a list) + case wrongType + /// The `value` could not be converted to the expected type. + /// + /// This error is thrown when a ``JSONDecodable`` initialization fails for the expected type. + case couldNotConvert(value: AnyHashable, to: Any.Type) + + public var errorDescription: String? { + switch self { + case .missingValue: + return "Missing value" + case .nullValue: + return "Unexpected null value" + case .wrongType: + return "Wrong type" + case .couldNotConvert(let value, let expectedType): + return "Could not convert \"\(value)\" to \(expectedType)" + } + } + + public static func == (lhs: JSONDecodingError, rhs: JSONDecodingError) -> Bool { + switch (lhs, rhs) { + case (.missingValue, .missingValue), + (.nullValue, .nullValue), + (.wrongType, .wrongType): + return true + + case let (.couldNotConvert(value: lhsValue, to: lhsType), + .couldNotConvert(value: rhsValue, to: rhsType)): + return lhsValue == rhsValue && lhsType == rhsType + + default: + return false + } + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(self) + } +} diff --git a/Sources/ApolloAPI/JSONStandardTypeConversions.swift b/Sources/ApolloAPI/JSONStandardTypeConversions.swift new file mode 100644 index 0000000000..6805b4ca3c --- /dev/null +++ b/Sources/ApolloAPI/JSONStandardTypeConversions.swift @@ -0,0 +1,160 @@ +import Foundation + +extension String: JSONDecodable, JSONEncodable { + /// The ``JSONDecodable`` initializer for a `String`. + /// + /// This initializer will accept a `jsonValue` of a `String`, `Int` or `Double`. + /// This allows for conversion of custom scalars that are represented as any of these types to + /// convert using the default custom scalar typealias of `String`. + /// + /// # See Also + /// ``CustomScalarType`` + @inlinable public init(_jsonValue value: JSONValue) throws { + switch value.base { + case let string as String: + self = string + case let int as Int: + self = String(int) + case let int64 as Int64: + self = String(int64) + case let double as Double: + self = String(double) + default: + throw JSONDecodingError.couldNotConvert(value: value, to: String.self) + } + } + + @inlinable public var _jsonValue: JSONValue { + return self + } +} + +extension Int: JSONDecodable, JSONEncodable { + @inlinable public init(_jsonValue value: JSONValue) throws { + guard let number = value as? NSNumber else { + throw JSONDecodingError.couldNotConvert(value: value, to: Int.self) + } + self = number.intValue + } + + @inlinable public var _jsonValue: JSONValue { + return self + } +} + +extension Float: JSONDecodable, JSONEncodable { + @inlinable public init(_jsonValue value: JSONValue) throws { + guard let number = value as? NSNumber else { + throw JSONDecodingError.couldNotConvert(value: value, to: Float.self) + } + self = number.floatValue + } + + @inlinable public var _jsonValue: JSONValue { + return self + } +} + +extension Double: JSONDecodable, JSONEncodable { + @inlinable public init(_jsonValue value: JSONValue) throws { + guard let number = value as? NSNumber else { + throw JSONDecodingError.couldNotConvert(value: value, to: Double.self) + } + self = number.doubleValue + } + + @inlinable public var _jsonValue: JSONValue { + return self + } +} + +extension Bool: JSONDecodable, JSONEncodable { + @inlinable public init(_jsonValue value: JSONValue) throws { + guard let bool = value as? Bool else { + throw JSONDecodingError.couldNotConvert(value: value, to: Bool.self) + } + self = bool + } + + @inlinable public var _jsonValue: JSONValue { + return self + } +} + +extension EnumType { + @inlinable public var _jsonValue: JSONValue { rawValue } +} + +extension RawRepresentable where RawValue: JSONDecodable { + @inlinable public init(_jsonValue value: JSONValue) throws { + let rawValue = try RawValue(_jsonValue: value) + if let tempSelf = Self(rawValue: rawValue) { + self = tempSelf + } else { + throw JSONDecodingError.couldNotConvert(value: value, to: Self.self) + } + } +} + +extension RawRepresentable where RawValue: JSONEncodable { + @inlinable public var _jsonValue: JSONValue { + return rawValue._jsonValue + } +} + +extension Optional where Wrapped: JSONDecodable { + @inlinable public init(jsonValue value: JSONValue) throws { + if value is NSNull { + self = .none + } else { + self = .some(try Wrapped(_jsonValue: value)) + } + } +} + +extension Optional: JSONEncodable where Wrapped: JSONEncodable & Hashable { + @inlinable public var _jsonValue: JSONValue { + switch self { + case .none: return NSNull() + case let .some(value): return value._jsonValue + } + } +} + +extension NSDictionary: JSONEncodable { + @inlinable public var _jsonValue: JSONValue { self } +} + +extension NSNull: JSONEncodable { + @inlinable public var _jsonValue: JSONValue { self } +} + +extension JSONEncodableDictionary: JSONEncodable { + @inlinable public var _jsonValue: JSONValue { _jsonObject } + + @inlinable public var _jsonObject: JSONObject { + mapValues(\._jsonValue) + } +} + +extension JSONObject: JSONDecodable { + @inlinable public init(_jsonValue value: JSONValue) throws { + guard let dictionary = value as? JSONObject else { + throw JSONDecodingError.couldNotConvert(value: value, to: JSONObject.self) + } + + self = dictionary + } +} + +extension Array: JSONEncodable { + @inlinable public var _jsonValue: JSONValue { + return map { element -> JSONValue in + if case let element as JSONEncodable = element { + return element._jsonValue + } else { + fatalError("Array is only JSONEncodable if Element is") + } + } + } +} diff --git a/Sources/ApolloAPI/LocalCacheMutation.swift b/Sources/ApolloAPI/LocalCacheMutation.swift new file mode 100644 index 0000000000..f09fed6c8a --- /dev/null +++ b/Sources/ApolloAPI/LocalCacheMutation.swift @@ -0,0 +1,47 @@ +public protocol LocalCacheMutation: AnyObject, Hashable { + static var operationType: GraphQLOperationType { get } + + var __variables: GraphQLOperation.Variables? { get } + + associatedtype Data: MutableRootSelectionSet +} + +public extension LocalCacheMutation { + var __variables: GraphQLOperation.Variables? { + return nil + } + + func hash(into hasher: inout Hasher) { + hasher.combine(__variables?._jsonEncodableValue?._jsonValue) + } + + static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.__variables?._jsonEncodableValue?._jsonValue == rhs.__variables?._jsonEncodableValue?._jsonValue + } +} + +public protocol MutableSelectionSet: SelectionSet { + var __data: DataDict { get set } +} + +public extension MutableSelectionSet { + @inlinable var __typename: String? { + get { __data["__typename"] } + set { __data["__typename"] = newValue } + } +} + +public extension MutableSelectionSet where Fragments: FragmentContainer { + @inlinable var fragments: Fragments { + get { Self.Fragments(_dataDict: __data) } + _modify { + var f = Self.Fragments(_dataDict: __data) + yield &f + self.__data._data = f.__data._data + } + @available(*, unavailable, message: "mutate properties of the fragment instead.") + set { preconditionFailure("") } + } +} + +public protocol MutableRootSelectionSet: RootSelectionSet, MutableSelectionSet {} diff --git a/Sources/ApolloAPI/ObjectData.swift b/Sources/ApolloAPI/ObjectData.swift new file mode 100644 index 0000000000..17f0a81e23 --- /dev/null +++ b/Sources/ApolloAPI/ObjectData.swift @@ -0,0 +1,95 @@ +public protocol _ObjectData_Transformer { + func transform(_ value: AnyHashable) -> (any ScalarType)? + func transform(_ value: AnyHashable) -> ObjectData? + func transform(_ value: AnyHashable) -> ListData? +} + +/// An opaque wrapper for data representing a GraphQL object. This type wraps data from different +/// sources, using a `_transformer` to ensure the raw data from different sources (which may be in +/// different formats) can be consumed with a consistent API. +public struct ObjectData { + public let _transformer: _ObjectData_Transformer + public let _rawData: [String: AnyHashable] + + public init( + _transformer: _ObjectData_Transformer, + _rawData: [String: AnyHashable] + ) { + self._transformer = _transformer + self._rawData = _rawData + } + + @inlinable public subscript(_ key: String) -> (any ScalarType)? { + guard let rawValue = _rawData[key] else { return nil } + var value: AnyHashable = rawValue + + // Attempting cast to `Int` to ensure we always use `Int` vs `Int32` or `Int64` for consistency and ScalarType casting, + // also need to attempt `Bool` cast first to ensure a bool doesn't get inadvertently converted to `Int` + switch value { + case let boolVal as Bool: + value = boolVal + case let intVal as Int: + value = intVal + default: + break + } + + return _transformer.transform(value) + } + + @_disfavoredOverload + @inlinable public subscript(_ key: String) -> ObjectData? { + guard let value = _rawData[key] else { return nil } + return _transformer.transform(value) + } + + @_disfavoredOverload + @inlinable public subscript(_ key: String) -> ListData? { + guard let value = _rawData[key] else { return nil } + return _transformer.transform(value) + } + +} + +/// An opaque wrapper for data representing the value for a list field on a GraphQL object. +/// This type wraps data from different sources, using a `_transformer` to ensure the raw data from +/// different sources (which may be in different formats) can be consumed with a consistent API. +public struct ListData { + public let _transformer: _ObjectData_Transformer + public let _rawData: [AnyHashable] + + public init( + _transformer: _ObjectData_Transformer, + _rawData: [AnyHashable] + ) { + self._transformer = _transformer + self._rawData = _rawData + } + + @inlinable public subscript(_ key: Int) -> (any ScalarType)? { + var value: AnyHashable = _rawData[key] + + // Attempting cast to `Int` to ensure we always use `Int` vs `Int32` or `Int64` for consistency and ScalarType casting, + // also need to attempt `Bool` cast first to ensure a bool doesn't get inadvertently converted to `Int` + switch value { + case let boolVal as Bool: + value = boolVal + case let intVal as Int: + value = intVal + default: + break + } + + return _transformer.transform(value) + } + + @_disfavoredOverload + @inlinable public subscript(_ key: Int) -> ObjectData? { + return _transformer.transform(_rawData[key]) + } + + @_disfavoredOverload + @inlinable public subscript(_ key: Int) -> ListData? { + return _transformer.transform(_rawData[key]) + } +} diff --git a/Sources/ApolloAPI/OutputTypeConvertible.swift b/Sources/ApolloAPI/OutputTypeConvertible.swift new file mode 100644 index 0000000000..5eea4dd621 --- /dev/null +++ b/Sources/ApolloAPI/OutputTypeConvertible.swift @@ -0,0 +1,40 @@ +public protocol OutputTypeConvertible { + @inlinable static var _asOutputType: Selection.Field.OutputType { get } +} + +extension String: OutputTypeConvertible { + public static let _asOutputType: Selection.Field.OutputType = .nonNull(.scalar(String.self)) +} +extension Int: OutputTypeConvertible { + public static let _asOutputType: Selection.Field.OutputType = .nonNull(.scalar(Int.self)) +} +extension Bool: OutputTypeConvertible { + public static let _asOutputType: Selection.Field.OutputType = .nonNull(.scalar(Bool.self)) +} +extension Float: OutputTypeConvertible { + public static let _asOutputType: Selection.Field.OutputType = .nonNull(.scalar(Float.self)) +} +extension Double: OutputTypeConvertible { + public static let _asOutputType: Selection.Field.OutputType = .nonNull(.scalar(Double.self)) +} + +extension Optional: OutputTypeConvertible where Wrapped: OutputTypeConvertible { + @inlinable public static var _asOutputType: Selection.Field.OutputType { + guard case let .nonNull(wrappedOutputType) = Wrapped._asOutputType else { + return Wrapped._asOutputType + } + return wrappedOutputType + } +} + +extension Array: OutputTypeConvertible where Element: OutputTypeConvertible { + @inlinable public static var _asOutputType: Selection.Field.OutputType { + .nonNull(.list(Element._asOutputType)) + } +} + +extension RootSelectionSet { + @inlinable public static var _asOutputType: Selection.Field.OutputType { + .nonNull(.object(self)) + } +} diff --git a/Sources/ApolloAPI/ParentType.swift b/Sources/ApolloAPI/ParentType.swift new file mode 100644 index 0000000000..207392a122 --- /dev/null +++ b/Sources/ApolloAPI/ParentType.swift @@ -0,0 +1,45 @@ +/// A protocol for a type that represents the `__parentType` of a ``SelectionSet``. +/// +/// A ``SelectionSet``'s `__parentType` is the type from the schema that the selection set is +/// selected against. This type can be an ``Object``, ``Interface``, or ``Union``. +public protocol ParentType { + /// A helper function to determine if an ``Object`` of the given type can be converted to + /// the receiver type. + /// + /// A type can be converted to an ``Interface`` type if and only if the type implements + /// the interface. + /// (ie. The ``Interface`` is contained in the ``Object``'s ``Object/implementedInterfaces``.) + /// + /// A type can be converted to a ``Union`` type if and only if the union includes the type. + /// (ie. The ``Object`` Type is contained in the ``Union``'s ``Union/possibleTypes``.) + /// + /// - Parameter objectType: An ``Object`` type to determine conversion compatibility for + /// - Returns: A `Bool` indicating if the type is compatible for conversion to the receiver type + @inlinable func canBeConverted(from objectType: Object) -> Bool + + @inlinable var __typename: String { get } +} + +extension Object: ParentType { + @inlinable public func canBeConverted(from objectType: Object) -> Bool { + objectType.typename == self.typename + } + + @inlinable public var __typename: String { self.typename } +} + +extension Interface: ParentType { + @inlinable public func canBeConverted(from objectType: Object) -> Bool { + objectType.implements(self) + } + + @inlinable public var __typename: String { self.name } +} + +extension Union: ParentType { + @inlinable public func canBeConverted(from objectType: Object) -> Bool { + possibleTypes.contains(where: { $0 == objectType }) + } + + @inlinable public var __typename: String { self.name } +} diff --git a/Apollo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Sources/ApolloAPI/Resources/PrivacyInfo.xcprivacy similarity index 50% rename from Apollo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to Sources/ApolloAPI/Resources/PrivacyInfo.xcprivacy index 18d981003d..d37d6275f5 100644 --- a/Apollo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/Sources/ApolloAPI/Resources/PrivacyInfo.xcprivacy @@ -2,7 +2,13 @@ - IDEDidComputeMac32BitWarning - + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + NSPrivacyTrackingDomains + + NSPrivacyTracking + diff --git a/Sources/ApolloAPI/ScalarTypes.swift b/Sources/ApolloAPI/ScalarTypes.swift index 9ace4f446d..58c84dfbf7 100644 --- a/Sources/ApolloAPI/ScalarTypes.swift +++ b/Sources/ApolloAPI/ScalarTypes.swift @@ -1,7 +1,53 @@ -public protocol ScalarType {} +/// An abstract protocol that a GraphQL "`scalar`" type must conform to. +/// +/// # See Also +/// [GraphQL Spec - Scalars](http://spec.graphql.org/October2021/#sec-Scalars) +public protocol AnyScalarType: JSONEncodable, AnyHashableConvertible {} + +/// A protocol that represents any GraphQL "`scalar`" defined in the GraphQL Specification. +/// +/// Conforming types are: +/// * `String` +/// * `Int` +/// * `Bool` +/// * `Float` +/// * `Double` +/// +/// # See Also +/// [GraphQL Spec - Scalars](http://spec.graphql.org/October2021/#sec-Scalars) +public protocol ScalarType: + AnyScalarType, + JSONDecodable, + GraphQLOperationVariableValue {} extension String: ScalarType {} extension Int: ScalarType {} +extension Bool: ScalarType {} extension Float: ScalarType {} extension Double: ScalarType {} -extension Bool: ScalarType {} + +/// A protocol a custom GraphQL "`scalar`" must conform to. +/// +/// Custom scalars defined in a schema are generated to conform to the ``CustomScalarType`` +/// protocol. By default, these are generated as typealiases to `String`. You can edit the +/// implementation of a custom scalar in the generated file. *Changes to generated custom scalar +/// types will not be overwritten when running code generation again.* +/// +/// # See Also +/// [GraphQL Spec - Scalars](http://spec.graphql.org/October2021/#sec-Scalars) +public protocol CustomScalarType: + AnyScalarType, + JSONDecodable, + OutputTypeConvertible, + GraphQLOperationVariableValue +{} + +extension CustomScalarType { + @inlinable public static var _asOutputType: Selection.Field.OutputType { + .nonNull(.customScalar(self)) + } +} + +extension Array: AnyScalarType where Array.Element: AnyScalarType & Hashable {} + +extension Optional: AnyScalarType where Wrapped: AnyScalarType & Hashable {} diff --git a/Sources/ApolloAPI/SchemaConfiguration.swift b/Sources/ApolloAPI/SchemaConfiguration.swift new file mode 100644 index 0000000000..b0c9473f75 --- /dev/null +++ b/Sources/ApolloAPI/SchemaConfiguration.swift @@ -0,0 +1,43 @@ +/// A protocol for an object used to provide custom configuration for a generated GraphQL schema. +/// +/// A ``SchemaConfiguration`` provides an entry point for customizing the cache key resolution +/// for the types in the schema, which is used by `NormalizedCache` mechanisms. +public protocol SchemaConfiguration { + /// The entry point for configuring the cache key resolution + /// for the types in the schema, which is used by `NormalizedCache` mechanisms. + /// + /// The default generated implementation always returns `nil`, disabling all cache normalization. + /// + /// Cache key resolution has a few notable quirks and limitations you should be aware of while + /// implementing your cache key resolution function: + /// + /// 1. While the cache key for an object can use a field from another nested object, if the fields + /// on the referenced object are changed in another operation, the cache key for the dependent + /// object will not be updated. For nested objects that are not normalized with their own cache + /// key, this will never occur, but if the nested object is an entity with its own cache key, it + /// can be mutated independently. In that case, any other objects whose cache keys are dependent + /// on the mutated entity will not be updated automatically. You must take care to update those + /// entities manually with a cache mutation. + /// + /// 2. The `object` passed to this function represents data for an object in an specific operation + /// model, not a type in your schema. This means that + /// [aliased fields](https://spec.graphql.org/draft/#sec-Field-Alias) will be keyed on their + /// alias name, not the name of the field on the schema type. + /// + /// 3. The `object` parameter of this function is an ``ObjectData`` struct that wraps the + /// underlying object data. Because cache key resolution is performed both on raw JSON (from a + /// network response) and `SelectionSet` model data (when writing to the cache directly), + /// the underlying data will have different formats. The ``ObjectData`` wrapper is used to + /// normalize this data to a consistent format in this context. + /// + /// # See Also + /// ``CacheKeyInfo`` + /// + /// - Parameters: + /// - type: The ``Object`` type of the response `object`. + /// - object: The response object to resolve the cache key for. + /// Represented as a ``ObjectData`` dictionary. + /// - Returns: A ``CacheKeyInfo`` describing the computed cache key for the response object. + static func cacheKeyInfo(for type: Object, object: ObjectData) -> CacheKeyInfo? + +} diff --git a/Sources/ApolloAPI/SchemaMetadata.swift b/Sources/ApolloAPI/SchemaMetadata.swift new file mode 100644 index 0000000000..bc27667bff --- /dev/null +++ b/Sources/ApolloAPI/SchemaMetadata.swift @@ -0,0 +1,62 @@ +/// A protocol that a generated GraphQL schema should conform to. +/// +/// The generated schema metadata is the source of information about the generated types in the +/// schema. It is used to map each object in a `GraphQLResponse` to the ``Object`` type +/// representing the response object. +public protocol SchemaMetadata { + + /// A ``SchemaConfiguration`` that provides custom configuration for the generated GraphQL schema. + static var configuration: SchemaConfiguration.Type { get } + + /// Maps each object in a `GraphQLResponse` to the ``Object`` type representing the + /// response object. + /// + /// > Note: This function will be generated by the code generation engine. You should never + /// alter the generated implementation or implement this function manually. + /// + /// - Parameter typename: The value of the `__typename` field of the response object. + /// - Returns: An ``Object`` type representing the response object if the type is known to the + /// schema. If the schema does not include a known ``Object`` with the given ``Object/typename``, + /// returns `nil`. + static func objectType(forTypename typename: String) -> Object? +} + +extension SchemaMetadata { + + /// A convenience function for getting the ``Object`` type representing a response object. + /// + /// Calls the ``objectType(forTypename:)`` function with the value of the objects `__typename` + /// field. + /// + /// - Parameter object: A ``JSONObject`` dictionary representing an object in a GraphQL response. + /// - Returns: An ``Object`` type representing the response object if the type is known to the + /// schema. If the schema does not include a known ``Object`` with the given ``Object/typename``, + /// returns `nil`. + @inlinable public static func graphQLType(for object: ObjectData) -> Object? { + guard let typename = object["__typename"] as? String else { + return nil + } + return objectType(forTypename: typename) ?? + Object(typename: typename, implementedInterfaces: []) + } + + /// Resolves the cache key for an object in a GraphQL response to be used by + /// `NormalizedCache` mechanisms. + /// + /// Maps the type of the `object` using the ``graphQLType(for:)`` function, then gets the + /// ``CacheKeyInfo`` for the `object` using the ``SchemaConfiguration/cacheKeyInfo(for:object:)`` + /// function. + /// Finally, this function transforms the ``CacheKeyInfo`` into the correct ``CacheReference`` + /// for the `NormalizedCache`. + /// + /// - Parameter object: A ``JSONObject`` dictionary representing an object in a GraphQL response. + /// - Returns: A `String` representing the cache key for the `object` to be used by + /// `NormalizedCache` mechanisms. + @inlinable public static func cacheKey(for object: ObjectData) -> String? { + guard let type = graphQLType(for: object), + let info = configuration.cacheKeyInfo(for: type, object: object) else { + return nil + } + return "\(info.uniqueKeyGroup ?? type.typename):\(info.id)" + } +} diff --git a/Sources/ApolloAPI/SchemaTypes/EnumType.swift b/Sources/ApolloAPI/SchemaTypes/EnumType.swift new file mode 100644 index 0000000000..5585849ca4 --- /dev/null +++ b/Sources/ApolloAPI/SchemaTypes/EnumType.swift @@ -0,0 +1,14 @@ +/// A protocol that an enum in a generated GraphQL schema conforms to. +/// +/// When used as an input value or the value of a field in a generated ``SelectionSet``, each +/// generated ``EnumType`` will be wrapped in a ``GraphQLEnum`` which provides support for handling +/// unknown enum cases that were not included in the schema at the time of code generation. +/// +/// # See Also +/// [GraphQLSpec - Enums](https://spec.graphql.org/draft/#sec-Enums) +public protocol EnumType: + RawRepresentable, + CaseIterable, + JSONEncodable, + GraphQLOperationVariableValue +where RawValue == String {} diff --git a/Sources/ApolloAPI/SchemaTypes/InputObject.swift b/Sources/ApolloAPI/SchemaTypes/InputObject.swift new file mode 100644 index 0000000000..cb8389dfe9 --- /dev/null +++ b/Sources/ApolloAPI/SchemaTypes/InputObject.swift @@ -0,0 +1,46 @@ +/// An protocol for a struct that represents a GraphQL Input Object. +/// +/// # See Also +/// [GraphQLSpec - Input Objects](https://spec.graphql.org/draft/#sec-Input-Objects) +public protocol InputObject: GraphQLOperationVariableValue, JSONEncodable, Hashable { + var __data: InputDict { get } +} + +extension InputObject { + public var _jsonValue: JSONValue { jsonEncodableValue?._jsonValue } + public var jsonEncodableValue: (any JSONEncodable)? { __data._jsonEncodableValue } + + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.__data == rhs.__data + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(__data) + } +} + +/// A structure that wraps the underlying data dictionary used by `InputObject`s. +public struct InputDict: GraphQLOperationVariableValue, Hashable { + + private var data: [String: GraphQLOperationVariableValue] + + public init(_ data: [String: GraphQLOperationVariableValue] = [:]) { + self.data = data + } + + public var _jsonEncodableValue: (any JSONEncodable)? { data._jsonEncodableObject } + + public subscript(key: String) -> T { + get { data[key] as! T } + set { data[key] = newValue } + } + + public static func == (lhs: InputDict, rhs: InputDict) -> Bool { + lhs.data._jsonEncodableValue?._jsonValue == rhs.data._jsonEncodableValue?._jsonValue + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(data._jsonEncodableValue?._jsonValue) + } + +} diff --git a/Sources/ApolloAPI/SchemaTypes/Interface.swift b/Sources/ApolloAPI/SchemaTypes/Interface.swift new file mode 100644 index 0000000000..eee08ee68f --- /dev/null +++ b/Sources/ApolloAPI/SchemaTypes/Interface.swift @@ -0,0 +1,17 @@ +/// Represents an `interface` type in a generated GraphQL schema. +/// +/// Each `interface` defined in the GraphQL schema will have an instance of ``Interface`` generated. +/// +/// # See Also +/// [GraphQLSpec - Interfaces](https://spec.graphql.org/draft/#sec-Interfaces) +public struct Interface: Hashable, Sendable { + /// The name of the ``Interface`` in the GraphQL schema. + public let name: String + + /// Designated Initializer + /// + /// - Parameter name: The name of the ``Interface`` in the GraphQL schema. + public init(name: String) { + self.name = name + } +} diff --git a/Sources/ApolloAPI/SchemaTypes/Object.swift b/Sources/ApolloAPI/SchemaTypes/Object.swift new file mode 100644 index 0000000000..7eeffcfad6 --- /dev/null +++ b/Sources/ApolloAPI/SchemaTypes/Object.swift @@ -0,0 +1,37 @@ +/// Represents an object `type` in a generated GraphQL schema. +/// +/// Each `type` defined in the GraphQL schema will have an instance of ``Object`` generated. +/// # See Also +/// [GraphQLSpec - Objects](https://spec.graphql.org/draft/#sec-Objects) +public struct Object: Hashable, Sendable { + + /// Designated Initializer + /// + /// - Parameters: + /// - typename: The name of the type. + /// - implementedInterfaces: A list of the interfaces implemented by the type. + public init( + typename: String, + implementedInterfaces: [Interface] + ) { + self.typename = typename + self.implementedInterfaces = implementedInterfaces + } + + /// A list of the interfaces implemented by the type. + public let implementedInterfaces: [Interface] + + /// The name of the type. + /// + /// When an entity of the type is included in a GraphQL response its `__typename` field will + /// match this value. + public let typename: String + + /// A helper function to determine if the receiver implements a given ``Interface`` Type. + /// + /// - Parameter interface: An ``Interface`` Type + /// - Returns: A `Bool` indicating if the receiver implements the given ``Interface`` Type. + public func implements(_ interface: Interface) -> Bool { + implementedInterfaces.contains(where: { $0 == interface }) + } +} diff --git a/Sources/ApolloAPI/SchemaTypes/Union.swift b/Sources/ApolloAPI/SchemaTypes/Union.swift new file mode 100644 index 0000000000..c6ed6a3e87 --- /dev/null +++ b/Sources/ApolloAPI/SchemaTypes/Union.swift @@ -0,0 +1,24 @@ +/// Represents a `union` type in a generated GraphQL schema. +/// +/// Each `union` defined in the GraphQL schema will have an instance of ``Union`` generated. +/// +/// # See Also +/// [GraphQLSpec - Unions](https://spec.graphql.org/draft/#sec-Unions) +public struct Union: Hashable, Sendable { + /// The name of the ``Union`` in the GraphQL schema. + public let name: String + + /// The ``Object`` types included in the `union`. + public let possibleTypes: [Object] + + /// Designated Initializer + /// + /// - Parameters: + /// - name: The name of the ``Union`` in the GraphQL schema. + /// - possibleTypes: The ``Object`` types included in the `union`. + public init(name: String, possibleTypes: [Object]) { + self.name = name + self.possibleTypes = possibleTypes + } + +} diff --git a/Sources/ApolloAPI/Selection+Conditions.swift b/Sources/ApolloAPI/Selection+Conditions.swift new file mode 100644 index 0000000000..f19756c22e --- /dev/null +++ b/Sources/ApolloAPI/Selection+Conditions.swift @@ -0,0 +1,139 @@ +public extension Selection { + /// The conditions representing a group of `@include/@skip` directives. + /// + /// The conditions are a two-dimensional array of `Selection.Condition`s. + /// The outer array represents groups of conditions joined together with a logical "or". + /// Conditions in the same inner array are joined together with a logical "and". + struct Conditions: Hashable { + public let value: [[Condition]] + + public init(_ value: [[Condition]]) { + self.value = value + } + + public init(_ conditions: [Condition]...) { + self.value = Array(conditions) + } + + public init(_ condition: Condition) { + self.value = [[condition]] + } + + @inlinable public static func ||(_ lhs: Conditions, rhs: [Condition]) -> Conditions { + var newValue = lhs.value + newValue.append(rhs) + return .init(newValue) + } + + @inlinable public static func ||(_ lhs: Conditions, rhs: Condition) -> Conditions { + lhs || [rhs] + } + } + + enum Condition: ExpressibleByStringLiteral, ExpressibleByBooleanLiteral, Hashable { + case value(Bool) + case variable(name: String, inverted: Bool) + + public init( + variableName: String, + inverted: Bool + ) { + self = .variable(name: variableName, inverted: inverted) + } + + public init(stringLiteral value: StringLiteralType) { + self = .variable(name: value, inverted: false) + } + + public init(booleanLiteral value: BooleanLiteralType) { + self = .value(value) + } + + @inlinable public static func `if`(_ condition: StringLiteralType) -> Condition { + .variable(name: condition, inverted: false) + } + + @inlinable public static func `if`(_ condition: Condition) -> Condition { + condition + } + + @inlinable public static prefix func !(condition: Condition) -> Condition { + switch condition { + case let .value(value): + return .value(!value) + case let .variable(name, inverted): + return .init(variableName: name, inverted: !inverted) + } + } + + @inlinable public static func &&(_ lhs: Condition, rhs: Condition) -> [Condition] { + [lhs, rhs] + } + + @inlinable public static func &&(_ lhs: [Condition], rhs: Condition) -> [Condition] { + var newValue = lhs + newValue.append(rhs) + return newValue + } + + @inlinable public static func ||(_ lhs: Condition, rhs: Condition) -> Conditions { + .init([[lhs], [rhs]]) + } + + @inlinable public static func ||(_ lhs: [Condition], rhs: Condition) -> Conditions { + .init([lhs, [rhs]]) + } + + } +} + +// MARK: - Evaluation + +// MARK: Conditions - Or Group +public extension Selection.Conditions { + func evaluate(with variables: GraphQLOperation.Variables?) -> Bool { + for andGroup in value { + if andGroup.evaluate(with: variables) { + return true + } + } + return false + } +} + +// MARK: Conditions - And Group +fileprivate extension Array where Element == Selection.Condition { + func evaluate(with variables: GraphQLOperation.Variables?) -> Bool { + for condition in self { + if !condition.evaluate(with: variables) { + return false + } + } + return true + } +} + +// MARK: Conditions - Individual +fileprivate extension Selection.Condition { + func evaluate(with variables: GraphQLOperation.Variables?) -> Bool { + switch self { + case let .value(value): + return value + case let .variable(variableName, inverted): + switch variables?[variableName] { + case let boolValue as Bool: + return inverted ? !boolValue : boolValue + + case let nullable as GraphQLNullable: + let evaluated = nullable.unwrapped ?? false + return inverted ? !evaluated : evaluated + + case .none: + return false + + case let .some(wrapped): + fatalError("Expected Bool for \(variableName), got \(wrapped)") + } + } + } +} diff --git a/Sources/ApolloAPI/Selection.swift b/Sources/ApolloAPI/Selection.swift new file mode 100644 index 0000000000..46c62c4e37 --- /dev/null +++ b/Sources/ApolloAPI/Selection.swift @@ -0,0 +1,184 @@ +public enum Selection { + /// A single field selection. + case field(Field) + /// A fragment spread of a named fragment definition. + case fragment(any Fragment.Type) + /// An inline fragment with a child selection set nested in a parent selection set. + case inlineFragment(any InlineFragment.Type) + /// A fragment spread or inline fragment marked with the `@defer` directive. + case deferred(if: Condition? = nil, any Deferrable.Type, label: String?) + /// A group of selections that have `@include/@skip` directives. + case conditional(Conditions, [Selection]) + + public struct Field { + public let name: String + public let alias: String? + public let arguments: [String: InputValue]? + public let type: OutputType + + public var responseKey: String { + return alias ?? name + } + + public init( + _ name: String, + alias: String? = nil, + type: OutputType, + arguments: [String: InputValue]? = nil + ) { + self.name = name + self.alias = alias + self.arguments = arguments + self.type = type + } + + public indirect enum OutputType { + case scalar(any ScalarType.Type) + case customScalar(any CustomScalarType.Type) + case object(any RootSelectionSet.Type) + case nonNull(OutputType) + case list(OutputType) + + public var namedType: OutputType { + switch self { + case .nonNull(let innerType), .list(let innerType): + return innerType.namedType + case .scalar, .customScalar, .object: + return self + } + } + + public var isNullable: Bool { + if case .nonNull = self { return false } + return true + } + } + } + + // MARK: - Convenience Initializers + + @inlinable static public func field( + _ name: String, + alias: String? = nil, + _ type: OutputTypeConvertible.Type, + arguments: [String: InputValue]? = nil + ) -> Selection { + .field(.init(name, alias: alias, type: type._asOutputType, arguments: arguments)) + } + + @inlinable static public func include( + if condition: String, + _ selection: Selection + ) -> Selection { + .conditional(Conditions([[Selection.Condition(stringLiteral: condition)]]), [selection]) + } + + @inlinable static public func include( + if condition: String, + _ selections: [Selection] + ) -> Selection { + .conditional(Conditions([[Selection.Condition(stringLiteral: condition)]]), selections) + } + + @inlinable static public func include( + if conditions: Conditions, + _ selection: Selection + ) -> Selection { + .conditional(conditions, [selection]) + } + + @inlinable static public func include( + if conditions: Conditions, + _ selections: [Selection] + ) -> Selection { + .conditional(conditions, selections) + } + + @inlinable static public func include( + if condition: Condition, + _ selection: Selection + ) -> Selection { + .conditional(Conditions([[condition]]), [selection]) + } + + @inlinable static public func include( + if condition: Condition, + _ selections: [Selection] + ) -> Selection { + .conditional(Conditions([[condition]]), selections) + } + + @inlinable static public func include( + if conditions: [Condition], + _ selection: Selection + ) -> Selection { + .conditional(Conditions([conditions]), [selection]) + } + + @inlinable static public func include( + if conditions: [Condition], + _ selections: [Selection] + ) -> Selection { + .conditional(Conditions([conditions]), selections) + } + +} + +// MARK: - Hashable Conformance + +extension Selection: Hashable { + public static func == (lhs: Selection, rhs: Selection) -> Bool { + switch (lhs, rhs) { + case let (.field(lhs), .field(rhs)): + return lhs == rhs + case let (.fragment(lhsFragment), .fragment(rhsFragment)): + return lhsFragment == rhsFragment + case let (.inlineFragment(lhsFragment), .inlineFragment(rhsFragment)): + return lhsFragment == rhsFragment + case let (.deferred(lhsCondition, lhsFragment, lhsLabel), + .deferred(rhsCondition, rhsFragment, rhsLabel)): + return lhsCondition == rhsCondition && + lhsFragment == rhsFragment && + lhsLabel == rhsLabel + case let (.conditional(lhsConditions, lhsSelections), + .conditional(rhsConditions, rhsSelections)): + return lhsConditions == rhsConditions && lhsSelections == rhsSelections + default: return false + } + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(self) + } +} + +extension Selection.Field: Hashable { + public static func == (lhs: Selection.Field, rhs: Selection.Field) -> Bool { + lhs.name == rhs.name && + lhs.alias == rhs.alias && + lhs.arguments == rhs.arguments && + lhs.type == rhs.type + } +} + +extension Selection.Field.OutputType: Hashable { + public static func == (lhs: Selection.Field.OutputType, rhs: Selection.Field.OutputType) -> Bool { + switch (lhs, rhs) { + case let (.scalar(lhs), .scalar(rhs)): + return lhs == rhs + case let (.customScalar(lhs), .customScalar(rhs)): + return lhs == rhs + case let (.object(lhs), .object(rhs)): + return lhs == rhs + case let (.nonNull(lhs), .nonNull(rhs)): + return lhs == rhs + case let (.list(lhs), .list(rhs)): + return lhs == rhs + default: return false + } + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(self) + } +} diff --git a/Sources/ApolloAPI/SelectionSet.swift b/Sources/ApolloAPI/SelectionSet.swift new file mode 100644 index 0000000000..d8ceca55da --- /dev/null +++ b/Sources/ApolloAPI/SelectionSet.swift @@ -0,0 +1,131 @@ +/// A selection set that represents the root selections on its `__parentType`. Nested selection +/// sets for type cases are not `RootSelectionSet`s. +/// +/// While a `TypeCase` only provides the additional selections that should be selected for its +/// specific type, a `RootSelectionSet` guarantees that all fields for itself and its nested type +/// cases are selected. +/// +/// When considering a specific `TypeCase`, all fields will be selected either by the root selection +/// set, a fragment spread, the type case itself, or another compatible `TypeCase` on the root +/// selection set. +/// +/// This is why only a `RootSelectionSet` can be executed by a `GraphQLExecutor`. Executing a +/// non-root selection set would result in fields from the root selection set not being collected +/// into the `ResponseDict` for the `SelectionSet`'s data. +public protocol RootSelectionSet: SelectionSet, SelectionSetEntityValue, OutputTypeConvertible { } + +/// A selection set that represents an inline fragment nested inside a `RootSelectionSet`. +/// +/// An `InlineFragment` can only ever exist as a nested selection set within a `RootSelectionSet`. +/// Each `InlineFragment` represents additional fields to be selected if the underlying +/// type.inclusion condition of the object data returned for the selection set is met. +/// +/// An `InlineFragment` will only include the specific `selections` that should be selected for that +/// `InlineFragment`. But the code generation engine will create accessor fields for any fields +/// from the fragment's parent `RootSelectionSet` that will be selected. This includes fields from +/// the parent selection set, as well as any other child selections sets that are compatible with +/// the `InlineFragment`'s `__parentType` and the operation's inclusion condition. +public protocol InlineFragment: SelectionSet { + associatedtype RootEntityType: RootSelectionSet +} + +/// A selection set that is comprised of only fields merged from other selection sets. +/// +/// A `CompositeSelectionSet` has no direct selections of its own, rather it is composed of +/// selections merged from multiple other selection sets. A `CompositeSelectionSet` is generated +/// when an entity in a given scope would include distinct selections from multiple other scopes +/// but is not defined in the operation/fragment definition itself. +public protocol CompositeSelectionSet: SelectionSet {} + +/// An `InlineFragment` that is also a `CompositeSelectionSet`. +public protocol CompositeInlineFragment: CompositeSelectionSet, InlineFragment { + + /// A list of the selection sets that the selection set is composed of. + static var __mergedSources: [any SelectionSet.Type] { get } + +} + +// MARK: - SelectionSet +public protocol SelectionSet: Hashable { + associatedtype Schema: SchemaMetadata + + /// A type representing all of the fragments the `SelectionSet` can be converted to. + /// Defaults to a stub type with no fragments. + /// A `SelectionSet` with fragments should provide a type that conforms to `FragmentContainer` + associatedtype Fragments = NoFragments + + static var __selections: [Selection] { get } + + /// The GraphQL type for the `SelectionSet`. + /// + /// This may be a concrete type (`Object`) or an abstract type (`Interface`, or `Union`). + static var __parentType: ParentType { get } + + /// The data of the underlying GraphQL object represented by the generated selection set. + var __data: DataDict { get } + + /// **For Internal Use Only -** Designated Initializer + /// + /// - Warning: This initializer is not supported for public use. It should only be used by the + /// `GraphQLSelectionSetMapper`, which is guaranteed by the GraphQL compiler to be safe. + /// Unsupported usage may result in unintended consequences including crashes. + /// + /// To manually initialize a ``SelectionSet`` model with JSON data, use + /// `SelectionSet.init(data: JSONObject, variables: GraphQLOperation.Variables?)` in + /// the `Apollo` library. + /// + /// To generate type safe initializers for your selection set models, use the + /// `selectionSetInitializers` option in your code generation configuration. + /// + /// - Parameter dataDict: The data of the underlying GraphQL object represented by the generated + /// selection set. + init(_dataDict: DataDict) +} + +extension SelectionSet { + + @inlinable public static var __selections: [Selection] { [] } + + @inlinable public var __objectType: Object? { + guard let __typename else { return nil } + return Schema.objectType(forTypename: __typename) + } + + @inlinable public var __typename: String? { __data["__typename"] } + + /// Verifies if a `SelectionSet` may be converted to an `InlineFragment` and performs + /// the conversion. + /// + /// - Warning: This function is not supported for use outside of generated call sites. + /// Generated call sites are guaranteed by the GraphQL compiler to be safe. + /// Unsupported usage may result in unintended consequences including crashes. + @_disfavoredOverload + @inlinable public func _asInlineFragment() -> T? { + guard __data.fragmentIsFulfilled(T.self) else { return nil } + return T.init(_dataDict: __data) + } + + @inlinable public func _asInlineFragment() -> T? { + guard __data.fragmentsAreFulfilled(T.__mergedSources) else { return nil } + return T.init(_dataDict: __data) + } + + @inlinable public func hash(into hasher: inout Hasher) { + hasher.combine(__data) + } + + @inlinable public static func ==(lhs: Self, rhs: Self) -> Bool { + return lhs.__data == rhs.__data + } +} + +extension SelectionSet where Fragments: FragmentContainer { + /// Contains accessors for all of the fragments the `SelectionSet` can be converted to. + public var fragments: Fragments { Fragments(_dataDict: __data) } +} + +extension InlineFragment { + @inlinable public var asRootEntityType: RootEntityType { + RootEntityType.init(_dataDict: __data) + } +} diff --git a/Sources/ApolloCodegenLib/ApolloCLI.swift b/Sources/ApolloCodegenLib/ApolloCLI.swift deleted file mode 100644 index 341bc9940a..0000000000 --- a/Sources/ApolloCodegenLib/ApolloCLI.swift +++ /dev/null @@ -1,93 +0,0 @@ -import Foundation - -// Only available on macOS -#if os(macOS) - -/// Wrapper for calling the bundled node-based Apollo CLI. -public struct ApolloCLI { - - enum ApolloCLIError: Error { - case lockInitializationFailed(URL) - case timedOutWaitingOnLock(URL) - } - - /// Creates an instance of `ApolloCLI`, downloading and extracting if needed - /// - /// - Parameters: - /// - cliFolderURL: The URL to the folder which contains the zip file with the CLI. - /// - timeout: The maximum time to wait before indicating that the download timed out, in seconds. - public static func createCLI(cliFolderURL: URL, timeout: Double) throws -> ApolloCLI { - let lock = try waitForCLIFolderLock(cliFolderURL: cliFolderURL, timeout: timeout) - defer { lock.unlock() } - - try CLIDownloader.downloadIfNeeded(to: cliFolderURL, timeout: timeout) - - if !(try CLIExtractor.validateSHASUMOfDownloadedFile(in: cliFolderURL)) { - CodegenLogger.log("Downloaded zip file has incorrect SHASUM, forcing redownload") - try CLIDownloader.forceRedownload(to: cliFolderURL, timeout: timeout) - } - - let binaryFolderURL = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - return ApolloCLI(binaryFolderURL: binaryFolderURL) - } - - private static func waitForCLIFolderLock(cliFolderURL: URL, timeout: Double) throws -> NSDistributedLock { - guard let lock = NSDistributedLock(path: cliFolderURL.path + ".lock") else { - throw ApolloCLIError.lockInitializationFailed(cliFolderURL) - } - - let maxPollCount = Int(timeout*2) - var pollCount = 0 - - repeat { - if lock.try() { - return lock - - } else { - pollCount += 1 - - if pollCount <= maxPollCount { - usleep(500_000) // sleep 0.5 seconds - } else { - throw ApolloCLIError.timedOutWaitingOnLock(cliFolderURL) - } - } - } while pollCount <= maxPollCount - - return lock - } - - public let binaryFolderURL: URL - - /// Designated initializer - /// - /// - Parameter binaryFolderURL: The folder where the extracted binary files live. - public init(binaryFolderURL: URL) { - self.binaryFolderURL = binaryFolderURL - } - - var scriptPath: String { - return self.binaryFolderURL.path + "/run" - } - - /// Runs a command with the bundled Apollo CLI - /// - /// NOTE: Will always run the `--version` command first for debugging purposes. - /// - Parameter arguments: The arguments to hand to the CLI - /// - Parameter folder: The folder to run the command from. - public func runApollo(with arguments: [String], - from folder: URL? = nil) throws -> String { - // Add the binary folder URL to $PATH so the script can find pre-compiled `node` - let command = "export PATH=$PATH:'\(self.binaryFolderURL.path)'" + - // Log out the version for debugging purposes - " && '\(self.scriptPath)' --version" + - // Set the final command to log out the passed-in arguments for debugging purposes - " && set -x" + - // Actually run the script with the given options. - " && '\(self.scriptPath)' \(arguments.joined(separator: " "))" - - return try Basher.run(command: command, from: folder) - } -} - -#endif diff --git a/Sources/ApolloCodegenLib/ApolloCodegen.swift b/Sources/ApolloCodegenLib/ApolloCodegen.swift deleted file mode 100644 index 13c62a3004..0000000000 --- a/Sources/ApolloCodegenLib/ApolloCodegen.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Foundation - -// Only available on macOS -#if os(macOS) - -/// A class to facilitate running code generation -public class ApolloCodegen { - - /// Errors which can happen with code generation - public enum CodegenError: Error, LocalizedError { - case folderDoesNotExist(_ url: URL) - case multipleFilesButNotDirectoryURL(_ url: URL) - case singleFileButNotSwiftFileURL(_ url: URL) - - public var errorDescription: String? { - switch self { - case .folderDoesNotExist(let url): - return "Can't run codegen trying to run the command from \(url) because there is no folder there! This should be the folder which, at some depth, contains all your `.graphql` files." - case .multipleFilesButNotDirectoryURL(let url): - return "Codegen is requesting multiple file generation, but the URL passed in (\(url)) is not a directory URL. Please check your URL and try again." - case .singleFileButNotSwiftFileURL(let url): - return "Codegen is requesting single file generation, but the URL passed in (\(url)) is a not a Swift file URL. Please check your URL and try again." - } - } - } - - /// Runs code generation from the given folder with the passed-in options - /// - /// - Parameters: - /// - folder: The folder to run the script from. Should be the folder that at some depth, contains all `.graphql` files. - /// - cliFolderURL: The folder where the Apollo CLI is/should be downloaded. - /// - options: The options object to use to run the code generation. - /// - Returns: Output from a successful run - @discardableResult - public static func run(from folder: URL, - with cliFolderURL: URL, - options: ApolloCodegenOptions) throws -> String { - guard FileManager.default.apollo.folderExists(at: folder) else { - throw CodegenError.folderDoesNotExist(folder) - } - - switch options.outputFormat { - case .multipleFiles(let folderURL): - /// We have to try to create the folder first because the stuff - /// underlying `isDirectoryURL` only works on actual directories - try FileManager.default.apollo.createFolderIfNeeded(at: folderURL) - guard folderURL.apollo.isDirectoryURL else { - throw CodegenError.multipleFilesButNotDirectoryURL(folderURL) - } - case .singleFile(let fileURL): - if options.codegenEngine == .typescript { - guard fileURL.apollo.isSwiftFileURL else { - throw CodegenError.singleFileButNotSwiftFileURL(fileURL) - } - } // else we're fine with JSON at this point for intermediate purposes. - - try FileManager.default.apollo.createContainingFolderIfNeeded(for: fileURL) - } - - let cli = try ApolloCLI.createCLI(cliFolderURL: cliFolderURL, timeout: options.downloadTimeout) - return try cli.runApollo(with: options.arguments, from: folder) - } -} - -#endif diff --git a/Sources/ApolloCodegenLib/ApolloCodegenOptions.swift b/Sources/ApolloCodegenLib/ApolloCodegenOptions.swift deleted file mode 100644 index c111f16e85..0000000000 --- a/Sources/ApolloCodegenLib/ApolloCodegenOptions.swift +++ /dev/null @@ -1,216 +0,0 @@ -import Foundation - -/// An object to hold all the various options for running codegen -public struct ApolloCodegenOptions { - - /// Enum to select how you want to export your API files. - public enum OutputFormat { - /// Outputs everything into a single file at the given URL. - /// NOTE: URL must be a file URL - case singleFile(atFileURL: URL) - /// Outputs everything into individual files in a folder a the given URL - /// NOTE: URL must be a folder URL - case multipleFiles(inFolderAtURL: URL) - } - - /// Enum to select which code generation you wish to use - public enum CodeGenerationEngine: Equatable { - /// The default, tried and true code generation engine - case typescript - - /// The current default for the code generation engine. - public static var `default`: CodeGenerationEngine { - .typescript - } - - var targetForApolloTools: String { - switch self { - case .typescript: - return "swift" - } - } - } - - /// The possible access modifiers for code generated by this tool. - public enum AccessModifier { - case `public` - case `internal` - case `none` - - /// The prefix which should be used for classes, enums, and structs generated by this tool. - public var prefixValue: String { - switch self { - case .public: return "public " - case .internal: return "internal " - case .none: return "" - } - } - } - - /// Enum to select how to handle properties using a custom scalar from the schema. - public enum CustomScalarFormat: Equatable { - /// Uses a default type instead of a custom scalar. - case none - /// Use your own types for custom scalars. - case passthrough - /// Use your own types for custom scalars with a prefix. - case passthroughWithPrefix(String) - } - - let codegenEngine: CodeGenerationEngine - let includes: String - let excludes: String? - let mergeInFieldsFromFragmentSpreads: Bool - let namespace: String? - let modifier: AccessModifier - let only: URL? - let omitDeprecatedEnumCases: Bool - let operationIDsURL: URL? - let outputFormat: OutputFormat - let customScalarFormat: CustomScalarFormat - let suppressSwiftMultilineStringLiterals: Bool - let urlToSchemaFile: URL - - let downloadTimeout: Double - - /// Designated initializer. - /// - /// - Parameters: - /// - codegenEngine: The code generation engine to use. Defaults to `CodeGenerationEngine.default` - /// - includes: Glob of files to search for GraphQL operations. This should be used to find queries *and* any client schema extensions. Defaults to `./**/*.graphql`, which will search for `.graphql` files throughout all subfolders of the folder where the script is run. - /// - excludes: Glob of files to exclude for GraphQL operations. Caveat: this doesn't currently work in watch mode - /// - mergeInFieldsFromFragmentSpreads: Set true to merge fragment fields onto its enclosing type. Defaults to true. - /// - modifier: [EXPERIMENTAL SWIFT CODEGEN ONLY] - The access modifier to use on everything created by this tool. Defaults to `.public`. - /// - namespace: [optional] The namespace to emit generated code into. Defaults to nil. - /// - omitDeprecatedEnumCases: Whether deprecated enum cases should be omitted from generated code. Defaults to false. - /// - only: [optional] Parse all input files, but only output generated code for the file at this URL if non-nil. Defaults to nil. - /// - operationIDsURL: [optional] Path to an operation id JSON map file. If specified, also stores the operation ids (hashes) as properties on operation types. Defaults to nil. - /// - outputFormat: The `OutputFormat` enum option to use to output generated code. - /// - customScalarFormat: How to handle properties using a custom scalar from the schema. - /// - suppressSwiftMultilineStringLiterals: Don't use multi-line string literals when generating code. Defaults to false. - /// - urlToSchemaFile: The URL to your schema file. Accepted file types are `.json` for JSON files, or either `.graphqls` or `.sdl` for Schema Definition Language files. - /// - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. - public init(codegenEngine: CodeGenerationEngine = .default, - includes: String = "./**/*.graphql", - excludes: String? = nil, - mergeInFieldsFromFragmentSpreads: Bool = true, - modifier: AccessModifier = .public, - namespace: String? = nil, - omitDeprecatedEnumCases: Bool = false, - only: URL? = nil, - operationIDsURL: URL? = nil, - outputFormat: OutputFormat, - customScalarFormat: CustomScalarFormat = .none, - suppressSwiftMultilineStringLiterals: Bool = false, - urlToSchemaFile: URL, - downloadTimeout: Double = 30.0) { - self.codegenEngine = codegenEngine - self.includes = includes - self.excludes = excludes - self.mergeInFieldsFromFragmentSpreads = mergeInFieldsFromFragmentSpreads - self.modifier = modifier - self.namespace = namespace - self.omitDeprecatedEnumCases = omitDeprecatedEnumCases - self.only = only - self.operationIDsURL = operationIDsURL - self.outputFormat = outputFormat - self.customScalarFormat = customScalarFormat - self.suppressSwiftMultilineStringLiterals = suppressSwiftMultilineStringLiterals - self.urlToSchemaFile = urlToSchemaFile - self.downloadTimeout = downloadTimeout - } - - /// Convenience initializer that takes the root folder of a target and generates - /// code with some default assumptions. - /// Makes the following assumptions: - /// - Schema is at [folder]/schema.json - /// - Output is a single file to [folder]/API.swift - /// - You want operation IDs generated and output to [folder]/operationIDs.json - /// - /// - Parameters: - /// - folder: The root of the target. - /// - codegenEngine: The code generation engine to use. Defaults to `CodeGenerationEngine.default` - /// - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds - public init(targetRootURL folder: URL, - codegenEngine: CodeGenerationEngine = .default, - downloadTimeout: Double = 30.0) { - let schema = folder.appendingPathComponent("schema.graphqls") - - let outputFileURL: URL - switch codegenEngine { - case .typescript: - outputFileURL = folder.appendingPathComponent("API.swift") - } - - let operationIDsURL = folder.appendingPathComponent("operationIDs.json") - - self.init(codegenEngine: codegenEngine, - operationIDsURL: operationIDsURL, - outputFormat: .singleFile(atFileURL: outputFileURL), - urlToSchemaFile: schema, - downloadTimeout: downloadTimeout) - } - - var arguments: [String] { - var arguments = [ - "codegen:generate", - "--target=\(self.codegenEngine.targetForApolloTools)", - "--addTypename", - "--includes='\(self.includes)'", - "--localSchemaFile='\(self.urlToSchemaFile.path)'" - ] - - if let namespace = self.namespace { - arguments.append("--namespace=\(namespace)") - } - - if let only = only { - arguments.append("--only='\(only.path)'") - } - - if let idsURL = self.operationIDsURL { - arguments.append("--operationIdsPath='\(idsURL.path)'") - } - - if let excludes = self.excludes { - arguments.append("--excludes='\(excludes)'") - } - - if self.omitDeprecatedEnumCases { - arguments.append("--omitDeprecatedEnumCases") - } - - switch customScalarFormat { - case .none: - break - case .passthrough: - arguments.append("--passthroughCustomScalars") - case .passthroughWithPrefix(let prefix): - arguments.append("--passthroughCustomScalars") - arguments.append("--customScalarsPrefix='\(prefix)'") - } - - if self.mergeInFieldsFromFragmentSpreads { - arguments.append("--mergeInFieldsFromFragmentSpreads") - } - - if self.suppressSwiftMultilineStringLiterals { - arguments.append("--suppressSwiftMultilineStringLiterals") - } - - switch self.outputFormat { - case .singleFile(let fileURL): - arguments.append("'\(fileURL.path)'") - case .multipleFiles(let folderURL): - arguments.append("'\(folderURL.path)'") - } - - return arguments - } -} - -extension ApolloCodegenOptions: CustomDebugStringConvertible { - public var debugDescription: String { - self.arguments.joined(separator: "\n") - } -} diff --git a/Sources/ApolloCodegenLib/ApolloFilePathHelper.swift b/Sources/ApolloCodegenLib/ApolloFilePathHelper.swift deleted file mode 100644 index de48993431..0000000000 --- a/Sources/ApolloCodegenLib/ApolloFilePathHelper.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Foundation - -/// Readability helpers for accessing frequent folders. -struct ApolloFilePathHelper { - - /// The URL to the `apollo` folder within the CLI - /// - /// - Parameter cliFolderURL: The URL to the CLI folder. - static func apolloFolderURL(fromCLIFolder cliFolderURL: URL) -> URL { - return cliFolderURL.appendingPathComponent("apollo") - } - - /// The URL to the zip folder within the CLI folder - /// - /// - Parameter cliFolderURL: The URL to the CLI folder - static func zipFileURL(fromCLIFolder cliFolderURL: URL) -> URL { - return cliFolderURL.appendingPathComponent("apollo.tar.gz") - } - - /// The URL to the binary folder within the CLI - /// - /// - Parameter apolloFolderURL: The URL to the `apollo` folder within the CLI - static func binaryFolderURL(fromApollo apolloFolderURL: URL) -> URL { - return apolloFolderURL.appendingPathComponent("bin") - } - - /// The URL to the binary executable within the CLI - /// - /// - Parameter binaryFolderURL: The url to the binary folder within the CLI - static func binaryURL(fromBinaryFolder binaryFolderURL: URL) -> URL { - return binaryFolderURL.appendingPathComponent("run") - } - - /// The URL to the cached SHASUM file for the current zip file of the CLI - /// - /// - Parameter apolloFolderURL: The URL to the Apollo folder within the CLI - static func shasumFileURL(fromApollo apolloFolderURL: URL) -> URL { - return apolloFolderURL.appendingPathComponent(".shasum") - } -} diff --git a/Sources/ApolloCodegenLib/ApolloSchemaDownloadConfiguration.swift b/Sources/ApolloCodegenLib/ApolloSchemaDownloadConfiguration.swift deleted file mode 100644 index db27ea36fe..0000000000 --- a/Sources/ApolloCodegenLib/ApolloSchemaDownloadConfiguration.swift +++ /dev/null @@ -1,121 +0,0 @@ -import Foundation - -/// A configuration object that defines behavior for schema download. -public struct ApolloSchemaDownloadConfiguration { - - /// How to attempt to download your schema - public enum DownloadMethod: Equatable { - - /// The Apollo Schema Registry, which serves as a central hub for managing your graph. - case apolloRegistry(_ settings: ApolloRegistrySettings) - /// GraphQL Introspection connecting to the specified URL. - case introspection(endpointURL: URL, httpMethod: HTTPMethod = .POST) - - public struct ApolloRegistrySettings: Equatable { - /// The API key to use when retrieving your schema from the Apollo Registry. - public let apiKey: String - /// The identifier of the graph to fetch. Can be found in Apollo Studio. - public let graphID: String - /// The variant of the graph in the registry. - public let variant: String? - - /// Designated initializer - /// - /// - Parameters: - /// - apiKey: The API key to use when retrieving your schema. - /// - graphID: The identifier of the graph to fetch. Can be found in Apollo Studio. - /// - variant: The variant of the graph to fetch. Defaults to "current", which will return whatever is set to the current variant. - public init(apiKey: String, - graphID: String, - variant: String = "current") { - self.apiKey = apiKey - self.graphID = graphID - self.variant = variant - } - } - - /// The HTTP request method. This is an option on Introspection schema downloads only. Apollo Registry downloads are always - /// POST requests. - public enum HTTPMethod: Equatable, CustomStringConvertible { - /// Use POST for HTTP requests. This is the default for GraphQL. - case POST - /// Use GET for HTTP requests with the GraphQL query being sent in the query string parameter named in - /// `queryParameterName`. - case GET(queryParameterName: String) - - public var description: String { - switch self { - case .POST: - return "POST" - case .GET: - return "GET" - } - } - } - - public static func == (lhs: DownloadMethod, rhs: DownloadMethod) -> Bool { - switch (lhs, rhs) { - case (.introspection(let lhsURL, let lhsHTTPMethod), .introspection(let rhsURL, let rhsHTTPMethod)): - return lhsURL == rhsURL && lhsHTTPMethod == rhsHTTPMethod - case (.apolloRegistry(let lhsSettings), .apolloRegistry(let rhsSettings)): - return lhsSettings == rhsSettings - default: - return false - } - } - - } - - public struct HTTPHeader: Equatable, CustomDebugStringConvertible { - let key: String - let value: String - - public var debugDescription: String { - "\(key): \(value)" - } - - public init(key: String, value: String) { - self.key = key - self.value = value - } - } - - /// How to download your schema. Supports the Apollo Registry and GraphQL Introspection methods. - public let downloadMethod: DownloadMethod - /// The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. - public let downloadTimeout: Double - /// Any additional headers to include when retrieving your schema. Defaults to nil. - public let headers: [HTTPHeader] - /// The URL of the folder in which the downloaded schema should be written. - public let outputURL: URL - - /// Designated Initializer - /// - /// - Parameters: - /// - downloadMethod: How to download your schema. - /// - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. - /// - headers: [optional] Any additional headers to include when retrieving your schema. Defaults to nil - /// - outputFolderURL: The URL of the folder in which the downloaded schema should be written - /// - schemaFilename: The name, without an extension, for your schema file. Defaults to `"schema" - public init(using downloadMethod: DownloadMethod, - timeout downloadTimeout: Double = 30.0, - headers: [HTTPHeader] = [], - outputFolderURL: URL, - schemaFilename: String = "schema") { - self.downloadMethod = downloadMethod - self.downloadTimeout = downloadTimeout - self.headers = headers - self.outputURL = outputFolderURL.appendingPathComponent("\(schemaFilename).graphqls") - } -} - -extension ApolloSchemaDownloadConfiguration: CustomDebugStringConvertible { - public var debugDescription: String { - return """ - downloadMethod: \(self.downloadMethod) - downloadTimeout: \(self.downloadTimeout) - headers: \(self.headers) - outputURL: \(self.outputURL) - """ - } -} diff --git a/Sources/ApolloCodegenLib/ApolloSchemaDownloader.swift b/Sources/ApolloCodegenLib/ApolloSchemaDownloader.swift deleted file mode 100644 index 83e975637b..0000000000 --- a/Sources/ApolloCodegenLib/ApolloSchemaDownloader.swift +++ /dev/null @@ -1,339 +0,0 @@ -import Foundation -// Only available on macOS -#if os(macOS) - -/// A wrapper to facilitate downloading a schema with the Apollo node CLI -public struct ApolloSchemaDownloader { - - public enum SchemaDownloadError: Error, LocalizedError { - case downloadedRegistryJSONFileNotFound(underlying: Error) - case downloadedIntrospectionJSONFileNotFound(underlying: Error) - case couldNotParseRegistryJSON(underlying: Error) - case unexpectedRegistryJSONType - case couldNotExtractSDLFromRegistryJSON - case couldNotCreateSDLDataToWrite(schema: String) - case couldNotConvertIntrospectionJSONToSDL(underlying: Error) - case couldNotCreateURLComponentsFromEndpointURL(url: URL) - case couldNotGetURLFromURLComponents(components: URLComponents) - - public var errorDescription: String? { - switch self { - case .downloadedRegistryJSONFileNotFound(let underlying): - return "Could not load the JSON file downloaded from the registry. Underlying error: \(underlying)" - case .downloadedIntrospectionJSONFileNotFound(let underlying): - return "Could not load the JSON file downloaded from your server via introspection. Underlying error: \(underlying)" - case .couldNotParseRegistryJSON(let underlying): - return "Could not parse JSON returned by the registry. Underlying error: \(underlying)" - case .unexpectedRegistryJSONType: - return "Root type in the registry JSON was not a dictionary." - case .couldNotExtractSDLFromRegistryJSON: - return "Could not extract the SDL schema from JSON sent by the registry." - case .couldNotCreateSDLDataToWrite(let schema): - return "Could not convert SDL schema into data to write to the filesystem. Schema: \(schema)" - case .couldNotConvertIntrospectionJSONToSDL(let underlying): - return "Could not convert downloaded introspection JSON into SDL format. Underlying error: \(underlying)" - case .couldNotCreateURLComponentsFromEndpointURL(let url): - return "Could not create URLComponents from \(url) for Introspection." - case .couldNotGetURLFromURLComponents(let components): - return "Could not get URL from \(components)." - } - } - } - - /// Downloads your schema using the specified configuration object. - /// - /// - Parameters: - /// - configuration: The `ApolloSchemaDownloadConfiguration` object to use to download the schema. - /// - Returns: Output from a successful run - public static func fetch(with configuration: ApolloSchemaDownloadConfiguration) throws { - try FileManager.default.apollo.createContainingFolderIfNeeded(for: configuration.outputURL) - - switch configuration.downloadMethod { - case .introspection(let endpointURL, let httpMethod): - try self.downloadViaIntrospection(from: endpointURL, httpMethod: httpMethod, configuration: configuration) - case .apolloRegistry(let settings): - try self.downloadFromRegistry(with: settings, configuration: configuration) - } - } - - private static func request(url: URL, - httpMethod: ApolloSchemaDownloadConfiguration.DownloadMethod.HTTPMethod, - headers: [ApolloSchemaDownloadConfiguration.HTTPHeader], - bodyData: Data? = nil) -> URLRequest { - - var request = URLRequest(url: url) - - request.addValue("application/json", forHTTPHeaderField: "Content-Type") - for header in headers { - request.addValue(header.value, forHTTPHeaderField: header.key) - } - - request.httpMethod = String(describing: httpMethod) - request.httpBody = bodyData - - return request - } - - // MARK: - Schema Registry - - static let RegistryEndpoint = URL(string: "https://graphql.api.apollographql.com/api/graphql")! - - static let RegistryDownloadQuery = """ - query DownloadSchema($graphID: ID!, $variant: String!) { - service(id: $graphID) { - variant(name: $variant) { - activeSchemaPublish { - schema { - document - } - } - } - } - } - """ - - - static func downloadFromRegistry(with settings: ApolloSchemaDownloadConfiguration.DownloadMethod.ApolloRegistrySettings, - configuration: ApolloSchemaDownloadConfiguration) throws { - - CodegenLogger.log("Downloading schema from registry", logLevel: .debug) - - let urlRequest = try registryRequest(with: settings, headers: configuration.headers) - let jsonOutputURL = configuration.outputURL.apollo.parentFolderURL().appendingPathComponent("registry_response.json") - - try URLDownloader().downloadSynchronously(with: urlRequest, - to: jsonOutputURL, - timeout: configuration.downloadTimeout) - - try self.convertFromRegistryJSONToSDLFile(jsonFileURL: jsonOutputURL, configuration: configuration) - - CodegenLogger.log("Successfully downloaded schema from registry", logLevel: .debug) - } - - static func registryRequest(with settings: ApolloSchemaDownloadConfiguration.DownloadMethod.ApolloRegistrySettings, - headers: [ApolloSchemaDownloadConfiguration.HTTPHeader]) throws -> URLRequest { - - var variables = [String: String]() - variables["graphID"] = settings.graphID - if let variant = settings.variant { - variables["variant"] = variant - } - - let requestBody = UntypedGraphQLRequestBodyCreator.requestBody(for: self.RegistryDownloadQuery, - variables: variables, - operationName: "DownloadSchema") - let bodyData = try JSONSerialization.data(withJSONObject: requestBody, options: [.sortedKeys]) - - var allHeaders = headers - allHeaders.append(ApolloSchemaDownloadConfiguration.HTTPHeader(key: "x-api-key", value: settings.apiKey)) - - let urlRequest = request(url: self.RegistryEndpoint, - httpMethod: .POST, - headers: allHeaders, - bodyData: bodyData) - - return urlRequest - } - - static func convertFromRegistryJSONToSDLFile(jsonFileURL: URL, configuration: ApolloSchemaDownloadConfiguration) throws { - let jsonData: Data - - do { - jsonData = try Data(contentsOf: jsonFileURL) - } catch { - throw SchemaDownloadError.downloadedRegistryJSONFileNotFound(underlying: error) - } - - let json: Any - do { - json = try JSONSerialization.jsonObject(with: jsonData) - } catch { - throw SchemaDownloadError.couldNotParseRegistryJSON(underlying: error) - } - - guard let dict = json as? [String: Any] else { - throw SchemaDownloadError.unexpectedRegistryJSONType - } - - guard - let data = dict["data"] as? [String: Any], - let service = data["service"] as? [String: Any], - let variant = service["variant"] as? [String: Any], - let asp = variant["activeSchemaPublish"] as? [String: Any], - let schemaDict = asp["schema"] as? [String: Any], - let sdlSchema = schemaDict["document"] as? String else { - throw SchemaDownloadError.couldNotExtractSDLFromRegistryJSON - } - - guard let sdlData = sdlSchema.data(using: .utf8) else { - throw SchemaDownloadError.couldNotCreateSDLDataToWrite(schema: sdlSchema) - } - - try sdlData.write(to: configuration.outputURL) - } - - // MARK: - Schema Introspection - - static let IntrospectionQuery = """ - query IntrospectionQuery { - __schema { - queryType { name } - mutationType { name } - subscriptionType { name } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } - } - fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } - } - fragment InputValue on __InputValue { - name - description - type { ...TypeRef } - defaultValue - } - fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - """ - - - static func downloadViaIntrospection(from endpointURL: URL, - httpMethod: ApolloSchemaDownloadConfiguration.DownloadMethod.HTTPMethod, - configuration: ApolloSchemaDownloadConfiguration) throws { - - CodegenLogger.log("Downloading schema via introspection from \(endpointURL)", logLevel: .debug) - - let urlRequest = try introspectionRequest(from: endpointURL, httpMethod: httpMethod, headers: configuration.headers) - let jsonOutputURL = configuration.outputURL.apollo.parentFolderURL().appendingPathComponent("introspection_response.json") - - try URLDownloader().downloadSynchronously(with: urlRequest, - to: jsonOutputURL, - timeout: configuration.downloadTimeout) - - try convertFromIntrospectionJSONToSDLFile(jsonFileURL: jsonOutputURL, configuration: configuration) - - CodegenLogger.log("Successfully downloaded schema via introspection", logLevel: .debug) - } - - static func introspectionRequest(from endpointURL: URL, - httpMethod: ApolloSchemaDownloadConfiguration.DownloadMethod.HTTPMethod, - headers: [ApolloSchemaDownloadConfiguration.HTTPHeader]) throws -> URLRequest { - let urlRequest: URLRequest - - switch httpMethod { - case .POST: - let requestBody = UntypedGraphQLRequestBodyCreator.requestBody(for: self.IntrospectionQuery, - variables: nil, - operationName: "IntrospectionQuery") - let bodyData = try JSONSerialization.data(withJSONObject: requestBody, options: [.sortedKeys]) - urlRequest = request(url: endpointURL, - httpMethod: httpMethod, - headers: headers, - bodyData: bodyData) - - case .GET(let queryParameterName): - guard var components = URLComponents(url: endpointURL, resolvingAgainstBaseURL: true) else { - throw SchemaDownloadError.couldNotCreateURLComponentsFromEndpointURL(url: endpointURL) - } - components.queryItems = [URLQueryItem(name: queryParameterName, value: IntrospectionQuery)] - - guard let url = components.url else { - throw SchemaDownloadError.couldNotGetURLFromURLComponents(components: components) - } - urlRequest = request(url: url, httpMethod: httpMethod, headers: headers) - } - - return urlRequest - } - - static func convertFromIntrospectionJSONToSDLFile(jsonFileURL: URL, configuration: ApolloSchemaDownloadConfiguration) throws { - let frontend = try ApolloCodegenFrontend() - let schema: GraphQLSchema - do { - schema = try frontend.loadSchema(from: jsonFileURL) - } catch { - throw SchemaDownloadError.downloadedIntrospectionJSONFileNotFound(underlying: error) - } - - let sdlSchema: String - do { - sdlSchema = try frontend.printSchemaAsSDL(schema: schema) - } catch { - throw SchemaDownloadError.couldNotConvertIntrospectionJSONToSDL(underlying: error) - } - - try sdlSchema.write(to: configuration.outputURL, - atomically: true, - encoding: .utf8) - } -} -#endif diff --git a/Sources/ApolloCodegenLib/Basher.swift b/Sources/ApolloCodegenLib/Basher.swift deleted file mode 100644 index 48544a9258..0000000000 --- a/Sources/ApolloCodegenLib/Basher.swift +++ /dev/null @@ -1,64 +0,0 @@ -import Foundation - -// Only available on macOS -#if os(macOS) - -/// Bash command runner -public struct Basher { - - public enum BashError: Error, LocalizedError { - case errorDuringTask(code: Int32) - case noOutput(code: Int32) - - public var errorDescription: String? { - switch self { - case .errorDuringTask(let code): - return "Task failed with code \(code)." - case .noOutput(let code): - return "Task had no output. Exit code: \(code)." - } - } - } - - /// Runs the given bash command as a string - /// - /// - Parameters: - /// - command: The bash command to run - /// - url: [optional] The URL to set as the `currentDirectoryURL`. - /// - Returns: The result of the command. - public static func run(command: String, from url: URL?) throws -> String { - let task = Process() - let pipe = Pipe() - task.standardOutput = pipe - task.standardError = pipe - task.arguments = [ - "-c", - command - ] - task.launchPath = "/bin/bash" - - if let url = url { - task.currentDirectoryURL = url - } - try task.run() - - task.waitUntilExit() - - let data = pipe.fileHandleForReading.readDataToEndOfFile() - - guard let output = String(bytes: data, encoding: .utf8) else { - CodegenLogger.log("[No output from pipe]", logLevel: .error) - throw BashError.noOutput(code: task.terminationStatus) - } - - guard task.terminationStatus == 0 else { - CodegenLogger.log(output, logLevel: .error) - throw BashError.errorDuringTask(code: task.terminationStatus) - } - - CodegenLogger.log(output) - return output - } -} - -#endif diff --git a/Sources/ApolloCodegenLib/CLIDownloader.swift b/Sources/ApolloCodegenLib/CLIDownloader.swift deleted file mode 100644 index 1ad4afd733..0000000000 --- a/Sources/ApolloCodegenLib/CLIDownloader.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation - -// Only available on macOS -#if os(macOS) - -/// Helper for downloading the CLI Zip file so we don't have to include it in the repo. -struct CLIDownloader { - /// The URL string for getting the current version of the CLI - static let downloadURLString = "https://install.apollographql.com/legacy-cli/darwin/2.33.9" - - /// Downloads the appropriate Apollo CLI in a zip file. - /// - /// - Parameters: - /// - cliFolderURL: The folder URL to download the zip file to. - /// - timeout: The maximum time to wait before indicating that the download timed out, in seconds. - static func downloadIfNeeded(to cliFolderURL: URL, timeout: Double) throws { - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - - guard !FileManager.default.apollo.fileExists(at: zipFileURL) else { - CodegenLogger.log("Zip file with the CLI is already downloaded!") - return - } - - try self.download(to: zipFileURL, timeout: timeout) - } - - /// Deletes any existing version of the zip file and re-downloads a new version. - /// - /// - Parameters: - /// - cliFolderURL: The folder where the zip file lives. - /// - timeout: The maximum time to wait before indicating that the download timed out, in seconds. - static func forceRedownload(to cliFolderURL: URL, timeout: Double) throws { - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - try FileManager.default.apollo.deleteFile(at: zipFileURL) - let apolloFolderURL = ApolloFilePathHelper.apolloFolderURL(fromCLIFolder: cliFolderURL) - try FileManager.default.apollo.deleteFolder(at: apolloFolderURL) - - try self.download(to: zipFileURL, timeout: timeout) - } - - /// Downloads the zip file of the Apollo CLI synchronously. - /// - /// - Parameters: - /// - zipFileURL: The URL where downloaded data should be saved. - /// - timeout: The maximum time to wait before indicating that the download timed out, in seconds. - private static func download(to zipFileURL: URL, timeout: Double) throws { - try FileManager.default.apollo.createContainingFolderIfNeeded(for: zipFileURL) - - CodegenLogger.log("Downloading zip file with the CLI...") - - let urlRequest = URLRequest(url: URL(string: CLIDownloader.downloadURLString)!) - try URLDownloader().downloadSynchronously(with: urlRequest, - to: zipFileURL, - timeout: timeout) - - CodegenLogger.log("CLI zip file successfully downloaded!") - } -} - -#endif diff --git a/Sources/ApolloCodegenLib/CLIExtractor.swift b/Sources/ApolloCodegenLib/CLIExtractor.swift deleted file mode 100644 index fd54bd0e3d..0000000000 --- a/Sources/ApolloCodegenLib/CLIExtractor.swift +++ /dev/null @@ -1,145 +0,0 @@ -import Foundation - -// Only available on macOS -#if os(macOS) - -/// Helper for extracting and validating the node-based Apollo CLI from a zip. -struct CLIExtractor { - - // MARK: - Extracting the binary - - enum CLIExtractorError: Error, LocalizedError { - case noBinaryFolderAfterUnzipping(atURL: URL) - case zipFileHasInvalidSHASUM(expectedSHASUM: String, gotSHASUM: String) - case zipFileNotPresent(atURL: URL) - - var errorDescription: String? { - switch self { - case .noBinaryFolderAfterUnzipping(let url): - return "Some kind of error occurred with unzipping and the binary folder could not be found at \(url)" - case .zipFileHasInvalidSHASUM(let expectedSHASUM, let gotSHASUM): - return "Error: The SHASUM of this zip file (\(gotSHASUM)) does not match the official released version from Apollo (\(expectedSHASUM))! This may present security issues. Terminating code generation." - case .zipFileNotPresent(let url): - return "Could not locate file to unzip at \(url). Please make sure you're passing in the correct URL for the scripts folder!" - } - } - } - - static let expectedSHASUM = "cb73089deb2a720a7d2f5a39ad449e1cfbdc22771130cd6e2a405aaa887c343e" - - /// Checks to see if the CLI has already been extracted and is the correct version, and extracts or re-extracts as necessary - /// - /// - Parameter cliFolderURL: The URL to the folder which contains the zip file with the CLI. - /// - Parameter expectedSHASUM: The expected SHASUM. Defaults to the real expected SHASUM. This parameter exists mostly for testing. - /// - Returns: The URL to the binary folder of the extracted CLI. - static func extractCLIIfNeeded(from cliFolderURL: URL, expectedSHASUM: String = CLIExtractor.expectedSHASUM) throws -> URL { - let apolloFolderURL = ApolloFilePathHelper.apolloFolderURL(fromCLIFolder: cliFolderURL) - - guard FileManager.default.apollo.folderExists(at: apolloFolderURL) else { - CodegenLogger.log("Apollo folder doesn't exist, extracting CLI from zip file.") - return try self.extractCLIFromZip(cliFolderURL: cliFolderURL) - } - - guard try self.validateSHASUMInExtractedFile(apolloFolderURL: apolloFolderURL, expected: expectedSHASUM) else { - CodegenLogger.log("SHASUM of extracted zip does not match expected, deleting existing folder and re-extracting.") - try FileManager.default.apollo.deleteFolder(at: apolloFolderURL) - return try self.extractCLIFromZip(cliFolderURL: cliFolderURL) - } - - let binaryFolderURL = ApolloFilePathHelper.binaryFolderURL(fromApollo: apolloFolderURL) - let binaryURL = ApolloFilePathHelper.binaryURL(fromBinaryFolder: binaryFolderURL) - guard FileManager.default.apollo.fileExists(at: binaryURL) else { - CodegenLogger.log("There was a valid `.shasum` file, but no binary at the expected path. Deleting existing apollo folder and re-extracting.", logLevel: .warning) - try FileManager.default.apollo.deleteFolder(at: apolloFolderURL) - return try self.extractCLIFromZip(cliFolderURL: cliFolderURL, expectedSHASUM: expectedSHASUM) - } - - CodegenLogger.log("Binary already extracted!") - return binaryFolderURL - } - - /// Checks the `.shasum` file which was written out the last time the CLI - /// was extracted to see if it matches the current version - /// - Parameter apolloFolderURL: The URL to the extracted apollo folder. - /// - Parameter expected: The expected SHASUM. Defaults to the real expected SHASUM. This parameter exists mostly for testing. - /// - Returns: true if the shasums match, false if not. - static func validateSHASUMInExtractedFile(apolloFolderURL: URL, expected: String = CLIExtractor.expectedSHASUM) throws -> Bool { - let shasumFileURL = ApolloFilePathHelper.shasumFileURL(fromApollo: apolloFolderURL) - guard FileManager.default.apollo.fileExists(at: shasumFileURL) else { - return false - } - - let contents = try String(contentsOf: shasumFileURL, encoding: .utf8) - - guard contents == expected else { - return contents.hasPrefix(expected) - } - - return true - } - - static func validateSHASUMOfDownloadedFile(in cliFolderURL: URL, expected: String = CLIExtractor.expectedSHASUM) throws -> Bool { - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - - do { - try self.validateZipFileSHASUM(at: zipFileURL) - return true - } catch { - switch error { - case CLIExtractorError.zipFileHasInvalidSHASUM: - return false - default: - throw error - } - } - } - - /// Writes the SHASUM of the extracted version of the CLI to a file for faster checks to ensure we have the correct version. - /// - /// - Parameter apolloFolderURL: The URL to the extracted apollo folder. - static func writeSHASUMToFile(apolloFolderURL: URL) throws { - let shasumFileURL = ApolloFilePathHelper.shasumFileURL(fromApollo: apolloFolderURL) - try CLIExtractor.expectedSHASUM.write(to: shasumFileURL, - atomically: true, - encoding: .utf8) - } - - /// Extracts the CLI from a zip file in the scripts folder. - /// - /// - Parameter cliFolderURL: The URL to the folder which contains the zip file with the CLI. - /// - Parameter expectedSHASUM: The expected SHASUM. Defaults to the real expected SHASUM. This parameter exists mostly for testing. - /// - Returns: The URL for the binary folder post-extraction. - static func extractCLIFromZip(cliFolderURL: URL, expectedSHASUM: String = CLIExtractor.expectedSHASUM) throws -> URL { - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - - try self.validateZipFileSHASUM(at: zipFileURL, expected: expectedSHASUM) - - CodegenLogger.log("Extracting CLI from zip file. This may take a second...") - _ = try Basher.run(command: "tar xzf '\(zipFileURL.path)' -C '\(cliFolderURL.path)'", from: nil) - - let apolloFolderURL = ApolloFilePathHelper.apolloFolderURL(fromCLIFolder: cliFolderURL) - let binaryFolderURL = ApolloFilePathHelper.binaryFolderURL(fromApollo: apolloFolderURL) - - guard FileManager.default.apollo.folderExists(at: binaryFolderURL) else { - throw CLIExtractorError.noBinaryFolderAfterUnzipping(atURL: binaryFolderURL) - } - - try self.writeSHASUMToFile(apolloFolderURL: apolloFolderURL) - - return binaryFolderURL - } - - /// Checks that the file at the given URL matches the expected SHASUM. - /// - /// - Parameter zipFileURL: The url to the zip file containing the Apollo CLI. - /// - Parameter expected: The expected SHASUM. Defaults to the real expected SHASUM. This parameter exists mostly for testing. - static func validateZipFileSHASUM(at zipFileURL: URL, expected: String = CLIExtractor.expectedSHASUM) throws { - let shasum = try FileManager.default.apollo.shasum(at: zipFileURL) - CodegenLogger.log("SHASUM of downloaded file: \(shasum)") - guard shasum == expected else { - throw CLIExtractorError.zipFileHasInvalidSHASUM(expectedSHASUM: expected, gotSHASUM: shasum) - } - } -} - -#endif diff --git a/Sources/ApolloCodegenLib/CodegenLogger.swift b/Sources/ApolloCodegenLib/CodegenLogger.swift deleted file mode 100644 index 6d88b52a68..0000000000 --- a/Sources/ApolloCodegenLib/CodegenLogger.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation - -/// Helper to get logs printing to stdout so they can be read from the command line. -public struct CodegenLogger { - public enum LogLevel: Int { - case error - case warning - case debug - - var name: String { - switch self { - case .error: - return "ERROR" - case .warning: - return "WARNING" - case .debug: - return "DEBUG" - } - } - } - - /// The `LogLevel` at which to print logs. Higher raw values than this will - /// be ignored. Defaults to `debug`. - public static var level = LogLevel.debug - - /// Logs the given string if its `logLevel` is at or above `CodegenLogger.level`, otherwise ignores it. - /// - /// - Parameter logString: The string to log out, as an autoclosure - /// - Parameter logLevel: The log level at which to print this specific log. Defaults to `debug`. - /// - Parameter file: The file where this function was called. Defaults to the direct caller. - /// - Parameter line: The line where this function was called. Defaults to the direct caller. - public static func log(_ logString: @autoclosure () -> String, - logLevel: LogLevel = .debug, - file: StaticString = #file, - line: UInt = #line) { - guard logLevel.rawValue <= CodegenLogger.level.rawValue else { - // We're not logging anything at this level. - return - } - - var standardOutput = FileHandle.standardOutput - print("[\(logLevel.name) - ApolloCodegenLib:\(file.apollo.lastPathComponent):\(line)] - \(logString())", to: &standardOutput) - } -} - -// Extension which allows `print` to output to a FileHandle -extension FileHandle: TextOutputStream { - public func write(_ string: String) { - guard let data = string.data(using: .utf8) else { return } - self.write(data) - } -} diff --git a/Sources/ApolloCodegenLib/FileFinder.swift b/Sources/ApolloCodegenLib/FileFinder.swift deleted file mode 100644 index 811409a66c..0000000000 --- a/Sources/ApolloCodegenLib/FileFinder.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Foundation - -public struct FileFinder { - - #if compiler(>=5.3) - /// Version that works if you're using the 5.3 compiler or above - /// - Parameter filePath: The full file path of the file to find. Defaults to the `#filePath` of the caller. - /// - Returns: The file URL for the parent folder. - public static func findParentFolder(from filePath: StaticString = #filePath) -> URL { - self.findParentFolder(from: filePath.apollo.toString) - } - - /// The URL of a file at a given path - /// - Parameter filePath: The full file path of the file to find - /// - Returns: The file's URL - public static func fileURL(from filePath: StaticString = #filePath) -> URL { - URL(fileURLWithPath: filePath.apollo.toString) - } - #else - /// Version that works if you're using the 5.2 compiler or below - /// - Parameter file: The full file path of the file to find. Defaults to the `#file` of the caller. - /// - Returns: The file URL for the parent folder. - public static func findParentFolder(from filePath: StaticString = #file) -> URL { - self.findParentFolder(from: filePath.apollo.toString) - } - - /// The URL of a file at a given path - /// - Parameter filePath: The full file path of the file to find - /// - Returns: The file's URL - public static func fileURL(from filePath: StaticString = #file) -> URL { - URL(fileURLWithPath: filePath.apollo.toString) - } - #endif - - /// Finds the parent folder from a given file path. - /// - Parameter filePath: The full file path, as a string - /// - Returns: The file URL for the parent folder. - public static func findParentFolder(from filePath: String) -> URL { - let url = URL(fileURLWithPath: filePath) - return url.deletingLastPathComponent() - } -} diff --git a/Sources/ApolloCodegenLib/FileManager+Apollo.swift b/Sources/ApolloCodegenLib/FileManager+Apollo.swift deleted file mode 100644 index 7b32473290..0000000000 --- a/Sources/ApolloCodegenLib/FileManager+Apollo.swift +++ /dev/null @@ -1,132 +0,0 @@ -import Foundation -import CommonCrypto -#if !COCOAPODS -import ApolloUtils -#endif - -extension FileManager: ApolloCompatible {} - -extension ApolloExtension where Base == FileManager { - - /// Checks if a file exists (and is not a folder) at the given path - /// - /// - Parameter path: The path to check - /// - Returns: `true` if there is something at the path and it is a file, not a folder. - public func fileExists(at path: String) -> Bool { - var isFolder = ObjCBool(false) - let exists = base.fileExists(atPath: path, isDirectory: &isFolder) - return exists && !isFolder.boolValue - } - - /// Checks if a file exists (and is not a folder) at the given URL - /// - /// - Parameter url: The URL to check - /// - Returns: `true` if there is something at the URL and it is a file, not a folder. - public func fileExists(at url: URL) -> Bool { - return fileExists(at: url.path) - } - - /// Checks if a folder exists (and is not a file) at the given path. - /// - /// - Parameter path: The path to check - /// - Returns: `true` if there is something at the path and it is a folder, not a file. - public func folderExists(at path: String) -> Bool { - var isFolder = ObjCBool(false) - let exists = base.fileExists(atPath: path, isDirectory: &isFolder) - return exists && isFolder.boolValue - } - - /// Checks if a folder exists (and is not a file) at the given URL. - /// - /// - Parameter url: The URL to check - /// - Returns: `true` if there is something at the URL and it is a folder, not a file. - public func folderExists(at url: URL) -> Bool { - return folderExists(at: url.path) - } - - /// Checks if a folder exists then attempts to delete it if it's there. - /// - /// - Parameter url: The URL to delete the folder for - public func deleteFolder(at url: URL) throws { - guard folderExists(at: url) else { - // Nothing to delete! - return - } - try base.removeItem(at: url) - } - - /// Checks if a file exists then attempts to delete it if it's there. - /// - /// - Parameter url: The URL to delete the file for - public func deleteFile(at url: URL) throws { - guard fileExists(at: url) else { - // Nothing to delete! - return - } - try base.removeItem(at: url) - } - - /// Creates the containing folder (including all intermediate directories) for the given file URL if necessary. - /// - /// - Parameter fileURL: The URL of the file to create a containing folder for if necessary. - public func createContainingFolderIfNeeded(for fileURL: URL) throws { - let parent = fileURL.deletingLastPathComponent() - try createFolderIfNeeded(at: parent) - } - - /// Creates the folder (including all intermediate directories) for the given URL if necessary. - /// - /// - Parameter url: The URL of the folder to create if necessary. - public func createFolderIfNeeded(at url: URL) throws { - guard !folderExists(at: url) else { - // Folder already exists, nothing more to do here. - return - } - try base.createDirectory(atPath: url.path, withIntermediateDirectories: true) - } - - /// Calculates the SHASUM (ie, SHA256 hash) of the given file - /// - /// - Parameter fileURL: The file to calculate the SHASUM for. - public func shasum(at fileURL: URL) throws -> String { - let file = try FileHandle(forReadingFrom: fileURL) - defer { - file.closeFile() - } - - let buffer = 1024 * 1024 // 1GB - - var context = CC_SHA256_CTX() - CC_SHA256_Init(&context) - - while autoreleasepool(invoking: { - let data = file.readData(ofLength: buffer) - guard !data.isEmpty else { - // Nothing more to read! - return false - } - - _ = data.withUnsafeBytes { bytesFromBuffer -> Int32 in - guard let rawBytes = bytesFromBuffer.bindMemory(to: UInt8.self).baseAddress else { - return Int32(kCCMemoryFailure) - } - return CC_SHA256_Update(&context, rawBytes, numericCast(data.count)) - } - - return true - }) {} - - var digestData = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) - _ = digestData.withUnsafeMutableBytes { bytesFromDigest -> Int32 in - guard let rawBytes = bytesFromDigest.bindMemory(to: UInt8.self).baseAddress else { - return Int32(kCCMemoryFailure) - } - - return CC_SHA256_Final(rawBytes, &context) - } - - return digestData - .map { String(format: "%02hhx", $0) } - .joined() - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/ApolloCodegenFrontend.swift b/Sources/ApolloCodegenLib/Frontend/ApolloCodegenFrontend.swift deleted file mode 100644 index 2e528e5e2b..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/ApolloCodegenFrontend.swift +++ /dev/null @@ -1,118 +0,0 @@ -import Foundation -import JavaScriptCore - -public final class ApolloCodegenFrontend { - #if SWIFT_PACKAGE - private static let bundle = Bundle.module - private static let libraryURL = bundle.url(forResource: "ApolloCodegenFrontend.bundle", - withExtension: "js")! - #else - private static let bundle = Bundle(for: ApolloCodegenFrontend.self) - private static let libraryURL = bundle.url(forResource: "ApolloCodegenFrontend.bundle", - withExtension: "js", - subdirectory: "dist")! - #endif - private static let librarySource = try! String.init(contentsOf: libraryURL) - - private let virtualMachine = JSVirtualMachine() - private let context: JSContext - private let bridge: JavaScriptBridge - - private let library: JavaScriptObject - - public init() throws { - let context = JSContext(virtualMachine: virtualMachine)! - self.context = context - bridge = JavaScriptBridge(context: context) - - try bridge.throwingJavaScriptErrorIfNeeded { - context.evaluateScript(Self.librarySource, withSourceURL: Self.libraryURL) - } - - library = bridge.fromJSValue(context.globalObject["ApolloCodegenFrontend"]) - - bridge.register(GraphQLSource.self, forJavaScriptClass: "Source", from: library) - - bridge.register(GraphQLError.self, from: library) - bridge.register(GraphQLSchemaValidationError.self, from: library) - - bridge.register(GraphQLSchema.self, from: library) - - bridge.register(GraphQLScalarType.self, from: library) - bridge.register(GraphQLEnumType.self, from: library) - bridge.register(GraphQLInputObjectType.self, from: library) - bridge.register(GraphQLObjectType.self, from: library) - bridge.register(GraphQLInterfaceType.self, from: library) - bridge.register(GraphQLUnionType.self, from: library) - } - - /// Load a schema by parsing either an introspection result or SDL based on the file extension. - public func loadSchema(from fileURL: URL) throws -> GraphQLSchema { - precondition(fileURL.isFileURL) - - if fileURL.pathExtension == "json" { - let introspectionResult = try String(contentsOf: fileURL) - return try loadSchemaFromIntrospectionResult(introspectionResult) - } else { - let source = try makeSource(from: fileURL) - return try loadSchemaFromSDL(source) - } - } - - /// Load a schema by parsing an introspection result. - public func loadSchemaFromIntrospectionResult(_ introspectionResult: String) throws -> GraphQLSchema { - return try library.call("loadSchemaFromIntrospectionResult", with: introspectionResult) - } - - /// Load a schema by parsing SDL. - public func loadSchemaFromSDL(_ source: GraphQLSource) throws -> GraphQLSchema { - return try library.call("loadSchemaFromSDL", with: source) - } - - /// Take a loaded GQL schema and print it as SDL. - public func printSchemaAsSDL(schema: GraphQLSchema) throws -> String { - return try library.call("printSchemaToSDL", with: schema) - } - - private lazy var sourceConstructor: JavaScriptObject = bridge.fromJSValue(library["Source"]) - - /// Create a `GraphQLSource` object from a string. - public func makeSource(_ body: String, filePath: String) throws -> GraphQLSource { - return try sourceConstructor.construct(with: body, filePath) - } - - /// Create a `GraphQLSource` object by reading from a file. - public func makeSource(from fileURL: URL) throws -> GraphQLSource { - precondition(fileURL.isFileURL) - - let body = try String(contentsOf: fileURL) - return try makeSource(body, filePath: fileURL.path) - } - - /// Parses a GraphQL document from a source, returning a reference to the parsed AST that can be passed on to validation and compilation. - /// Syntax errors will result in throwing a `GraphQLError`. - public func parseDocument(_ source: GraphQLSource) throws -> GraphQLDocument { - return try library.call("parseDocument", with: source) - } - - /// Parses a GraphQL document from a file, returning a reference to the parsed AST that can be passed on to validation and compilation. - /// Syntax errors will result in throwing a `GraphQLError`. - public func parseDocument(from fileURL: URL) throws -> GraphQLDocument { - return try library.call("parseDocument", with: makeSource(from: fileURL)) - } - - /// Validation and compilation take a single document, but you can merge documents, and operations and fragments will remember their source. - public func mergeDocuments(_ documents: [GraphQLDocument]) throws -> GraphQLDocument { - return try library.call("mergeDocuments", with: documents) - } - - /// Validate a GraphQL document and return any validation errors as `GraphQLError`s. - public func validateDocument(schema: GraphQLSchema, document: GraphQLDocument) throws -> [GraphQLError] { - return try library.call("validateDocument", with: schema, document) - } - - /// Compiles a GraphQL document into an intermediate representation that is more suitable for analysis and code generation. - public func compile(schema: GraphQLSchema, document: GraphQLDocument) throws -> CompilationResult { - return try library.call("compileDocument", with: schema, document) - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/CompilationResult.swift b/Sources/ApolloCodegenLib/Frontend/CompilationResult.swift deleted file mode 100644 index 6dbed5ed71..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/CompilationResult.swift +++ /dev/null @@ -1,140 +0,0 @@ -import JavaScriptCore - -/// The output of the frontend compiler. -public class CompilationResult: JavaScriptObject { - private(set) lazy var operations: [OperationDefinition] = self["operations"] - - private(set) lazy var fragments: [FragmentDefinition] = self["fragments"] - - private(set) lazy var referencedTypes: [GraphQLNamedType] = self["referencedTypes"] - - public class OperationDefinition: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var operationType: OperationType = self["operationType"] - - private(set) lazy var variables: [VariableDefinition] = self["variables"] - - private(set) lazy var rootType: GraphQLCompositeType = self["rootType"] - - private(set) lazy var selectionSet: SelectionSet = self["selectionSet"] - - private(set) lazy var source: String = self["source"] - - private(set) lazy var filePath: String = self["filePath"] - - var operationIdentifier: String { - // TODO: Compute this from source + referenced fragments - fatalError() - } - } - - public enum OperationType: String, Equatable, JavaScriptValueDecodable { - case query - case mutation - case subscription - - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - // No way to use guard when delegating to a failable initializer directly, but since this is a value type - // we can initialize a local variable instead and assign it to `self` on success. - // See https://forums.swift.org/t/theres-no-way-to-channel-a-fail-able-initializer-to-a-throwing-one-is-there/19322 - let rawValue: String = .fromJSValue(jsValue, bridge: bridge) - guard let operationType = Self(rawValue: rawValue) else { - preconditionFailure("Unknown GraphQL operation type: \(rawValue)") - } - - self = operationType - } - } - - public class VariableDefinition: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var type: GraphQLType = self["type"] - - private(set) lazy var defaultValue: GraphQLValue? = self["defaultValue"] - } - - public class FragmentDefinition: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var type: GraphQLCompositeType = self["type"] - - private(set) lazy var selectionSet: SelectionSet = self["selectionSet"] - - private(set) lazy var source: String = self["source"] - - private(set) lazy var filePath: String = self["filePath"] - } - - public class SelectionSet: JavaScriptObject { - private(set) lazy var parentType: GraphQLCompositeType = self["parentType"] - - private(set) lazy var selections: [Selection] = self["selections"] - } - - public enum Selection: JavaScriptValueDecodable { - case field(Field) - case inlineFragment(InlineFragment) - case fragmentSpread(FragmentSpread) - - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isObject, "Expected JavaScript object but found: \(jsValue)") - - let kind: String = jsValue["kind"].toString() - - switch kind { - case "Field": - self = .field(Field(jsValue, bridge: bridge)) - case "InlineFragment": - self = .inlineFragment(InlineFragment(jsValue, bridge: bridge)) - case "FragmentSpread": - self = .fragmentSpread(FragmentSpread(jsValue, bridge: bridge)) - default: - preconditionFailure(""" - Unknown GraphQL selection of kind "\(kind)" - """) - } - } - } - - public class Field: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var alias: String? = self["alias"] - - var responseKey: String { - alias ?? name - } - - private(set) lazy var arguments: [Argument]? = self["arguments"] - - private(set) lazy var type: GraphQLType = self["type"] - - private(set) lazy var selectionSet: SelectionSet? = self["selectionSet"] - - private(set) lazy var deprecationReason: String? = self["deprecationReason"] - - var isDeprecated: Bool { - return deprecationReason != nil - } - - private(set) lazy var description: String? = self["description"] - } - - public class Argument: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var value: GraphQLValue = self["value"] - } - - public class InlineFragment: JavaScriptObject { - private(set) lazy var typeCondition: GraphQLCompositeType? = self["typeCondition"] - - private(set) lazy var selectionSet: SelectionSet = self["selectionSet"] - } - - public class FragmentSpread: JavaScriptObject { - private(set) lazy var fragment: FragmentDefinition = self["fragment"] - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/GraphQLError.swift b/Sources/ApolloCodegenLib/Frontend/GraphQLError.swift deleted file mode 100644 index 786e91ae12..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/GraphQLError.swift +++ /dev/null @@ -1,47 +0,0 @@ -import Foundation -import JavaScriptCore - -/// A GraphQL error. -/// Corresponds to https://github.com/graphql/graphql-js/blob/master/src/error/GraphQLError.js -/// You can get error details if you need them, or call `error.logLines` to get errors in a format that lets Xcode show inline errors. -public class GraphQLError: JavaScriptError { - private lazy var source: GraphQLSource = self["source"] - - /// The source locations associated with this error. - private(set) lazy var sourceLocations: [GraphQLSourceLocation] = { - let locations: [JavaScriptObject] = self["locations"] - - if let nodes: [ASTNode] = self["nodes"] { - // We have AST nodes, so this is a validation error. - // Because errors can be associated with locations from different - // source files, we ignore the `source` property and go through the - // individual nodes instead. - - precondition(locations.count == nodes.count) - - return zip(locations, nodes).map { (location, node) in - return GraphQLSourceLocation(filePath: node.filePath, lineNumber: location["line"].toInt(), columnNumber: location["column"].toInt()) - } - } else { - // We have no AST nodes, so this is a syntax error. Those only apply to a single source file, - // so we can rely on the `source` property. - - return locations.map { - GraphQLSourceLocation(filePath: source.filePath, lineNumber: $0["line"].toInt(), columnNumber: $0["column"].toInt()) - } - } - }() - - /// Log lines for this error in a format that allows Xcode to show errors inline at the correct location. - /// See https://shazronatadobe.wordpress.com/2010/12/04/xcode-shell-build-phase-reporting-of-errors/ - var logLines: [String] { - return sourceLocations.map { - return [$0.filePath, String($0.lineNumber), "error", message ?? "?"].joined(separator: ":") - } - } -} - -/// A GraphQL schema validation error. This wraps one or more underlying validation errors. -public class GraphQLSchemaValidationError: JavaScriptError { - private(set) lazy var validationErrors: [GraphQLError] = self["validationErrors"] -} diff --git a/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift b/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift deleted file mode 100644 index e3170a8b1b..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift +++ /dev/null @@ -1,109 +0,0 @@ -import JavaScriptCore - -// These classes correspond directly to the ones in -// https://github.com/graphql/graphql-js/tree/master/src/type -// and are partially described in https://graphql.org/graphql-js/type/ - -/// A GraphQL schema. -public class GraphQLSchema: JavaScriptObject { - func getType(named typeName: String) throws -> GraphQLNamedType? { - try invokeMethod("getType", with: typeName) - } - - func getPossibleTypes(_ abstractType: GraphQLAbstractType) throws -> [GraphQLObjectType] { - return try invokeMethod("getPossibleTypes", with: abstractType) - } - - func getImplementations(interfaceType: GraphQLInterfaceType) throws -> InterfaceImplementations { - return try invokeMethod("getImplementations", with: interfaceType) - } - - class InterfaceImplementations: JavaScriptObject { - private(set) lazy var objects: [GraphQLObjectType] = self["objects"] - private(set) lazy var interfaces: [GraphQLInterfaceType] = self["interfaces"] - } - - func isSubType(abstractType: GraphQLAbstractType, maybeSubType: GraphQLNamedType) throws -> Bool { - return try invokeMethod("isSubType", with: abstractType, maybeSubType) - } -} - -public class GraphQLNamedType: JavaScriptObject { - private(set) lazy var name: String = self["name"] -} - -public class GraphQLScalarType: GraphQLNamedType { - private(set) lazy var description: String? = self["description"] - - private(set) lazy var specifiedByURL: String? = self["specifiedByUrl"] -} - -public class GraphQLEnumType: GraphQLNamedType { - private(set) lazy var description: String? = self["description"] - - private(set) lazy var values: [GraphQLEnumValue] = try! invokeMethod("getValues") -} - -public class GraphQLEnumValue: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var description: String? = self["description"] - - private(set) lazy var deprecationReason: String? = self["deprecationReason"] -} - -public class GraphQLInputObjectType: GraphQLNamedType { - private(set) lazy var description: String? = self["description"] - - private(set) lazy var fields: [String: GraphQLInputField] = try! invokeMethod("getFields") -} - -public class GraphQLInputField: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var type: GraphQLType = self["type"] - - private(set) lazy var description: String? = self["description"] - - private(set) lazy var defaultValue: Any? = self["defaultValue"] - - private(set) lazy var deprecationReason: String? = self["deprecationReason"] -} - -public class GraphQLCompositeType: GraphQLNamedType { -} - -public class GraphQLObjectType: GraphQLCompositeType { - private(set) lazy var description: String? = self["description"] - - private(set) lazy var fields: [String: GraphQLField] = try! invokeMethod("getFields") - - private(set) lazy var interfaces: [GraphQLInterfaceType] = try! invokeMethod("getInterfaces") -} - -public class GraphQLAbstractType: GraphQLCompositeType { -} - -public class GraphQLInterfaceType: GraphQLAbstractType { - private(set) lazy var description: String? = self["description"] - - private(set) lazy var deprecationReason: String? = self["deprecationReason"] - - private(set) lazy var fields: [String: GraphQLField] = try! invokeMethod("getFields") - - private(set) lazy var interfaces: [GraphQLInterfaceType] = try! invokeMethod("getInterfaces") -} - -public class GraphQLUnionType: GraphQLAbstractType { - private(set) lazy var types: [GraphQLObjectType] = try! invokeMethod("getTypes") -} - -public class GraphQLField: JavaScriptObject { - private(set) lazy var name: String = self["name"] - - private(set) lazy var type: GraphQLType = self["type"] - - private(set) lazy var description: String? = self["description"] - - private(set) lazy var deprecationReason: String? = self["deprecationReason"] -} diff --git a/Sources/ApolloCodegenLib/Frontend/GraphQLSource.swift b/Sources/ApolloCodegenLib/Frontend/GraphQLSource.swift deleted file mode 100644 index 8185ef0ade..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/GraphQLSource.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Foundation -import JavaScriptCore - -/// A representation of source input to GraphQL parsing. -/// Corresponds to https://github.com/graphql/graphql-js/blob/master/src/language/source.js -public class GraphQLSource: JavaScriptObject { - private(set) lazy var filePath: String = self["name"] - - private(set) lazy var body: String = self["body"] -} - -/// Represents a location in a GraphQL source file. -public struct GraphQLSourceLocation { - let filePath: String - - let lineNumber: Int - let columnNumber: Int -} - -// These classes correspond to the AST node types defined in -// https://github.com/graphql/graphql-js/blob/master/src/language/ast.js -// But since we don't need to access these directly, we haven't defined specific wrapper types except for -// `GraphQLDocument`. - -/// An AST node. -public class ASTNode: JavaScriptObject { - lazy var kind: String = self["kind"] - - private lazy var source: GraphQLSource = bridge.fromJSValue(self["loc"]["source"]) - private(set) lazy var filePath: String = source.filePath -} - -/// A parsed GraphQL document. -public class GraphQLDocument: ASTNode { - private(set) lazy var definitions: [ASTNode] = self["definitions"] - - required init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - super.init(jsValue, bridge: bridge) - - precondition(kind == "Document", "Expected GraphQL DocumentNode but found: \(jsValue)") - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/GraphQLType.swift b/Sources/ApolloCodegenLib/Frontend/GraphQLType.swift deleted file mode 100644 index fb2403f960..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/GraphQLType.swift +++ /dev/null @@ -1,44 +0,0 @@ -import JavaScriptCore - -/// A GraphQL type. -public indirect enum GraphQLType: Equatable { - case named(GraphQLNamedType) - case nonNull(GraphQLType) - case list(GraphQLType) - - public var typeReference: String { - switch self { - case let .named(type): - return type.name - case let .nonNull(ofType): - return "\(ofType.typeReference)!" - case let .list(ofType): - return "[\(ofType.typeReference)]" - } - } -} - -extension GraphQLType: CustomDebugStringConvertible { - public var debugDescription: String { - return "" - } -} - -extension GraphQLType: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isObject, "Expected JavaScript object but found: \(jsValue)") - - let tag = jsValue[jsValue.context.globalObject["Symbol"]["toStringTag"]].toString() - - switch tag { - case "GraphQLNonNull": - let ofType = jsValue["ofType"] - self = .nonNull(GraphQLType(ofType, bridge: bridge)) - case "GraphQLList": - let ofType = jsValue["ofType"] - self = .list(GraphQLType(ofType, bridge: bridge)) - default: - self = .named(bridge.fromJSValue(jsValue)) - } - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/GraphQLValue.swift b/Sources/ApolloCodegenLib/Frontend/GraphQLValue.swift deleted file mode 100644 index 85a576edb6..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/GraphQLValue.swift +++ /dev/null @@ -1,47 +0,0 @@ -import Foundation -import JavaScriptCore - -indirect enum GraphQLValue: Equatable { - case variable(String) - case int(Int) - case float(Double) - case string(String) - case boolean(Bool) - case null - case `enum`(String) - case list([GraphQLValue]) - case object([String: GraphQLValue]) -} - -extension GraphQLValue: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isObject, "Expected JavaScript object but found: \(jsValue)") - - let kind: String = jsValue["kind"].toString() - - switch kind { - case "Variable": - self = .variable(jsValue["value"].toString()) - case "IntValue": - self = .int(jsValue["value"].toInt()) - case "FloatValue": - self = .float(jsValue["value"].toDouble()) - case "StringValue": - self = .string(jsValue["value"].toString()) - case "BooleanValue": - self = .boolean(jsValue["value"].toBool()) - case "NullValue": - self = .null - case "EnumValue": - self = .enum(jsValue["value"].toString()) - case "ListValue": - self = .list(.fromJSValue(jsValue["value"], bridge: bridge)) - case "ObjectValue": - self = .object(.fromJSValue(jsValue["value"], bridge: bridge)) - default: - preconditionFailure(""" - Unknown GraphQL value of kind "\(kind)" - """) - } - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/.vscode/settings.json b/Sources/ApolloCodegenLib/Frontend/JavaScript/.vscode/settings.json deleted file mode 100644 index 7ba84c798e..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.tabSize": 2, -} \ No newline at end of file diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/jest.config.js b/Sources/ApolloCodegenLib/Frontend/JavaScript/jest.config.js deleted file mode 100644 index 8309f68456..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/jest.config.js +++ /dev/null @@ -1,18 +0,0 @@ -/** @typedef {import('ts-jest/dist/types')} */ -/** @type {import('@jest/types').Config.InitialOptions} */ - -module.exports = { - preset: "ts-jest", - testEnvironment: "node", - setupFilesAfterEnv: ["/src/__testUtils__/matchers.ts"], - testPathIgnorePatterns: [ - "/node_modules/", - "/__fixtures__/", - "/__testUtils__/", - ], - globals: { - "ts-jest": { - tsconfig: "./tsconfig.test.json", - }, - }, -}; diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/package.json b/Sources/ApolloCodegenLib/Frontend/JavaScript/package.json deleted file mode 100644 index 7e59af86e9..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "apollo-codegen-frontend", - "private": true, - "version": "1.0.0", - "description": "Apollo Codegen Frontend", - "license": "MIT", - "author": "Apollo GraphQL ", - "scripts": { - "build": "rollup --config", - "test": "jest" - }, - "engines": { - "npm": ">=7" - }, - "dependencies": { - "graphql": "file:./vendor/graphql-16.0.0-pre+modern-js.tgz", - "tslib": "^2.3.0" - }, - "devDependencies": { - "@rollup/plugin-node-resolve": "^11.0.1", - "@rollup/plugin-replace": "^2.3.4", - "@rollup/plugin-typescript": "^8.1.0", - "@types/common-tags": "^1.8.0", - "@types/jest": "^26.0.19", - "common-tags": "^1.8.0", - "jest": "^26.6.3", - "rollup": "^2.35.1", - "rollup-plugin-terser": "^7.0.2", - "ts-jest": "^26.4.4", - "typescript": "^4.1.3" - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/rollup.config.js b/Sources/ApolloCodegenLib/Frontend/JavaScript/rollup.config.js deleted file mode 100644 index 05e4e10ac0..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/rollup.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import typescript from "@rollup/plugin-typescript"; -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import replace from "@rollup/plugin-replace"; -import { terser } from "rollup-plugin-terser"; - -/** @type {import('rollup').RollupOptions} */ -const options = { - input: "src/index.ts", - output: { - file: "../dist/ApolloCodegenFrontend.bundle.js", - format: "iife", - name: "ApolloCodegenFrontend", - sourcemap: true, - }, - plugins: [ - typescript({ - tsconfig: "tsconfig.json", - }), - nodeResolve({ - modulesOnly: true, - dedupe: ["graphql"], - }), - replace({ - "process.env.NODE_ENV": JSON.stringify("production"), - }), - terser({ - keep_classnames: true, - }), - ], -}; - -export default options; diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/__testUtils__/matchers.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/__testUtils__/matchers.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/index.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/index.ts deleted file mode 100644 index c634a809d9..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/index.ts +++ /dev/null @@ -1,294 +0,0 @@ -import { - getFieldDef, - isMetaFieldName, - isNotNullOrUndefined, -} from "../utilities"; -import { - ASTNode, - DocumentNode, - FragmentDefinitionNode, - getNamedType, - getOperationRootType, - GraphQLCompositeType, - GraphQLError, - GraphQLNamedType, - GraphQLObjectType, - GraphQLSchema, - GraphQLType, - isCompositeType, - Kind, - OperationDefinitionNode, - print, - SelectionNode, - SelectionSetNode, - typeFromAST, -} from "graphql"; -import * as ir from "./ir"; -import { valueFromValueNode } from "./values"; - -function filePathForNode(node: ASTNode): string | undefined { - return node.loc?.source?.name; -} - -export interface CompilationResult { - operations: ir.OperationDefinition[]; - fragments: ir.FragmentDefinition[]; - referencedTypes: GraphQLNamedType[]; -} - -export function compileToIR( - schema: GraphQLSchema, - document: DocumentNode -): CompilationResult { - // Collect fragment definition nodes upfront so we can compile these as we encounter them. - const fragmentNodeMap = new Map(); - - for (const definitionNode of document.definitions) { - if (definitionNode.kind !== Kind.FRAGMENT_DEFINITION) continue; - - fragmentNodeMap.set(definitionNode.name.value, definitionNode); - } - - const operations: ir.OperationDefinition[] = []; - const fragmentMap = new Map(); - const referencedTypes = new Set(); - - for (const definitionNode of document.definitions) { - if (definitionNode.kind !== Kind.OPERATION_DEFINITION) continue; - - operations.push(compileOperation(definitionNode)); - } - - // We should have encountered all fragments because GraphQL validation normally makes sure - // there are no unused fragments in the document. But to allow for situations where you want that - // validation rule removed, we compile the remaining ones separately. - - for (const [name, fragmentNode] of fragmentNodeMap.entries()) { - fragmentMap.set(name, compileFragment(fragmentNode)); - } - - return { - operations, - fragments: Array.from(fragmentMap.values()), - referencedTypes: Array.from(referencedTypes.values()), - }; - - function getFragment(name: string): ir.FragmentDefinition | undefined { - let fragment = fragmentMap.get(name); - if (fragment) return fragment; - - const fragmentNode = fragmentNodeMap.get(name); - if (!fragmentNode) return undefined; - - // Remove the fragment node from the map so we know which ones we haven't encountered yet. - fragmentNodeMap.delete(name); - - fragment = compileFragment(fragmentNode); - fragmentMap.set(name, fragment); - return fragment; - } - - function compileOperation( - operationDefinition: OperationDefinitionNode - ): ir.OperationDefinition { - if (!operationDefinition.name) { - throw new GraphQLError("Operations should be named", operationDefinition); - } - - const filePath = filePathForNode(operationDefinition); - const name = operationDefinition.name.value; - const operationType = operationDefinition.operation; - - const variables = (operationDefinition.variableDefinitions || []).map( - (node) => { - const name = node.variable.name.value; - - // The casts are a workaround for the lack of support for passing a type union - // to overloaded functions in TypeScript. - // See https://github.com/microsoft/TypeScript/issues/14107 - const type = typeFromAST(schema, node.type as any) as GraphQLType; - - // `typeFromAST` returns `undefined` when a named type is not found - // in the schema. - if (!type) { - throw new GraphQLError( - `Couldn't get type from type node "${node.type}"`, - node - ); - } - - referencedTypes.add(getNamedType(type)); - - return { - name, - type, - }; - } - ); - - const source = print(operationDefinition); - const rootType = getOperationRootType( - schema, - operationDefinition - ) as GraphQLObjectType; - - return { - filePath, - name, - operationType, - rootType, - variables, - source, - selectionSet: compileSelectionSet( - operationDefinition.selectionSet, - rootType - ), - }; - } - - function compileFragment( - fragmentDefinition: FragmentDefinitionNode - ): ir.FragmentDefinition { - const name = fragmentDefinition.name.value; - - const filePath = filePathForNode(fragmentDefinition); - const source = print(fragmentDefinition); - - const typeCondition = typeFromAST( - schema, - fragmentDefinition.typeCondition - ) as GraphQLCompositeType; - - return { - name, - filePath, - source, - typeCondition, - selectionSet: compileSelectionSet( - fragmentDefinition.selectionSet, - typeCondition - ), - }; - } - - function compileSelectionSet( - selectionSetNode: SelectionSetNode, - parentType: GraphQLCompositeType, - visitedFragments: Set = new Set() - ): ir.SelectionSet { - return { - parentType, - selections: selectionSetNode.selections - .map((selectionNode) => - compileSelection(selectionNode, parentType, visitedFragments) - ) - .filter(isNotNullOrUndefined), - }; - } - - function compileSelection( - selectionNode: SelectionNode, - parentType: GraphQLCompositeType, - visitedFragments: Set - ): ir.Selection | undefined { - switch (selectionNode.kind) { - case Kind.FIELD: { - const name = selectionNode.name.value; - const alias = selectionNode.alias?.value; - - const fieldDef = getFieldDef(schema, parentType, name); - if (!fieldDef) { - throw new GraphQLError( - `Cannot query field "${name}" on type "${String(parentType)}"`, - selectionNode - ); - } - - const fieldType = fieldDef.type; - const unwrappedFieldType = getNamedType(fieldType); - - referencedTypes.add(unwrappedFieldType); - - const { description, deprecationReason } = fieldDef; - - const args: ir.Field["arguments"] = - selectionNode.arguments && selectionNode.arguments.length > 0 - ? selectionNode.arguments.map((arg) => { - const name = arg.name.value; - const argDef = fieldDef.args.find( - (argDef) => argDef.name === arg.name.value - ); - const argDefType = (argDef && argDef.type) || undefined; - return { - name, - value: valueFromValueNode(arg.value), - type: argDefType, - }; - }) - : undefined; - - let field: ir.Field = { - kind: "Field", - name, - alias, - arguments: args, - type: fieldType, - description: - !isMetaFieldName(name) && description ? description : undefined, - deprecationReason: deprecationReason || undefined, - }; - - if (isCompositeType(unwrappedFieldType)) { - const selectionSetNode = selectionNode.selectionSet; - - if (!selectionSetNode) { - throw new GraphQLError( - `Composite field "${name}" on type "${String( - parentType - )}" requires selection set`, - selectionNode - ); - } - - field.selectionSet = compileSelectionSet( - selectionSetNode, - unwrappedFieldType - ); - } - return field; - } - case Kind.INLINE_FRAGMENT: { - const typeNode = selectionNode.typeCondition; - const typeCondition = typeNode - ? (typeFromAST(schema, typeNode) as GraphQLCompositeType) - : parentType; - return { - kind: "InlineFragment", - selectionSet: compileSelectionSet( - selectionNode.selectionSet, - typeCondition - ), - }; - } - case Kind.FRAGMENT_SPREAD: { - const fragmentName = selectionNode.name.value; - if (visitedFragments.has(fragmentName)) return undefined; - visitedFragments.add(fragmentName); - - const fragment = getFragment(fragmentName); - if (!fragment) { - throw new GraphQLError( - `Unknown fragment "${fragmentName}".`, - selectionNode.name - ); - } - - const fragmentSpread: ir.FragmentSpread = { - kind: "FragmentSpread", - fragment, - }; - return fragmentSpread; - } - } - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/ir.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/ir.ts deleted file mode 100644 index b78026101c..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/ir.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { - GraphQLCompositeType, - GraphQLInputType, - GraphQLObjectType, - GraphQLOutputType, - GraphQLType, -} from "graphql"; -import { GraphQLValue } from "./values"; - -export interface OperationDefinition { - name: string; - operationType: OperationType; - variables: VariableDefinition[]; - rootType: GraphQLObjectType; - selectionSet: SelectionSet; - source: string; - filePath?: string; -} - -export type OperationType = "query" | "mutation" | "subscription"; - -export interface VariableDefinition { - name: string; - type: GraphQLType; - defaultValue?: GraphQLValue; -} - -export interface FragmentDefinition { - name: string; - typeCondition: GraphQLCompositeType; - selectionSet: SelectionSet; - source: string; - filePath?: string; -} - -export interface SelectionSet { - parentType: GraphQLCompositeType; - selections: Selection[]; -} - -export type Selection = Field | InlineFragment | FragmentSpread; - -export interface Field { - kind: "Field"; - name: string; - alias?: string; - arguments?: Argument[]; - type: GraphQLOutputType; - description?: string; - deprecationReason?: string; - selectionSet?: SelectionSet; - directives?: Directive[]; -} - -export interface Argument { - name: string; - value: GraphQLValue; - type?: GraphQLInputType; -} - -export interface InlineFragment { - kind: "InlineFragment"; - typeCondition?: GraphQLCompositeType; - selectionSet: SelectionSet; - directives?: Directive[]; -} - -export interface FragmentSpread { - kind: "FragmentSpread"; - fragment: FragmentDefinition; - directives?: Directive[]; -} - -export interface Directive { - name: string; - arguments?: Argument[]; -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/values.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/values.ts deleted file mode 100644 index 294d0a21ae..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/compiler/values.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ValueNode } from 'graphql'; - -export type GraphQLValue = - | { - kind: - | 'Variable' - | 'IntValue' - | 'FloatValue' - | 'StringValue' - | 'EnumValue'; - value: string; - } - | { kind: 'BooleanValue'; value: boolean } - | { kind: 'NullValue' } - | GraphQLListValue - | GraphQLObjectValue; - -export interface GraphQLListValue { - kind: 'ListValue'; - value: GraphQLValue[]; -} - -export interface GraphQLObjectValue { - kind: 'ObjectValue'; - value: { [name: string]: GraphQLValue }; -} - -export function valueFromValueNode(valueNode: ValueNode): GraphQLValue { - switch (valueNode.kind) { - case 'Variable': - return { kind: valueNode.kind, value: valueNode.name.value }; - case 'ListValue': - return { - kind: valueNode.kind, - value: valueNode.values.map(valueFromValueNode), - }; - case 'ObjectValue': - return { - kind: valueNode.kind, - value: valueNode.fields.reduce((object, field) => { - object[field.name.value] = valueFromValueNode(field.value); - return object; - }, {} as GraphQLObjectValue['value']), - }; - default: - return valueNode; - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/index.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/index.ts deleted file mode 100644 index acaaae402d..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { - Source, - buildClientSchema, - GraphQLSchema, - parse, - DocumentNode, - concatAST, - GraphQLError, - validate, - buildASTSchema, - printSchema, -} from "graphql"; -import { defaultValidationRules } from "./validationRules"; -import { compileToIR, CompilationResult } from "./compiler"; -import { assertValidSchema, assertValidSDL } from "./utilities/graphql"; - -// We need to export all the classes we want to map to native objects, -// so we have access to the constructor functions for type checks. -export { - Source, - GraphQLError, - GraphQLSchema, - GraphQLScalarType, - GraphQLObjectType, - GraphQLInterfaceType, - GraphQLUnionType, - GraphQLEnumType, - GraphQLInputObjectType, -} from "graphql"; -export { GraphQLSchemaValidationError } from "./utilities/graphql"; - -export function loadSchemaFromIntrospectionResult( - introspectionResult: string -): GraphQLSchema { - let payload = JSON.parse(introspectionResult); - - if (payload.data) { - payload = payload.data; - } - - const schema = buildClientSchema(payload); - - assertValidSchema(schema); - - return schema; -} - -export function loadSchemaFromSDL(source: Source): GraphQLSchema { - const document = parse(source); - - assertValidSDL(document); - - const schema = buildASTSchema(document, { assumeValidSDL: true }); - - assertValidSchema(schema); - - return schema; -} - -export function printSchemaToSDL(schema: GraphQLSchema): string { - return printSchema(schema) -} - -export function parseDocument(source: Source): DocumentNode { - return parse(source); -} - -export function mergeDocuments(documents: DocumentNode[]): DocumentNode { - return concatAST(documents); -} - -export function validateDocument( - schema: GraphQLSchema, - document: DocumentNode -): readonly GraphQLError[] { - return validate(schema, document, defaultValidationRules); -} - -export function compileDocument( - schema: GraphQLSchema, - document: DocumentNode -): CompilationResult { - return compileToIR(schema, document); -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/graphql.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/graphql.ts deleted file mode 100644 index edff5e3f42..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/graphql.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { - ASTNode, - FieldNode, - GraphQLCompositeType, - GraphQLField, - GraphQLSchema, - isInterfaceType, - isObjectType, - isUnionType, - Kind, - Location, - SchemaMetaFieldDef, - SelectionSetNode, - TypeMetaFieldDef, - TypeNameMetaFieldDef, - validateSchema, - visit, - GraphQLError, - DocumentNode, -} from "graphql"; -import { validateSDL } from "graphql/validation/validate"; - -export class GraphQLSchemaValidationError extends Error { - constructor(public validationErrors: readonly GraphQLError[]) { - super(validationErrors.map((error) => error.message).join("\n\n")); - - this.name = "GraphQLSchemaValidationError"; - } -} - -export function assertValidSDL(document: DocumentNode) { - const errors = validateSDL(document); - if (errors.length !== 0) { - throw new GraphQLSchemaValidationError(errors); - } -} - -export function assertValidSchema(schema: GraphQLSchema) { - const errors = validateSchema(schema); - if (errors.length !== 0) { - throw new GraphQLSchemaValidationError(errors); - } -} - -export function sourceAt(location: Location) { - return location.source.body.slice(location.start, location.end); -} - -export function filePathForNode(node: ASTNode): string | undefined { - return node.loc?.source?.name; -} - -export function isMetaFieldName(name: string) { - return name.startsWith("__"); -} - -const typenameField = { - kind: Kind.FIELD, - name: { kind: Kind.NAME, value: "__typename" }, -}; - -export function withTypenameFieldAddedWhereNeeded(ast: ASTNode) { - return visit(ast, { - enter: { - SelectionSet(node: SelectionSetNode) { - return { - ...node, - selections: node.selections.filter( - (selection) => - !( - selection.kind === "Field" && - (selection as FieldNode).name.value === "__typename" - ) - ), - }; - }, - }, - leave(node: ASTNode) { - if (!(node.kind === "Field" || node.kind === "FragmentDefinition")) - return undefined; - if (!node.selectionSet) return undefined; - - return { - ...node, - selectionSet: { - ...node.selectionSet, - selections: [typenameField, ...node.selectionSet.selections], - }, - }; - }, - }); -} - -// Utility functions extracted from graphql-js - -/** - * Not exactly the same as the executor's definition of getFieldDef, in this - * statically evaluated environment we do not always have an Object type, - * and need to handle Interface and Union types. - */ -export function getFieldDef( - schema: GraphQLSchema, - parentType: GraphQLCompositeType, - fieldName: string, -): GraphQLField | undefined { - if ( - fieldName === SchemaMetaFieldDef.name && - schema.getQueryType() === parentType - ) { - return SchemaMetaFieldDef; - } - if (fieldName === TypeMetaFieldDef.name && schema.getQueryType() === parentType) { - return TypeMetaFieldDef; - } - if ( - fieldName === TypeNameMetaFieldDef.name && - (isObjectType(parentType) || - isInterfaceType(parentType) || - isUnionType(parentType)) - ) { - return TypeNameMetaFieldDef; - } - if (isObjectType(parentType) || isInterfaceType(parentType)) { - return parentType.getFields()[fieldName]; - } - - return undefined; -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/index.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/index.ts deleted file mode 100644 index f3fd094d0b..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./graphql"; -export * from "./predicates"; diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/predicates.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/predicates.ts deleted file mode 100644 index 5769992556..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/utilities/predicates.ts +++ /dev/null @@ -1,14 +0,0 @@ -export function isNotNullOrUndefined( - value: T | null | undefined, -): value is T { - return value !== null && typeof value !== 'undefined'; -} - -export function isObject(value: any): value is object { - return ( - value !== undefined && - value !== null && - typeof value === 'object' && - !Array.isArray(value) - ); -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/validationRules.ts b/Sources/ApolloCodegenLib/Frontend/JavaScript/src/validationRules.ts deleted file mode 100644 index 4ad4a0255e..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/src/validationRules.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - NoUnusedFragmentsRule, - ValidationRule, - specifiedRules, - FieldNode, - GraphQLError, - OperationDefinitionNode, - ValidationContext, -} from "graphql"; - -const specifiedRulesToBeRemoved = [NoUnusedFragmentsRule]; - -export const defaultValidationRules: ValidationRule[] = [ - NoAnonymousQueries, - NoTypenameAlias, - ...specifiedRules.filter((rule) => !specifiedRulesToBeRemoved.includes(rule)), -]; - -export function NoAnonymousQueries(context: ValidationContext) { - return { - OperationDefinition(node: OperationDefinitionNode) { - if (!node.name) { - context.reportError( - new GraphQLError( - "Apollo does not support anonymous operations because operation names are used during code generation. Please give this operation a name.", - node - ) - ); - } - return false; - }, - }; -} - -export function NoTypenameAlias(context: ValidationContext) { - return { - Field(node: FieldNode) { - const aliasName = node.alias && node.alias.value; - if (aliasName == "__typename") { - context.reportError( - new GraphQLError( - "Apollo needs to be able to insert __typename when needed, so using it as an alias is not supported.", - node - ) - ); - } - }, - }; -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.base.json b/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.base.json deleted file mode 100644 index f85872ce12..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.base.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "es2019", - "lib": ["es2019"], - "module": "es2020", - "moduleResolution": "node", - "preserveSymlinks": true, - "esModuleInterop": true, - "sourceMap": true, - "declaration": false, - "declarationMap": false, - "removeComments": true, - "strict": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "forceConsistentCasingInFileNames": true, - }, -} \ No newline at end of file diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.json b/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.json deleted file mode 100644 index 0ddd372425..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.base", - "compilerOptions": { - "types": [], - "rootDir": "./src", - "outDir": "./lib" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "**/__tests__/*", "**/__testUtils__/*"] -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.test.base.json b/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.test.base.json deleted file mode 100644 index 54a491bc86..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.test.base.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.base", - "compilerOptions": { - "types": ["node", "jest"], - }, - "files": ["./src/__testUtils__/matchers.ts"], -} diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.test.json b/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.test.json deleted file mode 100644 index 6148abaca7..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScript/tsconfig.test.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.test.base", - "include": ["**/__tests__/**/*"] -} \ No newline at end of file diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScript/vendor/graphql-16.0.0-pre+modern-js.tgz b/Sources/ApolloCodegenLib/Frontend/JavaScript/vendor/graphql-16.0.0-pre+modern-js.tgz deleted file mode 100644 index 6f1cc6dfe4..0000000000 Binary files a/Sources/ApolloCodegenLib/Frontend/JavaScript/vendor/graphql-16.0.0-pre+modern-js.tgz and /dev/null differ diff --git a/Sources/ApolloCodegenLib/Frontend/JavaScriptBridge.swift b/Sources/ApolloCodegenLib/Frontend/JavaScriptBridge.swift deleted file mode 100644 index 35a7c8ae93..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/JavaScriptBridge.swift +++ /dev/null @@ -1,356 +0,0 @@ -import JavaScriptCore - -// JavaScriptCore APIs haven't been annotated for nullability, but most of its methods will never return `null` -// and can be safely force unwrapped. (Even when an exception is thrown they would still return -// a `JSValue` representing a JavaScript `undefined` value.) - -/// An error thrown during JavaScript execution. -/// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error -public class JavaScriptError: JavaScriptObject, Error, @unchecked Sendable { - // These properties were changed to read-only when `@unchecked Sendable` was added for - // Xcode 13.3. If you make them publicly writable or alter their values within the class - // you will need to do so with thread-safety in mind. - var name: String? { self["name"] } - var message: String? { self["message"] } - var stack: String? { self["stack"] } -} - -extension JavaScriptError: CustomStringConvertible { - public var description: String { - return jsValue.toString() - } -} - -/// A type that references an underlying JavaScript object. -public class JavaScriptObject: JavaScriptValueDecodable { - let jsValue: JSValue - unowned let bridge: JavaScriptBridge - - static func fromJSValue(_ jsValue: JSValue, bridge: JavaScriptBridge) -> Self { - return bridge.wrap(jsValue) - } - - required init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isObject) - - self.jsValue = jsValue - self.bridge = bridge - } - - subscript(property: Any) -> JSValue { - return jsValue[property] - } - - subscript(property: Any) -> Decodable { - return bridge.fromJSValue(jsValue[property]) - } - - private func call(_ functionName: String, with arguments: [Any]) throws -> JSValue { - return try bridge.throwingJavaScriptErrorIfNeeded { - let function = jsValue[functionName] - - precondition(!function.isUndefined, "Function \(functionName) is undefined") - - return function.call(withArguments: bridge.unwrap(arguments))! - } - } - - func call(_ functionName: String, with arguments: Any...) throws -> JSValue { - try call(functionName, with: arguments) - } - - func call(_ functionName: String, with arguments: Any...) throws -> Decodable { - return bridge.fromJSValue(try call(functionName, with: arguments)) - } - - private func invokeMethod(_ methodName: String, with arguments: [Any]) throws -> JSValue { - return try bridge.throwingJavaScriptErrorIfNeeded { - jsValue.invokeMethod(methodName, withArguments: bridge.unwrap(arguments)) - } - } - - func invokeMethod(_ methodName: String, with arguments: Any...) throws -> JSValue { - try invokeMethod(methodName, with: arguments) - } - - func invokeMethod(_ methodName: String, with arguments: Any...) throws -> Decodable { - return bridge.fromJSValue(try invokeMethod(methodName, with: arguments)) - } - - func construct(with arguments: Any...) throws -> Wrapper { - return bridge.fromJSValue(try bridge.throwingJavaScriptErrorIfNeeded { - jsValue.construct(withArguments: bridge.unwrap(arguments)) - }) - } -} - -extension JavaScriptObject: Equatable { - public static func ==(lhs: JavaScriptObject, rhs: JavaScriptObject) -> Bool { - return lhs.jsValue == rhs.jsValue - } -} - -extension JavaScriptObject: CustomDebugStringConvertible { - public var debugDescription: String { - return "<\(type(of: self)): \(jsValue.toString()!)>" - } -} - -/// The JavaScript bridge is responsible for converting values to and from type-safe wrapper objects. It also ensures exceptions thrown from JavaScript wrapped and rethrown. -class JavaScriptBridge { - private var context: JSContext - - // In JavaScript, classes are represented by constructor functions. We need access to these when checking - // the type of a received value in `wrap(_)` below. - // We keep a bidirectional mapping between constructors and wrapper types so we can both access the - // corresponding wrapper type, and perform an `instanceof` check based on the corresponding constructor - // for the expected wrapper type in case there isn't a direct match and we are receiving a subtype. - private var constructorToWrapperType: [JSValue /* constructor function */: JavaScriptObject.Type] = [:] - private var wrapperTypeToConstructor: [AnyHashable /* JavaScriptObject.Type */: JSValue] = [:] - - // We keep a map between `JSValue` objects and wrapper objects, to avoid repeatedly creating new wrappers and - // to guarantee referential equality. - // TODO: We may want to consider a weak map here, because this does mean we'll be keeping alive - // all objects that are passed over the bridge both on the Swift side and in JavaScript - // ('JSValue` is an Objective-C object that uses `JSValueProtect` to mark the underlying JavaScript - // object as inelligable for garbage collection.) - private var wrapperMap: [JSValue: JavaScriptObject] = [:] - - init(context: JSContext) { - self.context = context - - register(JavaScriptObject.self, forJavaScriptClass: "Object", from: context.globalObject) - register(JavaScriptError.self, forJavaScriptClass: "Error", from: context.globalObject) - } - - public func register(_ wrapperType: JavaScriptObject.Type, forJavaScriptClass className: String? = nil, from scope: JavaScriptObject) { - register(wrapperType, forJavaScriptClass: className, from: scope.jsValue) - } - - public func register(_ wrapperType: JavaScriptObject.Type, forJavaScriptClass className: String? = nil, from scope: JSValue) { - let className = className ?? String(describing: wrapperType) - - let constructor = scope[className] - precondition(constructor.isObject, "Couldn't find JavaScript constructor function for class \(className). Make sure the class is exported from the library's entry point.") - - constructorToWrapperType[constructor] = wrapperType - wrapperTypeToConstructor[ObjectIdentifier(wrapperType)] = constructor - } - - func fromJSValue(_ jsValue: JSValue) -> Decodable { - return Decodable.fromJSValue(jsValue, bridge: self) - } - - fileprivate func wrap(_ jsValue: JSValue) -> Wrapper { - if let wrapper = wrapperMap[jsValue] { - return checkedDowncast(wrapper) - } - - precondition(jsValue.isObject, "Expected JavaScript object but found: \(jsValue)") - - let wrapperType: JavaScriptObject.Type - - let constructor = jsValue["constructor"] - - // If an object doesn't have a prototype or has `Object` as its direct prototype, - // we assume it is of the expected type and let the wrapper handle further type checks if needed. - // This occurs for pseudo-classes like the AST nodes for example, that rely on a `kind` property - // to indicate their type instead of a prototype. - if constructor.isUndefined || constructor["name"].toString() == "Object" { - wrapperType = Wrapper.self - } else if let registeredType = constructorToWrapperType[constructor] { - // We have a wrapper type registered for the JavaScript class. - wrapperType = registeredType - } else { - // We may have received an unregistered subtype of the expected type, and we don't necessarily - // have a wrapper registered for every subtype (this is likely to happen with - // subtypes of `Error` for example). So if we can verify the value is indeed an instance of - // the expected type we use that as the wrapper. - - guard let expectedConstructor = wrapperTypeToConstructor[ObjectIdentifier(Wrapper.self)] else { - preconditionFailure(""" - Couldn't find JavaScript constructor for wrapper type \(Wrapper.self). \ - Make sure the type is registered with the bridge." - """) - } - - if jsValue.isInstance(of: expectedConstructor) { - wrapperType = Wrapper.self - } else { - preconditionFailure(""" - Object with JavaScript constructor \(constructor["name"]) doesn't seem to be \ - an instance of expected type \(expectedConstructor["name"])" - """) - } - } - - let wrapper = wrapperType.init(jsValue, bridge: self) - wrapperMap[jsValue] = wrapper - return checkedDowncast(wrapper) - } - - fileprivate func unwrap(_ values: [Any]) -> [Any] { - return values.map { value in - if let unwrappable = value as? CustomJavaScriptValueUnwrappable { - return unwrappable.unwrapJSValue - } else { - return value - } - } - } - - @discardableResult func throwingJavaScriptErrorIfNeeded(body: () -> ReturnValue) throws -> ReturnValue { - let result = body() - - // Errors thrown from JavaScript are stored on the context and ignored by default. - // To surface these to callers, we wrap them in a `JavaScriptError` and throw. - if let exception = context.exception { - throw fromJSValue(exception) as JavaScriptError - } - - return result - } -} - -/// A type that can decode itself from a JavaScript value. -protocol JavaScriptValueDecodable { - // We rely on a static `fromJSValue` method to allow for polymorphic construction and to be able - // to return existing wrappers instead of creating new instances. - static func fromJSValue(_ jsValue: JSValue, bridge: JavaScriptBridge) -> Self - - init(_ jsValue: JSValue, bridge: JavaScriptBridge) -} - -extension JavaScriptValueDecodable { - static func fromJSValue(_ jsValue: JSValue, bridge: JavaScriptBridge) -> Self { - return Self.init(jsValue, bridge: bridge) - } -} - -extension Optional: JavaScriptValueDecodable where Wrapped: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - if jsValue.isUndefined || jsValue.isNull { - self = nil - } else { - self = Wrapped.fromJSValue(jsValue, bridge: bridge) - } - } -} - -extension Array: JavaScriptValueDecodable where Element: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - self = jsValue.toArray { Element.fromJSValue($0, bridge: bridge) } - } -} - -extension Dictionary: JavaScriptValueDecodable where Key == String, Value: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - self = jsValue.toDictionary { Value.fromJSValue($0, bridge: bridge) } - } -} - -extension String: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isString, "Expected JavaScript string but found: \(jsValue)") - self = jsValue.toString() - } -} - -extension Int: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isNumber, "Expected JavaScript number but found: \(jsValue)") - self = jsValue.toInt() - } -} - -extension Bool: JavaScriptValueDecodable { - init(_ jsValue: JSValue, bridge: JavaScriptBridge) { - precondition(jsValue.isBoolean, "Expected JavaScript boolean but found: \(jsValue)") - self = jsValue.toBool() - } -} - -extension JSValue { - subscript(_ property: Any) -> JSValue { - return objectForKeyedSubscript(property) - } - - func toInt() -> Int { - return Int(toInt32()) - } - - // The regular `toArray()` does a deep convert of all elements, which means JavaScript objects - // will be converted to `NSDictionary` and we lose the ability to pass references back to JavaScript. - // That's why we manually construct an array by iterating over the indexes here. - func toArray(_ transform: (JSValue) throws -> Element) rethrows -> [Element] { - precondition(isArray, "Expected JavaScript array but found: \(self)") - - let length = self["length"].toInt() - - var array = [Element]() - array.reserveCapacity(length) - - for index in 0..(_ transform: (JSValue) throws -> Value) rethrows -> [String: Value] { - precondition(isObject, "Expected JavaScript object but found: \(self)") - - guard let keys = context.globalObject["Object"].invokeMethod("keys", withArguments: [self])?.toArray() as? [String] else { - preconditionFailure("Couldn't get keys for object \(self)") - } - - var dictionary = [String: Value]() - - for key in keys { - let element = try transform(self.objectForKeyedSubscript(key)) - dictionary[key] = element - } - - return dictionary - } -} - -private func checkedDowncast(_ object: AnyObject) -> ExpectedType { - guard let expected = object as? ExpectedType else { - preconditionFailure("Expected type to be \(ExpectedType.self), but found \(type(of: object))") - } - - return expected -} - -fileprivate protocol CustomJavaScriptValueUnwrappable { - var unwrapJSValue: Any { get } -} - -extension JavaScriptObject: CustomJavaScriptValueUnwrappable { - var unwrapJSValue: Any { - return jsValue - } -} - -extension Optional: CustomJavaScriptValueUnwrappable where Wrapped: CustomJavaScriptValueUnwrappable { - var unwrapJSValue: Any { - return map(\.unwrapJSValue) as Any - } -} - -extension Array: CustomJavaScriptValueUnwrappable where Element: CustomJavaScriptValueUnwrappable { - var unwrapJSValue: Any { - return map(\.unwrapJSValue) - } -} - -extension Dictionary: CustomJavaScriptValueUnwrappable where Key == String, Value: CustomJavaScriptValueUnwrappable { - var unwrapJSValue: Any { - return mapValues(\.unwrapJSValue) - } -} diff --git a/Sources/ApolloCodegenLib/Frontend/dist/ApolloCodegenFrontend.bundle.js b/Sources/ApolloCodegenLib/Frontend/dist/ApolloCodegenFrontend.bundle.js deleted file mode 100644 index 0ad3ba6364..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/dist/ApolloCodegenFrontend.bundle.js +++ /dev/null @@ -1,2 +0,0 @@ -var ApolloCodegenFrontend=function(e){"use strict";function t(e){return"object"==typeof e&&null!==e}function n(e,t){const n=/\r\n|[\n\r]/g;let r,i=1,o=t+1;for(;(r=n.exec(e.body))&&r.index120){const e=Math.floor(p/80),t=p%80,n=[];for(let e=0;e["",e])),[" ",s(t-1)+"^"],["",n[e+1]]])}return l+o([[""+(c-1),d[i-1]],[`${c}`,f],["",s(p-1)+"^"],[`${c+1}`,d[i+1]]])}function o(e){const t=e.filter((([e,t])=>void 0!==t)),n=Math.max(...t.map((([e])=>e.length)));return t.map((([e,t])=>{return s(n-(r=e).length)+r+(t?" | "+t:" |");var r})).join("\n")}function s(e){return Array(e+1).join(" ")}class GraphQLError extends Error{constructor(e,r,i,o,s,a,c){super(e);const u=Array.isArray(r)?0!==r.length?r:void 0:r?[r]:void 0;let p=i;!p&&u&&(p=u[0].loc?.source);let l,d=o;!d&&u&&(d=u.reduce(((e,t)=>(t.loc&&e.push(t.loc.start),e)),[])),d&&0===d.length&&(d=void 0),o&&i?l=o.map((e=>n(i,e))):u&&(l=u.reduce(((e,t)=>(t.loc&&e.push(n(t.loc.source,t.loc.start)),e)),[]));let f=c;if(null==f&&null!=a){const e=a.extensions;t(e)&&(f=e)}Object.defineProperties(this,{name:{value:"GraphQLError"},message:{value:e,enumerable:!0,writable:!0},locations:{value:l??void 0,enumerable:null!=l},path:{value:s??void 0,enumerable:null!=s},nodes:{value:u??void 0},source:{value:p??void 0},positions:{value:d??void 0},originalError:{value:a},extensions:{value:f??void 0,enumerable:null!=f}}),a?.stack?Object.defineProperty(this,"stack",{value:a.stack,writable:!0,configurable:!0}):Error.captureStackTrace?Error.captureStackTrace(this,GraphQLError):Object.defineProperty(this,"stack",{value:Error().stack,writable:!0,configurable:!0})}toString(){return function(e){let t=e.message;if(e.nodes)for(const n of e.nodes)n.loc&&(t+="\n\n"+r(n.loc));else if(e.source&&e.locations)for(const n of e.locations)t+="\n\n"+i(e.source,n);return t}(this)}get[Symbol.toStringTag](){return"Object"}}function a(e,t,n){return new GraphQLError(`Syntax Error: ${n}`,void 0,e,[t])}const c=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"});class Location{constructor(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}toJSON(){return{start:this.start,end:this.end}}[Symbol.for("nodejs.util.inspect.custom")](){return this.toJSON()}}class Token{constructor(e,t,n,r,i,o,s){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=s,this.prev=o,this.next=null}toJSON(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}}[Symbol.for("nodejs.util.inspect.custom")](){return this.toJSON()}}function u(e){return null!=e&&"string"==typeof e.kind}const p=Object.freeze({SOF:"",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"});function l(e){return d(e,[])}function d(e,t){switch(typeof e){case"string":return JSON.stringify(e);case"function":return e.name?`[function ${e.name}]`:"[function]";case"object":return null===e?"null":function(e,t){if(-1!==t.indexOf(e))return"[Circular]";const n=[...t,e];if("function"==typeof e.toJSON){const t=e.toJSON(e);if(t!==e)return"string"==typeof t?t:d(t,n)}else if(Array.isArray(e))return function(e,t){if(0===e.length)return"[]";if(t.length>2)return"[Array]";const n=Math.min(10,e.length),r=e.length-n,i=[];for(let r=0;r1&&i.push(`... ${r} more items`);return"["+i.join(", ")+"]"}(e,n);return function(e,t){const n=Object.keys(e);if(0===n.length)return"{}";if(t.length>2)return"["+function(e){const t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){const t=e.constructor.name;if("string"==typeof t&&""!==t)return t}return t}(e)+"]";return"{ "+n.map((n=>n+": "+d(e[n],t))).join(", ")+" }"}(e,n)}(e,t);default:return String(e)}}function f(e,t){if(!Boolean(e))throw new Error(t)}var h=function(e,t){return e instanceof t};class Source{constructor(e,t="GraphQL request",n={line:1,column:1}){"string"==typeof e||f(0,`Body must be a string. Received: ${l(e)}.`),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||f(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||f(0,"column in locationOffset is 1-indexed and must be positive.")}get[Symbol.toStringTag](){return"Source"}}const m=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"});function y(e){const t=e.split(/\r\n|[\n\r]/g),n=function(e){let t=!0,n=!0,r=0,i=null;for(let o=0;or&&E(t[i-1]);)--i;return t.slice(r,i).join("\n")}function E(e){for(let t=0;t31||9===s));return new Token(p.COMMENT,t,a,n,r,i,o.slice(t+1,a))}function _(e,t,n,r,i,o){const s=e.body;let c=n,u=t,l=!1;if(45===c&&(c=s.charCodeAt(++u)),48===c){if(c=s.charCodeAt(++u),c>=48&&c<=57)throw a(e,u,`Invalid number, unexpected digit after 0: ${N(c)}.`)}else u=O(e,u,c),c=s.charCodeAt(u);if(46===c&&(l=!0,c=s.charCodeAt(++u),u=O(e,u,c),c=s.charCodeAt(u)),69!==c&&101!==c||(l=!0,c=s.charCodeAt(++u),43!==c&&45!==c||(c=s.charCodeAt(++u)),u=O(e,u,c),c=s.charCodeAt(u)),46===c||function(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}(c))throw a(e,u,`Invalid number, expected digit but got: ${N(c)}.`);return new Token(l?p.FLOAT:p.INT,t,u,r,i,o,s.slice(t,u))}function O(e,t,n){const r=e.body;let i=t,o=n;if(o>=48&&o<=57){do{o=r.charCodeAt(++i)}while(o>=48&&o<=57);return i}throw a(e,i,`Invalid number, expected digit but got: ${N(o)}.`)}function b(e,t,n,r,i){const o=e.body;let s=t+1,c=s,u=0,l="";for(;s=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function A(e,t,n,r,i){const o=e.body,s=o.length;let a=t+1,c=0;for(;a!==s&&!isNaN(c=o.charCodeAt(a))&&(95===c||c>=48&&c<=57||c>=65&&c<=90||c>=97&&c<=122);)++a;return new Token(p.NAME,t,a,n,r,i,o.slice(t,a))}function D(e,t){return new Parser(e,t).parseDocument()}class Parser{constructor(e,t){const n=function(e){return h(e,Source)}(e)?e:new Source(e);this._lexer=new Lexer(n),this._options=t}parseName(){const e=this.expectToken(p.NAME);return{kind:c.NAME,value:e.value,loc:this.loc(e)}}parseDocument(){const e=this._lexer.token;return{kind:c.DOCUMENT,definitions:this.many(p.SOF,this.parseDefinition,p.EOF),loc:this.loc(e)}}parseDefinition(){if(this.peek(p.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else{if(this.peek(p.BRACE_L))return this.parseOperationDefinition();if(this.peekDescription())return this.parseTypeSystemDefinition()}throw this.unexpected()}parseOperationDefinition(){const e=this._lexer.token;if(this.peek(p.BRACE_L))return{kind:c.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(e)};const t=this.parseOperationType();let n;return this.peek(p.NAME)&&(n=this.parseName()),{kind:c.OPERATION_DEFINITION,operation:t,name:n,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}}parseOperationType(){const e=this.expectToken(p.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)}parseVariableDefinitions(){return this.optionalMany(p.PAREN_L,this.parseVariableDefinition,p.PAREN_R)}parseVariableDefinition(){const e=this._lexer.token;return{kind:c.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(p.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(p.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}}parseVariable(){const e=this._lexer.token;return this.expectToken(p.DOLLAR),{kind:c.VARIABLE,name:this.parseName(),loc:this.loc(e)}}parseSelectionSet(){const e=this._lexer.token;return{kind:c.SELECTION_SET,selections:this.many(p.BRACE_L,this.parseSelection,p.BRACE_R),loc:this.loc(e)}}parseSelection(){return this.peek(p.SPREAD)?this.parseFragment():this.parseField()}parseField(){const e=this._lexer.token,t=this.parseName();let n,r;return this.expectOptionalToken(p.COLON)?(n=t,r=this.parseName()):r=t,{kind:c.FIELD,alias:n,name:r,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(p.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(e)}}parseArguments(e){const t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(p.PAREN_L,t,p.PAREN_R)}parseArgument(){const e=this._lexer.token,t=this.parseName();return this.expectToken(p.COLON),{kind:c.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}}parseConstArgument(){const e=this._lexer.token;return{kind:c.ARGUMENT,name:this.parseName(),value:(this.expectToken(p.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}}parseFragment(){const e=this._lexer.token;this.expectToken(p.SPREAD);const t=this.expectOptionalKeyword("on");return!t&&this.peek(p.NAME)?{kind:c.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:c.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}}parseFragmentDefinition(){const e=this._lexer.token;return this.expectKeyword("fragment"),!0===this._options?.experimentalFragmentVariables?{kind:c.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}:{kind:c.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}}parseFragmentName(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()}parseValueLiteral(e){const t=this._lexer.token;switch(t.kind){case p.BRACKET_L:return this.parseList(e);case p.BRACE_L:return this.parseObject(e);case p.INT:return this._lexer.advance(),{kind:c.INT,value:t.value,loc:this.loc(t)};case p.FLOAT:return this._lexer.advance(),{kind:c.FLOAT,value:t.value,loc:this.loc(t)};case p.STRING:case p.BLOCK_STRING:return this.parseStringLiteral();case p.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:c.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:c.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:c.NULL,loc:this.loc(t)};default:return{kind:c.ENUM,value:t.value,loc:this.loc(t)}}case p.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()}parseStringLiteral(){const e=this._lexer.token;return this._lexer.advance(),{kind:c.STRING,value:e.value,block:e.kind===p.BLOCK_STRING,loc:this.loc(e)}}parseList(e){const t=this._lexer.token;return{kind:c.LIST,values:this.any(p.BRACKET_L,(()=>this.parseValueLiteral(e)),p.BRACKET_R),loc:this.loc(t)}}parseObject(e){const t=this._lexer.token;return{kind:c.OBJECT,fields:this.any(p.BRACE_L,(()=>this.parseObjectField(e)),p.BRACE_R),loc:this.loc(t)}}parseObjectField(e){const t=this._lexer.token,n=this.parseName();return this.expectToken(p.COLON),{kind:c.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}}parseDirectives(e){const t=[];for(;this.peek(p.AT);)t.push(this.parseDirective(e));return t}parseDirective(e){const t=this._lexer.token;return this.expectToken(p.AT),{kind:c.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}}parseTypeReference(){const e=this._lexer.token;let t;return this.expectOptionalToken(p.BRACKET_L)?(t=this.parseTypeReference(),this.expectToken(p.BRACKET_R),t={kind:c.LIST_TYPE,type:t,loc:this.loc(e)}):t=this.parseNamedType(),this.expectOptionalToken(p.BANG)?{kind:c.NON_NULL_TYPE,type:t,loc:this.loc(e)}:t}parseNamedType(){const e=this._lexer.token;return{kind:c.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}}parseTypeSystemDefinition(){const e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===p.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)}peekDescription(){return this.peek(p.STRING)||this.peek(p.BLOCK_STRING)}parseDescription(){if(this.peekDescription())return this.parseStringLiteral()}parseSchemaDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");const n=this.parseDirectives(!0),r=this.many(p.BRACE_L,this.parseOperationTypeDefinition,p.BRACE_R);return{kind:c.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}}parseOperationTypeDefinition(){const e=this._lexer.token,t=this.parseOperationType();this.expectToken(p.COLON);const n=this.parseNamedType();return{kind:c.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}}parseScalarTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");const n=this.parseName(),r=this.parseDirectives(!0);return{kind:c.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}}parseObjectTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");const n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),o=this.parseFieldsDefinition();return{kind:c.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:o,loc:this.loc(e)}}parseImplementsInterfaces(){return this.expectOptionalKeyword("implements")?this.delimitedMany(p.AMP,this.parseNamedType):[]}parseFieldsDefinition(){return this.optionalMany(p.BRACE_L,this.parseFieldDefinition,p.BRACE_R)}parseFieldDefinition(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(p.COLON);const i=this.parseTypeReference(),o=this.parseDirectives(!0);return{kind:c.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:o,loc:this.loc(e)}}parseArgumentDefs(){return this.optionalMany(p.PAREN_L,this.parseInputValueDef,p.PAREN_R)}parseInputValueDef(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName();this.expectToken(p.COLON);const r=this.parseTypeReference();let i;this.expectOptionalToken(p.EQUALS)&&(i=this.parseValueLiteral(!0));const o=this.parseDirectives(!0);return{kind:c.INPUT_VALUE_DEFINITION,description:t,name:n,type:r,defaultValue:i,directives:o,loc:this.loc(e)}}parseInterfaceTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");const n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),o=this.parseFieldsDefinition();return{kind:c.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:o,loc:this.loc(e)}}parseUnionTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");const n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:c.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}}parseUnionMemberTypes(){return this.expectOptionalToken(p.EQUALS)?this.delimitedMany(p.PIPE,this.parseNamedType):[]}parseEnumTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");const n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:c.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}}parseEnumValuesDefinition(){return this.optionalMany(p.BRACE_L,this.parseEnumValueDefinition,p.BRACE_R)}parseEnumValueDefinition(){const e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:c.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}}parseInputObjectTypeDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");const n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:c.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}}parseInputFieldsDefinition(){return this.optionalMany(p.BRACE_L,this.parseInputValueDef,p.BRACE_R)}parseTypeSystemExtension(){const e=this._lexer.lookahead();if(e.kind===p.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)}parseSchemaExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");const t=this.parseDirectives(!0),n=this.optionalMany(p.BRACE_L,this.parseOperationTypeDefinition,p.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:c.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}}parseScalarTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");const t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:c.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}}parseObjectTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");const t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:c.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}}parseInterfaceTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");const t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:c.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}}parseUnionTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");const t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:c.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}}parseEnumTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");const t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:c.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}}parseInputObjectTypeExtension(){const e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");const t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:c.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}}parseDirectiveDefinition(){const e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(p.AT);const n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");const o=this.parseDirectiveLocations();return{kind:c.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:o,loc:this.loc(e)}}parseDirectiveLocations(){return this.delimitedMany(p.PIPE,this.parseDirectiveLocation)}parseDirectiveLocation(){const e=this._lexer.token,t=this.parseName();if(void 0!==m[t.value])return t;throw this.unexpected(e)}loc(e){if(!0!==this._options?.noLocation)return new Location(e,this._lexer.lastToken,this._lexer.source)}peek(e){return this._lexer.token.kind===e}expectToken(e){const t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw a(this._lexer.source,t.start,`Expected ${k(e)}, found ${w(t)}.`)}expectOptionalToken(e){const t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t}expectKeyword(e){const t=this._lexer.token;if(t.kind!==p.NAME||t.value!==e)throw a(this._lexer.source,t.start,`Expected "${e}", found ${w(t)}.`);this._lexer.advance()}expectOptionalKeyword(e){const t=this._lexer.token;return t.kind===p.NAME&&t.value===e&&(this._lexer.advance(),!0)}unexpected(e){const t=e??this._lexer.token;return a(this._lexer.source,t.start,`Unexpected ${w(t)}.`)}any(e,t,n){this.expectToken(e);const r=[];for(;!this.expectOptionalToken(n);)r.push(t.call(this));return r}optionalMany(e,t,n){if(this.expectOptionalToken(e)){const e=[];do{e.push(t.call(this))}while(!this.expectOptionalToken(n));return e}return[]}many(e,t,n){this.expectToken(e);const r=[];do{r.push(t.call(this))}while(!this.expectOptionalToken(n));return r}delimitedMany(e,t){this.expectOptionalToken(e);const n=[];do{n.push(t.call(this))}while(this.expectOptionalToken(e));return n}}function w(e){const t=e.value;return k(e.kind)+(null!=t?` "${t}"`:"")}function k(e){return function(e){return e===p.BANG||e===p.DOLLAR||e===p.AMP||e===p.PAREN_L||e===p.PAREN_R||e===p.SPREAD||e===p.COLON||e===p.EQUALS||e===p.AT||e===p.BRACKET_L||e===p.BRACKET_R||e===p.BRACE_L||e===p.PIPE||e===p.BRACE_R}(e)?`"${e}"`:e}const x={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},F=Object.freeze({});function R(e,t,n=x){let r,i,o,s,a=Array.isArray(e),c=[e],p=-1,d=[];const f=[],h=[];let m=e;do{p++;const e=p===c.length,y=e&&0!==d.length;if(e){if(o=0===h.length?void 0:f[f.length-1],i=s,s=h.pop(),y){if(a)i=i.slice();else{const e={};for(const t of Object.keys(i))e[t]=i[t];i=e}let e=0;for(let t=0;tObject.keys(e).map((t=>e[t])));const Q=/^[_a-zA-Z][_a-zA-Z0-9]*$/;const V=Object.entries||(e=>Object.keys(e).map((t=>[t,e[t]])));function U(e,t){return e.reduce(((e,n)=>(e[t(n)]=n,e)),Object.create(null))}function j(e,t){const n=Object.create(null);for(const[r,i]of V(e))n[r]=t(i,r);return n}function M(e){if(null===Object.getPrototypeOf(e))return e;const t=Object.create(null);for(const[n,r]of V(e))t[n]=r;return t}function P(e,t,n){return e.reduce(((e,r)=>(e[t(r)]=n(r),e)),Object.create(null))}function B(e,t){const[n,r]="string"==typeof e?[e,t]:[void 0,e];let i=" Did you mean ";n&&(i+=n+" ");const o=r.map((e=>`"${e}"`));switch(o.length){case 0:return"";case 1:return i+o[0]+"?";case 2:return i+o[0]+" or "+o[1]+"?"}const s=o.slice(0,5),a=s.pop();return i+s.join(", ")+", or "+a+"?"}function Y(e){return e}function J(e,t){const n=Object.create(null),r=new LexicalDistance(e),i=Math.floor(.4*e.length)+1;for(const e of t){const t=r.measure(e,i);void 0!==t&&(n[e]=t)}return Object.keys(n).sort(((e,t)=>{const r=n[e]-n[t];return 0!==r?r:e.localeCompare(t)}))}class LexicalDistance{constructor(e){this._input=e,this._inputLowerCase=e.toLowerCase(),this._inputArray=q(this._inputLowerCase),this._rows=[new Array(e.length+1).fill(0),new Array(e.length+1).fill(0),new Array(e.length+1).fill(0)]}measure(e,t){if(this._input===e)return 0;const n=e.toLowerCase();if(this._inputLowerCase===n)return 1;let r=q(n),i=this._inputArray;if(r.lengtht)return;const a=this._rows;for(let e=0;e<=s;e++)a[0][e]=e;for(let e=1;e<=o;e++){const n=a[(e-1)%3],o=a[e%3];let c=o[0]=e;for(let t=1;t<=s;t++){const s=r[e-1]===i[t-1]?0:1;let u=Math.min(n[t]+1,o[t-1]+1,n[t-1]+s);if(e>1&&t>1&&r[e-1]===i[t-2]&&r[e-2]===i[t-1]){const n=a[(e-2)%3][t-2];u=Math.min(u,n+1)}ut)return}const c=a[o%3][s];return c<=t?c:void 0}}function q(e){const t=e.length,n=new Array(t);for(let r=0;re.value,Variable:e=>"$"+e.name,Document:e=>H(e.definitions,"\n\n")+"\n",OperationDefinition(e){const t=e.operation,n=e.name,r=W("(",H(e.variableDefinitions,", "),")"),i=H(e.directives," "),o=e.selectionSet;return n||i||r||"query"!==t?H([t,H([n,r]),i,o]," "):o},VariableDefinition:({variable:e,type:t,defaultValue:n,directives:r})=>e+": "+t+W(" = ",n)+W(" ",H(r," ")),SelectionSet:({selections:e})=>Z(e),Field:({alias:e,name:t,arguments:n,directives:r,selectionSet:i})=>{const o=W("",e,": ")+t;let s=o+W("(",H(n,", "),")");return s.length>80&&(s=o+W("(\n",ee(H(n,"\n")),"\n)")),H([s,H(r," "),i]," ")},Argument:({name:e,value:t})=>e+": "+t,FragmentSpread:({name:e,directives:t})=>"..."+e+W(" ",H(t," ")),InlineFragment:({typeCondition:e,directives:t,selectionSet:n})=>H(["...",W("on ",e),H(t," "),n]," "),FragmentDefinition:({name:e,typeCondition:t,variableDefinitions:n,directives:r,selectionSet:i})=>`fragment ${e}${W("(",H(n,", "),")")} on ${t} ${W("",H(r," ")," ")}`+i,IntValue:({value:e})=>e,FloatValue:({value:e})=>e,StringValue:({value:e,block:t},n)=>t?T(e,"description"===n?"":" "):JSON.stringify(e),BooleanValue:({value:e})=>e?"true":"false",NullValue:()=>"null",EnumValue:({value:e})=>e,ListValue:({values:e})=>"["+H(e,", ")+"]",ObjectValue:({fields:e})=>"{"+H(e,", ")+"}",ObjectField:({name:e,value:t})=>e+": "+t,Directive:({name:e,arguments:t})=>"@"+e+W("(",H(t,", "),")"),NamedType:({name:e})=>e,ListType:({type:e})=>"["+e+"]",NonNullType:({type:e})=>e+"!",SchemaDefinition:z((({directives:e,operationTypes:t})=>H(["schema",H(e," "),Z(t)]," "))),OperationTypeDefinition:({operation:e,type:t})=>e+": "+t,ScalarTypeDefinition:z((({name:e,directives:t})=>H(["scalar",e,H(t," ")]," "))),ObjectTypeDefinition:z((({name:e,interfaces:t,directives:n,fields:r})=>H(["type",e,W("implements ",H(t," & ")),H(n," "),Z(r)]," "))),FieldDefinition:z((({name:e,arguments:t,type:n,directives:r})=>e+(ne(t)?W("(\n",ee(H(t,"\n")),"\n)"):W("(",H(t,", "),")"))+": "+n+W(" ",H(r," ")))),InputValueDefinition:z((({name:e,type:t,defaultValue:n,directives:r})=>H([e+": "+t,W("= ",n),H(r," ")]," "))),InterfaceTypeDefinition:z((({name:e,interfaces:t,directives:n,fields:r})=>H(["interface",e,W("implements ",H(t," & ")),H(n," "),Z(r)]," "))),UnionTypeDefinition:z((({name:e,directives:t,types:n})=>H(["union",e,H(t," "),n&&0!==n.length?"= "+H(n," | "):""]," "))),EnumTypeDefinition:z((({name:e,directives:t,values:n})=>H(["enum",e,H(t," "),Z(n)]," "))),EnumValueDefinition:z((({name:e,directives:t})=>H([e,H(t," ")]," "))),InputObjectTypeDefinition:z((({name:e,directives:t,fields:n})=>H(["input",e,H(t," "),Z(n)]," "))),DirectiveDefinition:z((({name:e,arguments:t,repeatable:n,locations:r})=>"directive @"+e+(ne(t)?W("(\n",ee(H(t,"\n")),"\n)"):W("(",H(t,", "),")"))+(n?" repeatable":"")+" on "+H(r," | "))),SchemaExtension:({directives:e,operationTypes:t})=>H(["extend schema",H(e," "),Z(t)]," "),ScalarTypeExtension:({name:e,directives:t})=>H(["extend scalar",e,H(t," ")]," "),ObjectTypeExtension:({name:e,interfaces:t,directives:n,fields:r})=>H(["extend type",e,W("implements ",H(t," & ")),H(n," "),Z(r)]," "),InterfaceTypeExtension:({name:e,interfaces:t,directives:n,fields:r})=>H(["extend interface",e,W("implements ",H(t," & ")),H(n," "),Z(r)]," "),UnionTypeExtension:({name:e,directives:t,types:n})=>H(["extend union",e,H(t," "),n&&0!==n.length?"= "+H(n," | "):""]," "),EnumTypeExtension:({name:e,directives:t,values:n})=>H(["extend enum",e,H(t," "),Z(n)]," "),InputObjectTypeExtension:({name:e,directives:t,fields:n})=>H(["extend input",e,H(t," "),Z(n)]," ")};function z(e){return t=>H([t.description,e(t)],"\n")}function H(e,t=""){return e?.filter((e=>e)).join(t)??""}function Z(e){return W("{\n",ee(H(e,"\n")),"\n}")}function W(e,t,n=""){return null!=t&&""!==t?e+t+n:""}function ee(e){return W(" ",e.replace(/\n/g,"\n "))}function te(e){return-1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(te)}function re(e,t){if(!Boolean(e))throw new Error(null!=t?t:"Unexpected invariant triggered.")}function ie(e,t){switch(e.kind){case c.NULL:return null;case c.INT:return parseInt(e.value,10);case c.FLOAT:return parseFloat(e.value);case c.STRING:case c.ENUM:case c.BOOLEAN:return e.value;case c.LIST:return e.values.map((e=>ie(e,t)));case c.OBJECT:return P(e.fields,(e=>e.name.value),(e=>ie(e.value,t)));case c.VARIABLE:return t?.[e.name.value]}re(0,"Unexpected value node: "+l(e))}function oe(e){return se(e)||ae(e)||ce(e)||ue(e)||pe(e)||le(e)||de(e)||fe(e)}function se(e){return h(e,GraphQLScalarType)}function ae(e){return h(e,GraphQLObjectType)}function ce(e){return h(e,GraphQLInterfaceType)}function ue(e){return h(e,GraphQLUnionType)}function pe(e){return h(e,GraphQLEnumType)}function le(e){return h(e,GraphQLInputObjectType)}function de(e){return h(e,GraphQLList)}function fe(e){return h(e,GraphQLNonNull)}function he(e){return se(e)||pe(e)||le(e)||Ne(e)&&he(e.ofType)}function me(e){return se(e)||ae(e)||ce(e)||ue(e)||pe(e)||Ne(e)&&me(e.ofType)}function ye(e){return se(e)||pe(e)}function Ee(e){return ae(e)||ce(e)||ue(e)}function Te(e){return ce(e)||ue(e)}class GraphQLList{constructor(e){oe(e)||f(0,`Expected ${l(e)} to be a GraphQL type.`),this.ofType=e}toString(){return"["+String(this.ofType)+"]"}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLList"}}class GraphQLNonNull{constructor(e){ve(e)||f(0,`Expected ${l(e)} to be a GraphQL nullable type.`),this.ofType=e}toString(){return String(this.ofType)+"!"}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLNonNull"}}function Ne(e){return de(e)||fe(e)}function ve(e){return oe(e)&&!fe(e)}function Ie(e){if(e)return fe(e)?e.ofType:e}function ge(e){return se(e)||ae(e)||ce(e)||ue(e)||pe(e)||le(e)}function _e(e){if(e){let t=e;for(;Ne(t);)t=t.ofType;return t}}function Oe(e){return"function"==typeof e?e():e}function be(e){return e&&e.length>0?e:void 0}class GraphQLScalarType{constructor(e){const t=e.parseValue??Y;this.name=e.name,this.description=e.description,this.specifiedByUrl=e.specifiedByUrl,this.serialize=e.serialize??Y,this.parseValue=t,this.parseLiteral=e.parseLiteral??((e,n)=>t(ie(e,n))),this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=be(e.extensionASTNodes),"string"==typeof e.name||f(0,"Must provide name."),null==e.specifiedByUrl||"string"==typeof e.specifiedByUrl||f(0,`${this.name} must provide "specifiedByUrl" as a string, but got: ${l(e.specifiedByUrl)}.`),null==e.serialize||"function"==typeof e.serialize||f(0,`${this.name} must provide "serialize" function. If this custom Scalar is also used as an input type, ensure "parseValue" and "parseLiteral" functions are also provided.`),e.parseLiteral&&("function"==typeof e.parseValue&&"function"==typeof e.parseLiteral||f(0,`${this.name} must provide both "parseValue" and "parseLiteral" functions.`))}toConfig(){return{name:this.name,description:this.description,specifiedByUrl:this.specifiedByUrl,serialize:this.serialize,parseValue:this.parseValue,parseLiteral:this.parseLiteral,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes??[]}}toString(){return this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLScalarType"}}class GraphQLObjectType{constructor(e){this.name=e.name,this.description=e.description,this.isTypeOf=e.isTypeOf,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=be(e.extensionASTNodes),this._fields=Se.bind(void 0,e),this._interfaces=Le.bind(void 0,e),"string"==typeof e.name||f(0,"Must provide name."),null==e.isTypeOf||"function"==typeof e.isTypeOf||f(0,`${this.name} must provide "isTypeOf" as a function, but got: ${l(e.isTypeOf)}.`)}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:De(this.getFields()),isTypeOf:this.isTypeOf,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes||[]}}toString(){return this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLObjectType"}}function Le(e){const t=Oe(e.interfaces)??[];return Array.isArray(t)||f(0,`${e.name} interfaces must be an Array or a function which returns an Array.`),t}function Se(e){const t=Oe(e.fields);return Ae(t)||f(0,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),j(t,((t,n)=>{Ae(t)||f(0,`${e.name}.${n} field config must be an object.`),null==t.resolve||"function"==typeof t.resolve||f(0,`${e.name}.${n} field resolver must be a function if provided, but got: ${l(t.resolve)}.`);const r=t.args??{};Ae(r)||f(0,`${e.name}.${n} args must be an object with argument names as keys.`);const i=V(r).map((([e,t])=>({name:e,description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:t.extensions&&M(t.extensions),astNode:t.astNode})));return{name:n,description:t.description,type:t.type,args:i,resolve:t.resolve,subscribe:t.subscribe,deprecationReason:t.deprecationReason,extensions:t.extensions&&M(t.extensions),astNode:t.astNode}}))}function Ae(e){return t(e)&&!Array.isArray(e)}function De(e){return j(e,(e=>({description:e.description,type:e.type,args:we(e.args),resolve:e.resolve,subscribe:e.subscribe,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function we(e){return P(e,(e=>e.name),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})))}function ke(e){return fe(e.type)&&void 0===e.defaultValue}class GraphQLInterfaceType{constructor(e){this.name=e.name,this.description=e.description,this.resolveType=e.resolveType,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=be(e.extensionASTNodes),this._fields=Se.bind(void 0,e),this._interfaces=Le.bind(void 0,e),"string"==typeof e.name||f(0,"Must provide name."),null==e.resolveType||"function"==typeof e.resolveType||f(0,`${this.name} must provide "resolveType" as a function, but got: ${l(e.resolveType)}.`)}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}getInterfaces(){return"function"==typeof this._interfaces&&(this._interfaces=this._interfaces()),this._interfaces}toConfig(){return{name:this.name,description:this.description,interfaces:this.getInterfaces(),fields:De(this.getFields()),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes??[]}}toString(){return this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLInterfaceType"}}class GraphQLUnionType{constructor(e){this.name=e.name,this.description=e.description,this.resolveType=e.resolveType,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=be(e.extensionASTNodes),this._types=xe.bind(void 0,e),"string"==typeof e.name||f(0,"Must provide name."),null==e.resolveType||"function"==typeof e.resolveType||f(0,`${this.name} must provide "resolveType" as a function, but got: ${l(e.resolveType)}.`)}getTypes(){return"function"==typeof this._types&&(this._types=this._types()),this._types}toConfig(){return{name:this.name,description:this.description,types:this.getTypes(),resolveType:this.resolveType,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes??[]}}toString(){return this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLUnionType"}}function xe(e){const t=Oe(e.types);return Array.isArray(t)||f(0,`Must provide Array of types or a function which returns such an array for Union ${e.name}.`),t}class GraphQLEnumType{constructor(e){var t,n;this.name=e.name,this.description=e.description,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=be(e.extensionASTNodes),this._values=(t=this.name,Ae(n=e.values)||f(0,`${t} values must be an object with value names as keys.`),V(n).map((([e,n])=>(Ae(n)||f(0,`${t}.${e} must refer to an object with a "value" key representing an internal value but got: ${l(n)}.`),{name:e,description:n.description,value:void 0!==n.value?n.value:e,deprecationReason:n.deprecationReason,extensions:n.extensions&&M(n.extensions),astNode:n.astNode})))),this._valueLookup=new Map(this._values.map((e=>[e.value,e]))),this._nameLookup=U(this._values,(e=>e.name)),"string"==typeof e.name||f(0,"Must provide name.")}getValues(){return this._values}getValue(e){return this._nameLookup[e]}serialize(e){const t=this._valueLookup.get(e);if(void 0===t)throw new GraphQLError(`Enum "${this.name}" cannot represent value: ${l(e)}`);return t.name}parseValue(e){if("string"!=typeof e){const t=l(e);throw new GraphQLError(`Enum "${this.name}" cannot represent non-string value: ${t}.`+Fe(this,t))}const t=this.getValue(e);if(null==t)throw new GraphQLError(`Value "${e}" does not exist in "${this.name}" enum.`+Fe(this,e));return t.value}parseLiteral(e,t){if(e.kind!==c.ENUM){const t=K(e);throw new GraphQLError(`Enum "${this.name}" cannot represent non-enum value: ${t}.`+Fe(this,t),e)}const n=this.getValue(e.value);if(null==n){const t=K(e);throw new GraphQLError(`Value "${t}" does not exist in "${this.name}" enum.`+Fe(this,t),e)}return n.value}toConfig(){const e=P(this.getValues(),(e=>e.name),(e=>({description:e.description,value:e.value,deprecationReason:e.deprecationReason,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,values:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes??[]}}toString(){return this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLEnumType"}}function Fe(e,t){return B("the enum value",J(t,e.getValues().map((e=>e.name))))}class GraphQLInputObjectType{constructor(e){this.name=e.name,this.description=e.description,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=be(e.extensionASTNodes),this._fields=Re.bind(void 0,e),"string"==typeof e.name||f(0,"Must provide name.")}getFields(){return"function"==typeof this._fields&&(this._fields=this._fields()),this._fields}toConfig(){const e=j(this.getFields(),(e=>({description:e.description,type:e.type,defaultValue:e.defaultValue,extensions:e.extensions,astNode:e.astNode})));return{name:this.name,description:this.description,fields:e,extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes??[]}}toString(){return this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLInputObjectType"}}function Re(e){const t=Oe(e.fields);return Ae(t)||f(0,`${e.name} fields must be an object with field names as keys or a function which returns such an object.`),j(t,((t,n)=>(!("resolve"in t)||f(0,`${e.name}.${n} field has a resolve property, but Input Types cannot define resolvers.`),{name:n,description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:t.extensions&&M(t.extensions),astNode:t.astNode})))}function Ge(e){return fe(e.type)&&void 0===e.defaultValue}function $e(e,t){return e===t||(fe(e)&&fe(t)||!(!de(e)||!de(t)))&&$e(e.ofType,t.ofType)}function Ce(e,t,n){return t===n||(fe(n)?!!fe(t)&&Ce(e,t.ofType,n.ofType):fe(t)?Ce(e,t.ofType,n):de(n)?!!de(t)&&Ce(e,t.ofType,n.ofType):!de(t)&&(Te(n)&&(ce(t)||ae(t))&&e.isSubType(n,t)))}function Qe(e,t,n){return t===n||(Te(t)?Te(n)?e.getPossibleTypes(t).some((t=>e.isSubType(n,t))):e.isSubType(t,n):!!Te(n)&&e.isSubType(n,t))}const Ve=2147483647,Ue=-2147483648;const je=new GraphQLScalarType({name:"Int",description:"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",serialize:function(e){const t=Pe(e);if("boolean"==typeof t)return t?1:0;let n=t;if("string"==typeof t&&""!==t&&(n=Number(t)),"number"!=typeof n||!Number.isInteger(n))throw new GraphQLError(`Int cannot represent non-integer value: ${l(t)}`);if(n>Ve||nVe||eVe||te.name===t))}function Xe(e,n){if(fe(n)){const t=Xe(e,n.ofType);return t?.kind===c.NULL?null:t}if(null===e)return{kind:c.NULL};if(void 0===e)return null;if(de(n)){const t=n.ofType;if(function(e){if(null==e||"object"!=typeof e)return!1;const t=e.length;return"number"==typeof t&&t>=0&&t%1==0||"function"==typeof e[Symbol.iterator]}(e)){const n=[];for(const r of Array.from(e)){const e=Xe(r,t);null!=e&&n.push(e)}return{kind:c.LIST,values:n}}return Xe(e,t)}if(le(n)){if(!t(e))return null;const r=[];for(const t of C(n.getFields())){const n=Xe(e[t.name],t.type);n&&r.push({kind:c.OBJECT_FIELD,name:{kind:c.NAME,value:t.name},value:n})}return{kind:c.OBJECT,fields:r}}if(ye(n)){const t=n.serialize(e);if(null==t)return null;if("boolean"==typeof t)return{kind:c.BOOLEAN,value:t};if("number"==typeof t&&Number.isFinite(t)){const e=String(t);return ze.test(e)?{kind:c.INT,value:e}:{kind:c.FLOAT,value:e}}if("string"==typeof t)return pe(n)?{kind:c.ENUM,value:t}:n===Je&&ze.test(t)?{kind:c.INT,value:t}:{kind:c.STRING,value:t};throw new TypeError(`Cannot convert value to AST: ${l(t)}.`)}re(0,"Unexpected input type: "+l(n))}const ze=/^-?(?:0|[1-9][0-9]*)$/,He=new GraphQLObjectType({name:"__Schema",description:"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",fields:()=>({description:{type:Be,resolve:e=>e.description},types:{description:"A list of all types supported by this server.",type:new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(et))),resolve:e=>C(e.getTypeMap())},queryType:{description:"The type that query operations will be rooted at.",type:new GraphQLNonNull(et),resolve:e=>e.getQueryType()},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:et,resolve:e=>e.getMutationType()},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:et,resolve:e=>e.getSubscriptionType()},directives:{description:"A list of all directives supported by this server.",type:new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Ze))),resolve:e=>e.getDirectives()}})}),Ze=new GraphQLObjectType({name:"__Directive",description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:()=>({name:{type:new GraphQLNonNull(Be),resolve:e=>e.name},description:{type:Be,resolve:e=>e.description},isRepeatable:{type:new GraphQLNonNull(Ye),resolve:e=>e.isRepeatable},locations:{type:new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(We))),resolve:e=>e.locations},args:{type:new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(nt))),resolve:e=>e.args}})}),We=new GraphQLEnumType({name:"__DirectiveLocation",description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:m.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:m.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:m.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:m.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:m.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:m.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:m.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},VARIABLE_DEFINITION:{value:m.VARIABLE_DEFINITION,description:"Location adjacent to a variable definition."},SCHEMA:{value:m.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:m.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:m.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:m.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:m.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:m.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:m.UNION,description:"Location adjacent to a union definition."},ENUM:{value:m.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:m.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:m.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:m.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),et=new GraphQLObjectType({name:"__Type",description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByUrl`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:()=>({kind:{type:new GraphQLNonNull(ot),resolve:e=>se(e)?it.SCALAR:ae(e)?it.OBJECT:ce(e)?it.INTERFACE:ue(e)?it.UNION:pe(e)?it.ENUM:le(e)?it.INPUT_OBJECT:de(e)?it.LIST:fe(e)?it.NON_NULL:void re(0,`Unexpected type: "${l(e)}".`)},name:{type:Be,resolve:e=>void 0!==e.name?e.name:void 0},description:{type:Be,resolve:e=>void 0!==e.description?e.description:void 0},specifiedByUrl:{type:Be,resolve:e=>void 0!==e.specifiedByUrl?e.specifiedByUrl:void 0},fields:{type:new GraphQLList(new GraphQLNonNull(tt)),args:{includeDeprecated:{type:Ye,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if(ae(e)||ce(e)){const n=C(e.getFields());return t?n:n.filter((e=>null==e.deprecationReason))}}},interfaces:{type:new GraphQLList(new GraphQLNonNull(et)),resolve(e){if(ae(e)||ce(e))return e.getInterfaces()}},possibleTypes:{type:new GraphQLList(new GraphQLNonNull(et)),resolve(e,t,n,{schema:r}){if(Te(e))return r.getPossibleTypes(e)}},enumValues:{type:new GraphQLList(new GraphQLNonNull(rt)),args:{includeDeprecated:{type:Ye,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if(pe(e)){const n=e.getValues();return t?n:n.filter((e=>null==e.deprecationReason))}}},inputFields:{type:new GraphQLList(new GraphQLNonNull(nt)),args:{includeDeprecated:{type:Ye,defaultValue:!1}},resolve(e,{includeDeprecated:t}){if(le(e)){const n=C(e.getFields());return t?n:n.filter((e=>null==e.deprecationReason))}}},ofType:{type:et,resolve:e=>void 0!==e.ofType?e.ofType:void 0}})}),tt=new GraphQLObjectType({name:"__Field",description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:()=>({name:{type:new GraphQLNonNull(Be),resolve:e=>e.name},description:{type:Be,resolve:e=>e.description},args:{type:new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(nt))),args:{includeDeprecated:{type:Ye,defaultValue:!1}},resolve:(e,{includeDeprecated:t})=>t?e.args:e.args.filter((e=>null==e.deprecationReason))},type:{type:new GraphQLNonNull(et),resolve:e=>e.type},isDeprecated:{type:new GraphQLNonNull(Ye),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:Be,resolve:e=>e.deprecationReason}})}),nt=new GraphQLObjectType({name:"__InputValue",description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:()=>({name:{type:new GraphQLNonNull(Be),resolve:e=>e.name},description:{type:Be,resolve:e=>e.description},type:{type:new GraphQLNonNull(et),resolve:e=>e.type},defaultValue:{type:Be,description:"A GraphQL-formatted string representing the default value for this input value.",resolve(e){const{type:t,defaultValue:n}=e,r=Xe(n,t);return r?K(r):null}},isDeprecated:{type:new GraphQLNonNull(Ye),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:Be,resolve:e=>e.deprecationReason}})}),rt=new GraphQLObjectType({name:"__EnumValue",description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:()=>({name:{type:new GraphQLNonNull(Be),resolve:e=>e.name},description:{type:Be,resolve:e=>e.description},isDeprecated:{type:new GraphQLNonNull(Ye),resolve:e=>null!=e.deprecationReason},deprecationReason:{type:Be,resolve:e=>e.deprecationReason}})}),it=Object.freeze({SCALAR:"SCALAR",OBJECT:"OBJECT",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",INPUT_OBJECT:"INPUT_OBJECT",LIST:"LIST",NON_NULL:"NON_NULL"}),ot=new GraphQLEnumType({name:"__TypeKind",description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:it.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:it.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:it.INTERFACE,description:"Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields."},UNION:{value:it.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:it.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:it.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:it.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:it.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}}),st={name:"__schema",type:new GraphQLNonNull(He),description:"Access the current type schema of this server.",args:[],resolve:(e,t,n,{schema:r})=>r,deprecationReason:void 0,extensions:void 0,astNode:void 0},at={name:"__type",type:et,description:"Request the type information of a single type.",args:[{name:"name",description:void 0,type:new GraphQLNonNull(Be),defaultValue:void 0,deprecationReason:void 0,extensions:void 0,astNode:void 0}],resolve:(e,{name:t},n,{schema:r})=>r.getType(t),deprecationReason:void 0,extensions:void 0,astNode:void 0},ct={name:"__typename",type:new GraphQLNonNull(Be),description:"The name of the current Object type at runtime.",args:[],resolve:(e,t,n,{parentType:r})=>r.name,deprecationReason:void 0,extensions:void 0,astNode:void 0},ut=Object.freeze([He,Ze,We,et,tt,nt,rt,ot]);function pt(e){return ut.some((({name:t})=>e.name===t))}function lt(e){return h(e,GraphQLDirective)}class GraphQLDirective{constructor(e){this.name=e.name,this.description=e.description,this.locations=e.locations,this.isRepeatable=e.isRepeatable??!1,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,e.name||f(0,"Directive must be named."),Array.isArray(e.locations)||f(0,`@${e.name} locations must be an Array.`);const n=e.args??{};t(n)&&!Array.isArray(n)||f(0,`@${e.name} args must be an object with argument names as keys.`),this.args=V(n).map((([e,t])=>({name:e,description:t.description,type:t.type,defaultValue:t.defaultValue,deprecationReason:t.deprecationReason,extensions:t.extensions&&M(t.extensions),astNode:t.astNode})))}toConfig(){return{name:this.name,description:this.description,locations:this.locations,args:we(this.args),isRepeatable:this.isRepeatable,extensions:this.extensions,astNode:this.astNode}}toString(){return"@"+this.name}toJSON(){return this.toString()}get[Symbol.toStringTag](){return"GraphQLDirective"}}const dt=new GraphQLDirective({name:"include",description:"Directs the executor to include this field or fragment only when the `if` argument is true.",locations:[m.FIELD,m.FRAGMENT_SPREAD,m.INLINE_FRAGMENT],args:{if:{type:new GraphQLNonNull(Ye),description:"Included when true."}}}),ft=new GraphQLDirective({name:"skip",description:"Directs the executor to skip this field or fragment when the `if` argument is true.",locations:[m.FIELD,m.FRAGMENT_SPREAD,m.INLINE_FRAGMENT],args:{if:{type:new GraphQLNonNull(Ye),description:"Skipped when true."}}}),ht="No longer supported",mt=new GraphQLDirective({name:"deprecated",description:"Marks an element of a GraphQL schema as no longer supported.",locations:[m.FIELD_DEFINITION,m.ARGUMENT_DEFINITION,m.INPUT_FIELD_DEFINITION,m.ENUM_VALUE],args:{reason:{type:Be,description:"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).",defaultValue:ht}}}),yt=new GraphQLDirective({name:"specifiedBy",description:"Exposes a URL that specifies the behaviour of this scalar.",locations:[m.SCALAR],args:{url:{type:new GraphQLNonNull(Be),description:"The URL that specifies the behaviour of this scalar."}}}),Et=Object.freeze([dt,ft,mt,yt]);function Tt(e){if(!function(e){return h(e,GraphQLSchema)}(e))throw new Error(`Expected ${l(e)} to be a GraphQL schema.`);return e}class GraphQLSchema{constructor(e){this.__validationErrors=!0===e.assumeValid?[]:void 0,t(e)||f(0,"Must provide configuration object."),!e.types||Array.isArray(e.types)||f(0,`"types" must be Array if provided but got: ${l(e.types)}.`),!e.directives||Array.isArray(e.directives)||f(0,`"directives" must be Array if provided but got: ${l(e.directives)}.`),this.description=e.description,this.extensions=e.extensions&&M(e.extensions),this.astNode=e.astNode,this.extensionASTNodes=e.extensionASTNodes,this._queryType=e.query,this._mutationType=e.mutation,this._subscriptionType=e.subscription,this._directives=e.directives??Et;const n=new Set(e.types);if(null!=e.types)for(const t of e.types)n.delete(t),Nt(t,n);null!=this._queryType&&Nt(this._queryType,n),null!=this._mutationType&&Nt(this._mutationType,n),null!=this._subscriptionType&&Nt(this._subscriptionType,n);for(const e of this._directives)if(lt(e))for(const t of e.args)Nt(t.type,n);Nt(He,n),this._typeMap=Object.create(null),this._subTypeMap=Object.create(null),this._implementationsMap=Object.create(null);for(const e of Array.from(n)){if(null==e)continue;const t=e.name;if(t||f(0,"One of the provided types for building the Schema is missing a name."),void 0!==this._typeMap[t])throw new Error(`Schema must contain uniquely named types but contains multiple types named "${t}".`);if(this._typeMap[t]=e,ce(e)){for(const t of e.getInterfaces())if(ce(t)){let n=this._implementationsMap[t.name];void 0===n&&(n=this._implementationsMap[t.name]={objects:[],interfaces:[]}),n.interfaces.push(e)}}else if(ae(e))for(const t of e.getInterfaces())if(ce(t)){let n=this._implementationsMap[t.name];void 0===n&&(n=this._implementationsMap[t.name]={objects:[],interfaces:[]}),n.objects.push(e)}}}getQueryType(){return this._queryType}getMutationType(){return this._mutationType}getSubscriptionType(){return this._subscriptionType}getTypeMap(){return this._typeMap}getType(e){return this.getTypeMap()[e]}getPossibleTypes(e){return ue(e)?e.getTypes():this.getImplementations(e).objects}getImplementations(e){return this._implementationsMap[e.name]??{objects:[],interfaces:[]}}isSubType(e,t){let n=this._subTypeMap[e.name];if(void 0===n){if(n=Object.create(null),ue(e))for(const t of e.getTypes())n[t.name]=!0;else{const t=this.getImplementations(e);for(const e of t.objects)n[e.name]=!0;for(const e of t.interfaces)n[e.name]=!0}this._subTypeMap[e.name]=n}return void 0!==n[t.name]}getDirectives(){return this._directives}getDirective(e){return this.getDirectives().find((t=>t.name===e))}toConfig(){return{description:this.description,query:this.getQueryType(),mutation:this.getMutationType(),subscription:this.getSubscriptionType(),types:C(this.getTypeMap()),directives:this.getDirectives().slice(),extensions:this.extensions,astNode:this.astNode,extensionASTNodes:this.extensionASTNodes??[],assumeValid:void 0!==this.__validationErrors}}get[Symbol.toStringTag](){return"GraphQLSchema"}}function Nt(e,t){const n=_e(e);if(!t.has(n))if(t.add(n),ue(n))for(const e of n.getTypes())Nt(e,t);else if(ae(n)||ce(n)){for(const e of n.getInterfaces())Nt(e,t);for(const e of C(n.getFields())){Nt(e.type,t);for(const n of e.args)Nt(n.type,t)}}else if(le(n))for(const e of C(n.getFields()))Nt(e.type,t);return t}function vt(e){if(Tt(e),e.__validationErrors)return e.__validationErrors;const t=new SchemaValidationContext(e);!function(e){const t=e.schema,n=t.getQueryType();n?ae(n)||e.reportError(`Query root type must be Object type, it cannot be ${l(n)}.`,It(t,"query")??n.astNode):e.reportError("Query root type must be provided.",t.astNode);const r=t.getMutationType();r&&!ae(r)&&e.reportError(`Mutation root type must be Object type if provided, it cannot be ${l(r)}.`,It(t,"mutation")??r.astNode);const i=t.getSubscriptionType();i&&!ae(i)&&e.reportError(`Subscription root type must be Object type if provided, it cannot be ${l(i)}.`,It(t,"subscription")??i.astNode)}(t),function(e){for(const t of e.schema.getDirectives())if(lt(t)){gt(e,t);for(const n of t.args)gt(e,n),he(n.type)||e.reportError(`The type of @${t.name}(${n.name}:) must be Input Type but got: ${l(n.type)}.`,n.astNode),ke(n)&&null!=n.deprecationReason&&e.reportError(`Required argument @${t.name}(${n.name}:) cannot be deprecated.`,[Rt(n.astNode),n.astNode?.type])}else e.reportError(`Expected directive but got: ${l(t)}.`,t?.astNode)}(t),function(e){const t=function(e){const t=Object.create(null),n=[],r=Object.create(null);return i;function i(o){if(t[o.name])return;t[o.name]=!0,r[o.name]=n.length;const s=C(o.getFields());for(const t of s)if(fe(t.type)&&le(t.type.ofType)){const o=t.type.ofType,s=r[o.name];if(n.push(t),void 0===s)i(o);else{const t=n.slice(s),r=t.map((e=>e.name)).join(".");e.reportError(`Cannot reference Input Object "${o.name}" within itself through a series of non-null fields: "${r}".`,t.map((e=>e.astNode)))}n.pop()}r[o.name]=void 0}}(e),n=e.schema.getTypeMap();for(const r of C(n))ge(r)?(pt(r)||gt(e,r),ae(r)||ce(r)?(_t(e,r),Ot(e,r)):ue(r)?St(e,r):pe(r)?At(e,r):le(r)&&(Dt(e,r),t(r))):e.reportError(`Expected GraphQL named type but got: ${l(r)}.`,r.astNode)}(t);const n=t.getErrors();return e.__validationErrors=n,n}class SchemaValidationContext{constructor(e){this._errors=[],this.schema=e}reportError(e,t){const n=Array.isArray(t)?t.filter(Boolean):t;this.addError(new GraphQLError(e,n))}addError(e){this._errors.push(e)}getErrors(){return this._errors}}function It(e,t){const n=kt(e,(e=>e.operationTypes));for(const e of n)if(e.operation===t)return e.type}function gt(e,t){const n=("string"==typeof(r=t.name)||f(0,"Expected name to be a string."),r.length>1&&"_"===r[0]&&"_"===r[1]?new GraphQLError(`Name "${r}" must not begin with "__", which is reserved by GraphQL introspection.`):Q.test(r)?void 0:new GraphQLError(`Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "${r}" does not.`));var r;n&&e.addError(function(e,t,n){const r=e instanceof Error?e:new Error("Unexpected error value: "+l(e));return Array.isArray(r.path)?r:new GraphQLError(r.message,r.nodes??t,r.source,r.positions,n,r)}(n,t.astNode))}function _t(e,t){const n=C(t.getFields());0===n.length&&e.reportError(`Type ${t.name} must define one or more fields.`,wt(t));for(const r of n){gt(e,r),me(r.type)||e.reportError(`The type of ${t.name}.${r.name} must be Output Type but got: ${l(r.type)}.`,r.astNode?.type);for(const n of r.args){const i=n.name;gt(e,n),he(n.type)||e.reportError(`The type of ${t.name}.${r.name}(${i}:) must be Input Type but got: ${l(n.type)}.`,n.astNode?.type),ke(n)&&null!=n.deprecationReason&&e.reportError(`Required argument ${t.name}.${r.name}(${i}:) cannot be deprecated.`,[Rt(n.astNode),n.astNode?.type])}}}function Ot(e,t){const n=Object.create(null);for(const r of t.getInterfaces())ce(r)?t!==r?n[r.name]?e.reportError(`Type ${t.name} can only implement ${r.name} once.`,xt(t,r)):(n[r.name]=!0,Lt(e,t,r),bt(e,t,r)):e.reportError(`Type ${t.name} cannot implement itself because it would create a circular reference.`,xt(t,r)):e.reportError(`Type ${l(t)} must only implement Interface types, it cannot implement ${l(r)}.`,xt(t,r))}function bt(e,t,n){const r=t.getFields();for(const i of C(n.getFields())){const o=i.name,s=r[o];if(s){Ce(e.schema,s.type,i.type)||e.reportError(`Interface field ${n.name}.${o} expects type ${l(i.type)} but ${t.name}.${o} is type ${l(s.type)}.`,[i.astNode?.type,s.astNode?.type]);for(const r of i.args){const i=r.name,a=s.args.find((e=>e.name===i));a?$e(r.type,a.type)||e.reportError(`Interface field argument ${n.name}.${o}(${i}:) expects type ${l(r.type)} but ${t.name}.${o}(${i}:) is type ${l(a.type)}.`,[r.astNode?.type,a.astNode?.type]):e.reportError(`Interface field argument ${n.name}.${o}(${i}:) expected but ${t.name}.${o} does not provide it.`,[r.astNode,s.astNode])}for(const r of s.args){const s=r.name;!i.args.find((e=>e.name===s))&&ke(r)&&e.reportError(`Object field ${t.name}.${o} includes required argument ${s} that is missing from the Interface field ${n.name}.${o}.`,[r.astNode,i.astNode])}}else e.reportError(`Interface field ${n.name}.${o} expected but ${t.name} does not provide it.`,[i.astNode,...wt(t)])}}function Lt(e,t,n){const r=t.getInterfaces();for(const i of n.getInterfaces())-1===r.indexOf(i)&&e.reportError(i===t?`Type ${t.name} cannot implement ${n.name} because it would create a circular reference.`:`Type ${t.name} must implement ${i.name} because it is implemented by ${n.name}.`,[...xt(n,i),...xt(t,n)])}function St(e,t){const n=t.getTypes();0===n.length&&e.reportError(`Union type ${t.name} must define one or more member types.`,wt(t));const r=Object.create(null);for(const i of n)r[i.name]?e.reportError(`Union type ${t.name} can only include type ${i.name} once.`,Ft(t,i.name)):(r[i.name]=!0,ae(i)||e.reportError(`Union type ${t.name} can only include Object types, it cannot include ${l(i)}.`,Ft(t,String(i))))}function At(e,t){const n=t.getValues();0===n.length&&e.reportError(`Enum type ${t.name} must define one or more values.`,wt(t));for(const r of n){const n=r.name;gt(e,r),"true"!==n&&"false"!==n&&"null"!==n||e.reportError(`Enum type ${t.name} cannot include value: ${n}.`,r.astNode)}}function Dt(e,t){const n=C(t.getFields());0===n.length&&e.reportError(`Input Object type ${t.name} must define one or more fields.`,wt(t));for(const r of n)gt(e,r),he(r.type)||e.reportError(`The type of ${t.name}.${r.name} must be Input Type but got: ${l(r.type)}.`,r.astNode?.type),Ge(r)&&null!=r.deprecationReason&&e.reportError(`Required input field ${t.name}.${r.name} cannot be deprecated.`,[Rt(r.astNode),r.astNode?.type])}function wt(e){const{astNode:t,extensionASTNodes:n}=e;return t?n?[t].concat(n):[t]:n??[]}function kt(e,t){let n=[];for(const r of wt(e))n=n.concat(t(r)??[]);return n}function xt(e,t){return kt(e,(e=>e.interfaces)).filter((e=>e.name.value===t.name))}function Ft(e,t){return kt(e,(e=>e.types)).filter((e=>e.name.value===t))}function Rt(e){return e?.directives?.find((e=>e.name.value===mt.name))}function Gt(e,t){let n;return t.kind===c.LIST_TYPE?(n=Gt(e,t.type),n&&new GraphQLList(n)):t.kind===c.NON_NULL_TYPE?(n=Gt(e,t.type),n&&new GraphQLNonNull(n)):t.kind===c.NAMED_TYPE?e.getType(t.name.value):void re(0,"Unexpected type node: "+l(t))}class TypeInfo{constructor(e,t,n){this._schema=e,this._typeStack=[],this._parentTypeStack=[],this._inputTypeStack=[],this._fieldDefStack=[],this._defaultValueStack=[],this._directive=null,this._argument=null,this._enumValue=null,this._getFieldDef=t??$t,n&&(he(n)&&this._inputTypeStack.push(n),Ee(n)&&this._parentTypeStack.push(n),me(n)&&this._typeStack.push(n))}getType(){if(this._typeStack.length>0)return this._typeStack[this._typeStack.length-1]}getParentType(){if(this._parentTypeStack.length>0)return this._parentTypeStack[this._parentTypeStack.length-1]}getInputType(){if(this._inputTypeStack.length>0)return this._inputTypeStack[this._inputTypeStack.length-1]}getParentInputType(){if(this._inputTypeStack.length>1)return this._inputTypeStack[this._inputTypeStack.length-2]}getFieldDef(){if(this._fieldDefStack.length>0)return this._fieldDefStack[this._fieldDefStack.length-1]}getDefaultValue(){if(this._defaultValueStack.length>0)return this._defaultValueStack[this._defaultValueStack.length-1]}getDirective(){return this._directive}getArgument(){return this._argument}getEnumValue(){return this._enumValue}enter(e){const t=this._schema;switch(e.kind){case c.SELECTION_SET:{const e=_e(this.getType());this._parentTypeStack.push(Ee(e)?e:void 0);break}case c.FIELD:{const n=this.getParentType();let r,i;n&&(r=this._getFieldDef(t,n,e),r&&(i=r.type)),this._fieldDefStack.push(r),this._typeStack.push(me(i)?i:void 0);break}case c.DIRECTIVE:this._directive=t.getDirective(e.name.value);break;case c.OPERATION_DEFINITION:{let n;switch(e.operation){case"query":n=t.getQueryType();break;case"mutation":n=t.getMutationType();break;case"subscription":n=t.getSubscriptionType()}this._typeStack.push(ae(n)?n:void 0);break}case c.INLINE_FRAGMENT:case c.FRAGMENT_DEFINITION:{const n=e.typeCondition,r=n?Gt(t,n):_e(this.getType());this._typeStack.push(me(r)?r:void 0);break}case c.VARIABLE_DEFINITION:{const n=Gt(t,e.type);this._inputTypeStack.push(he(n)?n:void 0);break}case c.ARGUMENT:{let t,n;const r=this.getDirective()??this.getFieldDef();r&&(t=r.args.find((t=>t.name===e.name.value)),t&&(n=t.type)),this._argument=t,this._defaultValueStack.push(t?t.defaultValue:void 0),this._inputTypeStack.push(he(n)?n:void 0);break}case c.LIST:{const e=Ie(this.getInputType()),t=de(e)?e.ofType:e;this._defaultValueStack.push(void 0),this._inputTypeStack.push(he(t)?t:void 0);break}case c.OBJECT_FIELD:{const t=_e(this.getInputType());let n,r;le(t)&&(r=t.getFields()[e.name.value],r&&(n=r.type)),this._defaultValueStack.push(r?r.defaultValue:void 0),this._inputTypeStack.push(he(n)?n:void 0);break}case c.ENUM:{const t=_e(this.getInputType());let n;pe(t)&&(n=t.getValue(e.value)),this._enumValue=n;break}}}leave(e){switch(e.kind){case c.SELECTION_SET:this._parentTypeStack.pop();break;case c.FIELD:this._fieldDefStack.pop(),this._typeStack.pop();break;case c.DIRECTIVE:this._directive=null;break;case c.OPERATION_DEFINITION:case c.INLINE_FRAGMENT:case c.FRAGMENT_DEFINITION:this._typeStack.pop();break;case c.VARIABLE_DEFINITION:this._inputTypeStack.pop();break;case c.ARGUMENT:this._argument=null,this._defaultValueStack.pop(),this._inputTypeStack.pop();break;case c.LIST:case c.OBJECT_FIELD:this._defaultValueStack.pop(),this._inputTypeStack.pop();break;case c.ENUM:this._enumValue=null}}}function $t(e,t,n){const r=n.name.value;return r===st.name&&e.getQueryType()===t?st:r===at.name&&e.getQueryType()===t?at:r===ct.name&&Ee(t)?ct:ae(t)||ce(t)?t.getFields()[r]:void 0}function Ct(e,t){return{enter(n){e.enter(n);const r=$(t,n.kind,!1);if(r){const i=r.apply(t,arguments);return void 0!==i&&(e.leave(n),u(i)&&e.enter(i)),i}},leave(n){const r=$(t,n.kind,!0);let i;return r&&(i=r.apply(t,arguments)),e.leave(n),i}}}function Qt(e){return e.kind===c.OPERATION_DEFINITION||e.kind===c.FRAGMENT_DEFINITION}function Vt(e){return e.kind===c.SCALAR_TYPE_DEFINITION||e.kind===c.OBJECT_TYPE_DEFINITION||e.kind===c.INTERFACE_TYPE_DEFINITION||e.kind===c.UNION_TYPE_DEFINITION||e.kind===c.ENUM_TYPE_DEFINITION||e.kind===c.INPUT_OBJECT_TYPE_DEFINITION}function Ut(e){return e.kind===c.SCALAR_TYPE_EXTENSION||e.kind===c.OBJECT_TYPE_EXTENSION||e.kind===c.INTERFACE_TYPE_EXTENSION||e.kind===c.UNION_TYPE_EXTENSION||e.kind===c.ENUM_TYPE_EXTENSION||e.kind===c.INPUT_OBJECT_TYPE_EXTENSION}function jt(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),r=Object.create(null);for(const t of e.getDocument().definitions)Vt(t)&&(r[t.name.value]=!0);const i=Object.keys(n).concat(Object.keys(r));return{NamedType(t,o,s,a,u){const p=t.name.value;if(!n[p]&&!r[p]){const n=u[2]??s,r=null!=n&&(l=n,!Array.isArray(l)&&(function(e){return e.kind===c.SCHEMA_DEFINITION||Vt(e)||e.kind===c.DIRECTIVE_DEFINITION}(l)||function(e){return e.kind===c.SCHEMA_EXTENSION||Ut(e)}(l)));if(r&&function(e){return-1!==Mt.indexOf(e)}(p))return;const o=J(p,r?Mt.concat(i):i);e.reportError(new GraphQLError(`Unknown type "${p}".`+B(o),t))}var l}}}const Mt=[...qe,...ut].map((e=>e.name));function Pt(e){const t=[],n=[];return{OperationDefinition:e=>(t.push(e),!1),FragmentDefinition:e=>(n.push(e),!1),Document:{leave(){const r=Object.create(null);for(const n of t)for(const t of e.getRecursivelyReferencedFragments(n))r[t.name.value]=!0;for(const t of n){const n=t.name.value;!0!==r[n]&&e.reportError(new GraphQLError(`Fragment "${n}" is never used.`,t))}}}}}function Bt(e){const t=Object.create(null),n=e.getSchema(),r=n?n.getDirectives():Et;for(const e of r)t[e.name]=e.locations;const i=e.getDocument().definitions;for(const e of i)e.kind===c.DIRECTIVE_DEFINITION&&(t[e.name.value]=e.locations.map((e=>e.value)));return{Directive(n,r,i,o,s){const a=n.name.value,u=t[a];if(!u)return void e.reportError(new GraphQLError(`Unknown directive "@${a}".`,n));const p=function(e){const t=e[e.length-1];switch(!Array.isArray(t)||re(0),t.kind){case c.OPERATION_DEFINITION:return function(e){switch(e){case"query":return m.QUERY;case"mutation":return m.MUTATION;case"subscription":return m.SUBSCRIPTION}re(0,"Unexpected operation: "+l(e))}(t.operation);case c.FIELD:return m.FIELD;case c.FRAGMENT_SPREAD:return m.FRAGMENT_SPREAD;case c.INLINE_FRAGMENT:return m.INLINE_FRAGMENT;case c.FRAGMENT_DEFINITION:return m.FRAGMENT_DEFINITION;case c.VARIABLE_DEFINITION:return m.VARIABLE_DEFINITION;case c.SCHEMA_DEFINITION:case c.SCHEMA_EXTENSION:return m.SCHEMA;case c.SCALAR_TYPE_DEFINITION:case c.SCALAR_TYPE_EXTENSION:return m.SCALAR;case c.OBJECT_TYPE_DEFINITION:case c.OBJECT_TYPE_EXTENSION:return m.OBJECT;case c.FIELD_DEFINITION:return m.FIELD_DEFINITION;case c.INTERFACE_TYPE_DEFINITION:case c.INTERFACE_TYPE_EXTENSION:return m.INTERFACE;case c.UNION_TYPE_DEFINITION:case c.UNION_TYPE_EXTENSION:return m.UNION;case c.ENUM_TYPE_DEFINITION:case c.ENUM_TYPE_EXTENSION:return m.ENUM;case c.ENUM_VALUE_DEFINITION:return m.ENUM_VALUE;case c.INPUT_OBJECT_TYPE_DEFINITION:case c.INPUT_OBJECT_TYPE_EXTENSION:return m.INPUT_OBJECT;case c.INPUT_VALUE_DEFINITION:return e[e.length-3].kind===c.INPUT_OBJECT_TYPE_DEFINITION?m.INPUT_FIELD_DEFINITION:m.ARGUMENT_DEFINITION}}(s);p&&-1===u.indexOf(p)&&e.reportError(new GraphQLError(`Directive "@${a}" may not be used on ${p}.`,n))}}}function Yt(e){const t=Object.create(null),n=e.getSchema(),r=n?n.getDirectives():Et;for(const e of r)t[e.name]=!e.isRepeatable;const i=e.getDocument().definitions;for(const e of i)e.kind===c.DIRECTIVE_DEFINITION&&(t[e.name.value]=!e.repeatable);const o=Object.create(null),s=Object.create(null);return{enter(n){if(null==n.directives)return;let r;if(n.kind===c.SCHEMA_DEFINITION||n.kind===c.SCHEMA_EXTENSION)r=o;else if(Vt(n)||Ut(n)){const e=n.name.value;r=s[e],void 0===r&&(s[e]=r=Object.create(null))}else r=Object.create(null);for(const i of n.directives){const n=i.name.value;t[n]&&(r[n]?e.reportError(new GraphQLError(`The directive "@${n}" can only be used once at this location.`,[r[n],i])):r[n]=i)}}}}function Jt(e){const t=Object.create(null),n=e.getSchema(),r=n?n.getDirectives():Et;for(const e of r)t[e.name]=e.args.map((e=>e.name));const i=e.getDocument().definitions;for(const e of i)if(e.kind===c.DIRECTIVE_DEFINITION){const n=e.arguments??[];t[e.name.value]=n.map((e=>e.name.value))}return{Directive(n){const r=n.name.value,i=t[r];if(n.arguments&&i)for(const t of n.arguments){const n=t.name.value;if(-1===i.indexOf(n)){const o=J(n,i);e.reportError(new GraphQLError(`Unknown argument "${n}" on directive "@${r}".`+B(o),t))}}return!1}}}function qt(e){let t=Object.create(null);return{Field(){t=Object.create(null)},Directive(){t=Object.create(null)},Argument(n){const r=n.name.value;return t[r]?e.reportError(new GraphQLError(`There can be only one argument named "${r}".`,[t[r],n.name])):t[r]=n.name,!1}}}function Kt(e,t){const n=e.getInputType();if(!n)return;const r=_e(n);if(ye(r))try{if(void 0===r.parseLiteral(t,void 0)){const r=l(n);e.reportError(new GraphQLError(`Expected value of type "${r}", found ${K(t)}.`,t))}}catch(r){const i=l(n);r instanceof GraphQLError?e.reportError(r):e.reportError(new GraphQLError(`Expected value of type "${i}", found ${K(t)}; `+r.message,t,void 0,void 0,void 0,r))}else{const r=l(n);e.reportError(new GraphQLError(`Expected value of type "${r}", found ${K(t)}.`,t))}}function Xt(e){const t=Object.create(null),n=e.getSchema(),r=n?n.getDirectives():Et;for(const e of r)t[e.name]=U(e.args.filter(ke),(e=>e.name));const i=e.getDocument().definitions;for(const e of i)if(e.kind===c.DIRECTIVE_DEFINITION){const n=e.arguments??[];t[e.name.value]=U(n.filter(zt),(e=>e.name.value))}return{Directive:{leave(n){const r=n.name.value,i=t[r];if(i){const t=U(n.arguments??[],(e=>e.name.value));for(const o of Object.keys(i))if(!t[o]){const t=i[o].type,s=oe(t)?l(t):K(t);e.reportError(new GraphQLError(`Directive "@${r}" argument "${o}" of type "${s}" is required, but it was not provided.`,n))}}}}}}function zt(e){return e.type.kind===c.NON_NULL_TYPE&&null==e.defaultValue}function Ht(e,t,n,r,i){if(fe(r)&&!fe(t)){const o=void 0!==i;if(!(null!=n&&n.kind!==c.NULL)&&!o)return!1;return Ce(e,t,r.ofType)}return Ce(e,t,r)}function Zt(e){return Array.isArray(e)?e.map((([e,t])=>`subfields "${e}" conflict because `+Zt(t))).join(" and "):e}function Wt(e,t,n,r,i,o,s){const a=e.getFragment(s);if(!a)return;const[c,u]=sn(e,n,a);if(o!==c){tn(e,t,n,r,i,o,c);for(let s=0;s{const n=t.find((t=>t.name.value===e.name.value));return!!n&&(r=e.value,i=n.value,K(r)===K(i));var r,i}))}(c.arguments??[],d.arguments??[]))return[[i,"they have differing arguments"],[c],[d]]}const m=u?.type,y=f?.type;if(m&&y&&rn(m,y))return[[i,`they return conflicting types "${l(m)}" and "${l(y)}"`],[c],[d]];const E=c.selectionSet,T=d.selectionSet;if(E&&T){return function(e,t,n,r){if(e.length>0)return[[t,e.map((([e])=>e))],e.reduce(((e,[,t])=>e.concat(t)),[n]),e.reduce(((e,[,,t])=>e.concat(t)),[r])]}(function(e,t,n,r,i,o,s,a){const c=[],[u,p]=on(e,t,i,o),[l,d]=on(e,t,s,a);if(tn(e,c,t,n,r,u,l),0!==d.length)for(let i=0;i!1}},function(e){let t=0;return{Document(e){t=e.definitions.filter((e=>e.kind===c.OPERATION_DEFINITION)).length},OperationDefinition(n){!n.name&&t>1&&e.reportError(new GraphQLError("This anonymous operation must be the only defined operation.",n))}}},function(e){return{OperationDefinition(t){"subscription"===t.operation&&1!==t.selectionSet.selections.length&&e.reportError(new GraphQLError(t.name?`Subscription "${t.name.value}" must select only one top level field.`:"Anonymous Subscription must select only one top level field.",t.selectionSet.selections.slice(1)))}}},jt,function(e){return{InlineFragment(t){const n=t.typeCondition;if(n){const t=Gt(e.getSchema(),n);if(t&&!Ee(t)){const t=K(n);e.reportError(new GraphQLError(`Fragment cannot condition on non composite type "${t}".`,n))}}},FragmentDefinition(t){const n=Gt(e.getSchema(),t.typeCondition);if(n&&!Ee(n)){const n=K(t.typeCondition);e.reportError(new GraphQLError(`Fragment "${t.name.value}" cannot condition on non composite type "${n}".`,t.typeCondition))}}}},function(e){return{VariableDefinition(t){const n=Gt(e.getSchema(),t.type);if(n&&!he(n)){const n=t.variable.name.value,r=K(t.type);e.reportError(new GraphQLError(`Variable "$${n}" cannot be non-input type "${r}".`,t.type))}}}},function(e){return{Field(t){const n=e.getType(),r=t.selectionSet;if(n)if(ye(_e(n))){if(r){const i=t.name.value,o=l(n);e.reportError(new GraphQLError(`Field "${i}" must not have a selection since type "${o}" has no subfields.`,r))}}else if(!r){const r=t.name.value,i=l(n);e.reportError(new GraphQLError(`Field "${r}" of type "${i}" must have a selection of subfields. Did you mean "${r} { ... }"?`,t))}}}},function(e){return{Field(t){const n=e.getParentType();if(n){if(!e.getFieldDef()){const r=e.getSchema(),i=t.name.value;let o=B("to use an inline fragment on",function(e,t,n){if(!Te(t))return[];const r=new Set,i=Object.create(null);for(const o of e.getPossibleTypes(t))if(o.getFields()[n]){r.add(o),i[o.name]=1;for(const e of o.getInterfaces())e.getFields()[n]&&(r.add(e),i[e.name]=(i[e.name]??0)+1)}return Array.from(r).sort(((t,n)=>{const r=i[n.name]-i[t.name];return 0!==r?r:ce(t)&&e.isSubType(t,n)?-1:ce(n)&&e.isSubType(n,t)?1:t.name.localeCompare(n.name)})).map((e=>e.name))}(r,n,i));""===o&&(o=B(function(e,t){if(ae(e)||ce(e)){return J(t,Object.keys(e.getFields()))}return[]}(n,i))),e.reportError(new GraphQLError(`Cannot query field "${i}" on type "${n.name}".`+o,t))}}}}},function(e){const t=Object.create(null);return{OperationDefinition:()=>!1,FragmentDefinition(n){const r=n.name.value;return t[r]?e.reportError(new GraphQLError(`There can be only one fragment named "${r}".`,[t[r],n.name])):t[r]=n.name,!1}}},function(e){return{FragmentSpread(t){const n=t.name.value;e.getFragment(n)||e.reportError(new GraphQLError(`Unknown fragment "${n}".`,t.name))}}},Pt,function(e){return{InlineFragment(t){const n=e.getType(),r=e.getParentType();if(Ee(n)&&Ee(r)&&!Qe(e.getSchema(),n,r)){const i=l(r),o=l(n);e.reportError(new GraphQLError(`Fragment cannot be spread here as objects of type "${i}" can never be of type "${o}".`,t))}},FragmentSpread(t){const n=t.name.value,r=function(e,t){const n=e.getFragment(t);if(n){const t=Gt(e.getSchema(),n.typeCondition);if(Ee(t))return t}}(e,n),i=e.getParentType();if(r&&i&&!Qe(e.getSchema(),r,i)){const o=l(i),s=l(r);e.reportError(new GraphQLError(`Fragment "${n}" cannot be spread here as objects of type "${o}" can never be of type "${s}".`,t))}}}},function(e){const t=Object.create(null),n=[],r=Object.create(null);return{OperationDefinition:()=>!1,FragmentDefinition:e=>(i(e),!1)};function i(o){if(t[o.name.value])return;const s=o.name.value;t[s]=!0;const a=e.getFragmentSpreads(o.selectionSet);if(0!==a.length){r[s]=n.length;for(const t of a){const o=t.name.value,s=r[o];if(n.push(t),void 0===s){const t=e.getFragment(o);t&&i(t)}else{const t=n.slice(s),r=t.slice(0,-1).map((e=>'"'+e.name.value+'"')).join(", ");e.reportError(new GraphQLError(`Cannot spread fragment "${o}" within itself`+(""!==r?` via ${r}.`:"."),t))}n.pop()}r[s]=void 0}}},function(e){let t=Object.create(null);return{OperationDefinition(){t=Object.create(null)},VariableDefinition(n){const r=n.variable.name.value;t[r]?e.reportError(new GraphQLError(`There can be only one variable named "$${r}".`,[t[r],n.variable.name])):t[r]=n.variable.name}}},function(e){let t=Object.create(null);return{OperationDefinition:{enter(){t=Object.create(null)},leave(n){const r=e.getRecursiveVariableUsages(n);for(const{node:i}of r){const r=i.name.value;!0!==t[r]&&e.reportError(new GraphQLError(n.name?`Variable "$${r}" is not defined by operation "${n.name.value}".`:`Variable "$${r}" is not defined.`,[i,n]))}}},VariableDefinition(e){t[e.variable.name.value]=!0}}},function(e){let t=[];return{OperationDefinition:{enter(){t=[]},leave(n){const r=Object.create(null),i=e.getRecursiveVariableUsages(n);for(const{node:e}of i)r[e.name.value]=!0;for(const i of t){const t=i.variable.name.value;!0!==r[t]&&e.reportError(new GraphQLError(n.name?`Variable "$${t}" is never used in operation "${n.name.value}".`:`Variable "$${t}" is never used.`,i))}}},VariableDefinition(e){t.push(e)}}},Bt,Yt,function(e){return{...Jt(e),Argument(t){const n=e.getArgument(),r=e.getFieldDef(),i=e.getParentType();if(!n&&r&&i){const n=t.name.value,o=J(n,r.args.map((e=>e.name)));e.reportError(new GraphQLError(`Unknown argument "${n}" on field "${i.name}.${r.name}".`+B(o),t))}}}},qt,function(e){return{ListValue(t){if(!de(Ie(e.getParentInputType())))return Kt(e,t),!1},ObjectValue(t){const n=_e(e.getInputType());if(!le(n))return Kt(e,t),!1;const r=U(t.fields,(e=>e.name.value));for(const i of C(n.getFields())){if(!r[i.name]&&Ge(i)){const r=l(i.type);e.reportError(new GraphQLError(`Field "${n.name}.${i.name}" of required type "${r}" was not provided.`,t))}}},ObjectField(t){const n=_e(e.getParentInputType());if(!e.getInputType()&&le(n)){const r=J(t.name.value,Object.keys(n.getFields()));e.reportError(new GraphQLError(`Field "${t.name.value}" is not defined by type "${n.name}".`+B(r),t))}},NullValue(t){const n=e.getInputType();fe(n)&&e.reportError(new GraphQLError(`Expected value of type "${l(n)}", found ${K(t)}.`,t))},EnumValue:t=>Kt(e,t),IntValue:t=>Kt(e,t),FloatValue:t=>Kt(e,t),StringValue:t=>Kt(e,t),BooleanValue:t=>Kt(e,t)}},function(e){return{...Xt(e),Field:{leave(t){const n=e.getFieldDef();if(!n)return!1;const r=U(t.arguments??[],(e=>e.name.value));for(const i of n.args){if(!r[i.name]&&ke(i)){const r=l(i.type);e.reportError(new GraphQLError(`Field "${n.name}" argument "${i.name}" of type "${r}" is required, but it was not provided.`,t))}}}}}},function(e){let t=Object.create(null);return{OperationDefinition:{enter(){t=Object.create(null)},leave(n){const r=e.getRecursiveVariableUsages(n);for(const{node:n,type:i,defaultValue:o}of r){const r=n.name.value,s=t[r];if(s&&i){const t=e.getSchema(),a=Gt(t,s.type);if(a&&!Ht(t,a,s.defaultValue,i,o)){const t=l(a),o=l(i);e.reportError(new GraphQLError(`Variable "$${r}" of type "${t}" used in position expecting type "${o}".`,[s,n]))}}}}},VariableDefinition(e){t[e.variable.name.value]=e}}},function(e){const t=new PairSet,n=new Map;return{SelectionSet(r){const i=function(e,t,n,r,i){const o=[],[s,a]=on(e,t,r,i);if(function(e,t,n,r,i){for(const[o,s]of V(i))if(s.length>1)for(let i=0;i0&&e.reportError(new GraphQLError("Must provide only one schema definition.",t)),++r)}}},function(e){const t=e.getSchema(),n=Object.create(null),r=t?{query:t.getQueryType(),mutation:t.getMutationType(),subscription:t.getSubscriptionType()}:{};return{SchemaDefinition:i,SchemaExtension:i};function i(t){const i=t.operationTypes??[];for(const t of i){const i=t.operation,o=n[i];r[i]?e.reportError(new GraphQLError(`Type for ${i} already defined in the schema. It cannot be redefined.`,t)):o?e.reportError(new GraphQLError(`There can be only one ${i} type in schema.`,[o,t])):n[i]=t}return!1}},function(e){const t=Object.create(null),n=e.getSchema();return{ScalarTypeDefinition:r,ObjectTypeDefinition:r,InterfaceTypeDefinition:r,UnionTypeDefinition:r,EnumTypeDefinition:r,InputObjectTypeDefinition:r};function r(r){const i=r.name.value;if(!n?.getType(i))return t[i]?e.reportError(new GraphQLError(`There can be only one type named "${i}".`,[t[i],r.name])):t[i]=r.name,!1;e.reportError(new GraphQLError(`Type "${i}" already exists in the schema. It cannot also be defined in this type definition.`,r.name))}},function(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),r=Object.create(null);return{EnumTypeDefinition:i,EnumTypeExtension:i};function i(t){const i=t.name.value;r[i]||(r[i]=Object.create(null));const o=t.values??[],s=r[i];for(const t of o){const r=t.name.value,o=n[i];pe(o)&&o.getValue(r)?e.reportError(new GraphQLError(`Enum value "${i}.${r}" already exists in the schema. It cannot also be defined in this type extension.`,t.name)):s[r]?e.reportError(new GraphQLError(`Enum value "${i}.${r}" can only be defined once.`,[s[r],t.name])):s[r]=t.name}return!1}},function(e){const t=e.getSchema(),n=t?t.getTypeMap():Object.create(null),r=Object.create(null);return{InputObjectTypeDefinition:i,InputObjectTypeExtension:i,InterfaceTypeDefinition:i,InterfaceTypeExtension:i,ObjectTypeDefinition:i,ObjectTypeExtension:i};function i(t){const i=t.name.value;r[i]||(r[i]=Object.create(null));const o=t.fields??[],s=r[i];for(const t of o){const r=t.name.value;un(n[i],r)?e.reportError(new GraphQLError(`Field "${i}.${r}" already exists in the schema. It cannot also be defined in this type extension.`,t.name)):s[r]?e.reportError(new GraphQLError(`Field "${i}.${r}" can only be defined once.`,[s[r],t.name])):s[r]=t.name}return!1}},function(e){const t=Object.create(null),n=e.getSchema();return{DirectiveDefinition(r){const i=r.name.value;if(!n?.getDirective(i))return t[i]?e.reportError(new GraphQLError(`There can be only one directive named "@${i}".`,[t[i],r.name])):t[i]=r.name,!1;e.reportError(new GraphQLError(`Directive "@${i}" already exists in the schema. It cannot be redefined.`,r.name))}}},jt,Bt,Yt,function(e){const t=e.getSchema(),n=Object.create(null);for(const t of e.getDocument().definitions)Vt(t)&&(n[t.name.value]=t);return{ScalarTypeExtension:r,ObjectTypeExtension:r,InterfaceTypeExtension:r,UnionTypeExtension:r,EnumTypeExtension:r,InputObjectTypeExtension:r};function r(r){const i=r.name.value,o=n[i],s=t?.getType(i);let a;if(o?a=pn[o.kind]:s&&(a=function(e){if(se(e))return c.SCALAR_TYPE_EXTENSION;if(ae(e))return c.OBJECT_TYPE_EXTENSION;if(ce(e))return c.INTERFACE_TYPE_EXTENSION;if(ue(e))return c.UNION_TYPE_EXTENSION;if(pe(e))return c.ENUM_TYPE_EXTENSION;if(le(e))return c.INPUT_OBJECT_TYPE_EXTENSION;re(0,"Unexpected type: "+l(e))}(s)),a){if(a!==r.kind){const t=function(e){switch(e){case c.SCALAR_TYPE_EXTENSION:return"scalar";case c.OBJECT_TYPE_EXTENSION:return"object";case c.INTERFACE_TYPE_EXTENSION:return"interface";case c.UNION_TYPE_EXTENSION:return"union";case c.ENUM_TYPE_EXTENSION:return"enum";case c.INPUT_OBJECT_TYPE_EXTENSION:return"input object"}re(0,"Unexpected kind: "+l(e))}(r.kind);e.reportError(new GraphQLError(`Cannot extend non-${t} type "${i}".`,o?[o,r]:r))}}else{let o=Object.keys(n);t&&(o=o.concat(Object.keys(t.getTypeMap())));const s=J(i,o);e.reportError(new GraphQLError(`Cannot extend type "${i}" because it is not defined.`+B(s),r.name))}}},Jt,qt,cn,Xt]);class ASTValidationContext{constructor(e,t){this._ast=e,this._fragments=void 0,this._fragmentSpreads=new Map,this._recursivelyReferencedFragments=new Map,this._onError=t}reportError(e){this._onError(e)}getDocument(){return this._ast}getFragment(e){let t=this._fragments;return t||(this._fragments=t=this.getDocument().definitions.reduce(((e,t)=>(t.kind===c.FRAGMENT_DEFINITION&&(e[t.name.value]=t),e)),Object.create(null))),t[e]}getFragmentSpreads(e){let t=this._fragmentSpreads.get(e);if(!t){t=[];const n=[e];for(;0!==n.length;){const e=n.pop();for(const r of e.selections)r.kind===c.FRAGMENT_SPREAD?t.push(r):r.selectionSet&&n.push(r.selectionSet)}this._fragmentSpreads.set(e,t)}return t}getRecursivelyReferencedFragments(e){let t=this._recursivelyReferencedFragments.get(e);if(!t){t=[];const n=Object.create(null),r=[e.selectionSet];for(;0!==r.length;){const e=r.pop();for(const i of this.getFragmentSpreads(e)){const e=i.name.value;if(!0!==n[e]){n[e]=!0;const i=this.getFragment(e);i&&(t.push(i),r.push(i.selectionSet))}}}this._recursivelyReferencedFragments.set(e,t)}return t}}class SDLValidationContext extends ASTValidationContext{constructor(e,t,n){super(e,n),this._schema=t}getSchema(){return this._schema}}class ValidationContext extends ASTValidationContext{constructor(e,t,n,r){super(t,r),this._schema=e,this._typeInfo=n,this._variableUsages=new Map,this._recursiveVariableUsages=new Map}getSchema(){return this._schema}getVariableUsages(e){let t=this._variableUsages.get(e);if(!t){const n=[],r=new TypeInfo(this._schema);R(e,Ct(r,{VariableDefinition:()=>!1,Variable(e){n.push({node:e,type:r.getInputType(),defaultValue:r.getDefaultValue()})}})),t=n,this._variableUsages.set(e,t)}return t}getRecursiveVariableUsages(e){let t=this._recursiveVariableUsages.get(e);if(!t){t=this.getVariableUsages(e);for(const n of this.getRecursivelyReferencedFragments(e))t=t.concat(this.getVariableUsages(n));this._recursiveVariableUsages.set(e,t)}return t}getType(){return this._typeInfo.getType()}getParentType(){return this._typeInfo.getParentType()}getInputType(){return this._typeInfo.getInputType()}getParentInputType(){return this._typeInfo.getParentInputType()}getFieldDef(){return this._typeInfo.getFieldDef()}getDirective(){return this._typeInfo.getDirective()}getArgument(){return this._typeInfo.getArgument()}getEnumValue(){return this._typeInfo.getEnumValue()}}function fn(e,t,n=ln,r=new TypeInfo(e),i={maxErrors:void 0}){t||f(0,"Must provide document."),function(e){const t=vt(e);if(0!==t.length)throw new Error(t.map((e=>e.message)).join("\n\n"))}(e);const o=Object.freeze({}),s=[],a=new ValidationContext(e,t,r,(e=>{if(null!=i.maxErrors&&s.length>=i.maxErrors)throw s.push(new GraphQLError("Too many validation errors, error limit reached. Validation aborted.")),o;s.push(e)})),c=G(n.map((e=>e(a))));try{R(t,Ct(r,c))}catch(e){if(e!==o)throw e}return s}function hn(e,t,n=dn){const r=[],i=new SDLValidationContext(e,t,(e=>{r.push(e)}));return R(e,G(n.map((e=>e(i))))),r}function mn(e,t,n){if(e){if(e.kind===c.VARIABLE){const r=e.name.value;if(null==n||void 0===n[r])return;const i=n[r];if(null===i&&fe(t))return;return i}if(fe(t)){if(e.kind===c.NULL)return;return mn(e,t.ofType,n)}if(e.kind===c.NULL)return null;if(de(t)){const r=t.ofType;if(e.kind===c.LIST){const t=[];for(const i of e.values)if(yn(i,n)){if(fe(r))return;t.push(null)}else{const e=mn(i,r,n);if(void 0===e)return;t.push(e)}return t}const i=mn(e,r,n);if(void 0===i)return;return[i]}if(le(t)){if(e.kind!==c.OBJECT)return;const r=Object.create(null),i=U(e.fields,(e=>e.name.value));for(const e of C(t.getFields())){const t=i[e.name];if(!t||yn(t.value,n)){if(void 0!==e.defaultValue)r[e.name]=e.defaultValue;else if(fe(e.type))return;continue}const o=mn(t.value,e.type,n);if(void 0===o)return;r[e.name]=o}return r}if(ye(t)){let r;try{r=t.parseLiteral(e,n)}catch(e){return}if(void 0===r)return;return r}re(0,"Unexpected input type: "+l(t))}}function yn(e,t){return e.kind===c.VARIABLE&&(null==t||void 0===t[e.name.value])}function En(e,t,n){const r=t.directives?.find((t=>t.name.value===e.name));if(r)return function(e,t,n){const r={},i=U(t.arguments??[],(e=>e.name.value));for(const a of e.args){const e=a.name,u=a.type,p=i[e];if(!p){if(void 0!==a.defaultValue)r[e]=a.defaultValue;else if(fe(u))throw new GraphQLError(`Argument "${e}" of required type "${l(u)}" was not provided.`,t);continue}const d=p.value;let f=d.kind===c.NULL;if(d.kind===c.VARIABLE){const t=d.name.value;if(null==n||(o=n,s=t,!Object.prototype.hasOwnProperty.call(o,s))){if(void 0!==a.defaultValue)r[e]=a.defaultValue;else if(fe(u))throw new GraphQLError(`Argument "${e}" of required type "${l(u)}" was provided the variable "$${t}" which was not provided a runtime value.`,d);continue}f=null==n[t]}if(f&&fe(u))throw new GraphQLError(`Argument "${e}" of non-null type "${l(u)}" must not be null.`,d);const h=mn(d,u,n);if(void 0===h)throw new GraphQLError(`Argument "${e}" has invalid value ${K(d)}.`,d);r[e]=h}var o,s;return r}(e,r,n)}function Tn(e,n){t(e)&&t(e.__schema)||f(0,`Invalid or incomplete introspection result. Ensure that you are passing "data" property of introspection response and no "errors" was returned alongside: ${l(e)}.`);const r=e.__schema,i=P(r.types,(e=>e.name),(e=>function(e){if(null!=e&&null!=e.name&&null!=e.kind)switch(e.kind){case it.SCALAR:return new GraphQLScalarType({name:(r=e).name,description:r.description,specifiedByUrl:r.specifiedByUrl});case it.OBJECT:return new GraphQLObjectType({name:(n=e).name,description:n.description,interfaces:()=>y(n),fields:()=>E(n)});case it.INTERFACE:return new GraphQLInterfaceType({name:(t=e).name,description:t.description,interfaces:()=>y(t),fields:()=>E(t)});case it.UNION:return function(e){if(!e.possibleTypes){const t=l(e);throw new Error(`Introspection result missing possibleTypes: ${t}.`)}return new GraphQLUnionType({name:e.name,description:e.description,types:()=>e.possibleTypes.map(h)})}(e);case it.ENUM:return function(e){if(!e.enumValues){const t=l(e);throw new Error(`Introspection result missing enumValues: ${t}.`)}return new GraphQLEnumType({name:e.name,description:e.description,values:P(e.enumValues,(e=>e.name),(e=>({description:e.description,deprecationReason:e.deprecationReason})))})}(e);case it.INPUT_OBJECT:return function(e){if(!e.inputFields){const t=l(e);throw new Error(`Introspection result missing inputFields: ${t}.`)}return new GraphQLInputObjectType({name:e.name,description:e.description,fields:()=>N(e.inputFields)})}(e)}var t;var n;var r;const i=l(e);throw new Error(`Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ${i}.`)}(e)));for(const e of[...qe,...ut])i[e.name]&&(i[e.name]=e);const o=r.queryType?h(r.queryType):null,s=r.mutationType?h(r.mutationType):null,a=r.subscriptionType?h(r.subscriptionType):null,c=r.directives?r.directives.map((function(e){if(!e.args){const t=l(e);throw new Error(`Introspection result missing directive args: ${t}.`)}if(!e.locations){const t=l(e);throw new Error(`Introspection result missing directive locations: ${t}.`)}return new GraphQLDirective({name:e.name,description:e.description,isRepeatable:e.isRepeatable,locations:e.locations.slice(),args:N(e.args)})})):[];return new GraphQLSchema({description:r.description,query:o,mutation:s,subscription:a,types:C(i),directives:c,assumeValid:n?.assumeValid});function u(e){if(e.kind===it.LIST){const t=e.ofType;if(!t)throw new Error("Decorated type deeper than introspection query.");return new GraphQLList(u(t))}if(e.kind===it.NON_NULL){const t=e.ofType;if(!t)throw new Error("Decorated type deeper than introspection query.");const n=u(t);return new GraphQLNonNull(function(e){if(!ve(e))throw new Error(`Expected ${l(e)} to be a GraphQL nullable type.`);return e}(n))}return d(e)}function d(e){const t=e.name;if(!t)throw new Error(`Unknown type reference: ${l(e)}.`);const n=i[t];if(!n)throw new Error(`Invalid or incomplete schema, unknown type: ${t}. Ensure that a full introspection query is used in order to build a client schema.`);return n}function h(e){return function(e){if(!ae(e))throw new Error(`Expected ${l(e)} to be a GraphQL Object type.`);return e}(d(e))}function m(e){return function(e){if(!ce(e))throw new Error(`Expected ${l(e)} to be a GraphQL Interface type.`);return e}(d(e))}function y(e){if(null===e.interfaces&&e.kind===it.INTERFACE)return[];if(!e.interfaces){const t=l(e);throw new Error(`Introspection result missing interfaces: ${t}.`)}return e.interfaces.map(m)}function E(e){if(!e.fields)throw new Error(`Introspection result missing fields: ${l(e)}.`);return P(e.fields,(e=>e.name),T)}function T(e){const t=u(e.type);if(!me(t)){const e=l(t);throw new Error(`Introspection must provide output type for fields, but received: ${e}.`)}if(!e.args){const t=l(e);throw new Error(`Introspection result missing field args: ${t}.`)}return{description:e.description,deprecationReason:e.deprecationReason,type:t,args:N(e.args)}}function N(e){return P(e,(e=>e.name),v)}function v(e){const t=u(e.type);if(!he(t)){const e=l(t);throw new Error(`Introspection must provide input type for arguments, but received: ${e}.`)}const n=null!=e.defaultValue?mn(function(e,t){const n=new Parser(e,t);n.expectToken(p.SOF);const r=n.parseValueLiteral(!1);return n.expectToken(p.EOF),r}(e.defaultValue),t):void 0;return{description:e.description,type:t,defaultValue:n,deprecationReason:e.deprecationReason}}}function Nn(e,t,n){const r=[],i=Object.create(null),o=[];let s;const a=[];for(const e of t.definitions)if(e.kind===c.SCHEMA_DEFINITION)s=e;else if(e.kind===c.SCHEMA_EXTENSION)a.push(e);else if(Vt(e))r.push(e);else if(Ut(e)){const t=e.name.value,n=i[t];i[t]=n?n.concat([e]):[e]}else e.kind===c.DIRECTIVE_DEFINITION&&o.push(e);if(0===Object.keys(i).length&&0===r.length&&0===o.length&&0===a.length&&null==s)return e;const u=Object.create(null);for(const t of e.types)u[t.name]=h(t);for(const e of r){const t=e.name.value;u[t]=vn[t]??L(e)}const p={query:e.query&&f(e.query),mutation:e.mutation&&f(e.mutation),subscription:e.subscription&&f(e.subscription),...s&&E([s]),...E(a)};return{description:s?.description?.value,...p,types:C(u),directives:[...e.directives.map((function(e){const t=e.toConfig();return new GraphQLDirective({...t,args:j(t.args,y)})})),...o.map((function(e){const t=e.locations.map((({value:e})=>e));return new GraphQLDirective({name:e.name.value,description:e.description?.value,locations:t,isRepeatable:e.repeatable,args:I(e.arguments),astNode:e})}))],extensions:void 0,astNode:s??e.astNode,extensionASTNodes:e.extensionASTNodes.concat(a),assumeValid:n?.assumeValid??!1};function d(e){return de(e)?new GraphQLList(d(e.ofType)):fe(e)?new GraphQLNonNull(d(e.ofType)):f(e)}function f(e){return u[e.name]}function h(e){return pt(e)||Ke(e)?e:se(e)?function(e){const t=e.toConfig(),n=i[t.name]??[];let r=t.specifiedByUrl;for(const e of n)r=gn(e)??r;return new GraphQLScalarType({...t,specifiedByUrl:r,extensionASTNodes:t.extensionASTNodes.concat(n)})}(e):ae(e)?function(e){const t=e.toConfig(),n=i[t.name]??[];return new GraphQLObjectType({...t,interfaces:()=>[...e.getInterfaces().map(f),...O(n)],fields:()=>({...j(t.fields,m),...v(n)}),extensionASTNodes:t.extensionASTNodes.concat(n)})}(e):ce(e)?function(e){const t=e.toConfig(),n=i[t.name]??[];return new GraphQLInterfaceType({...t,interfaces:()=>[...e.getInterfaces().map(f),...O(n)],fields:()=>({...j(t.fields,m),...v(n)}),extensionASTNodes:t.extensionASTNodes.concat(n)})}(e):ue(e)?function(e){const t=e.toConfig(),n=i[t.name]??[];return new GraphQLUnionType({...t,types:()=>[...e.getTypes().map(f),...b(n)],extensionASTNodes:t.extensionASTNodes.concat(n)})}(e):pe(e)?function(e){const t=e.toConfig(),n=i[e.name]??[];return new GraphQLEnumType({...t,values:{...t.values,..._(n)},extensionASTNodes:t.extensionASTNodes.concat(n)})}(e):le(e)?function(e){const t=e.toConfig(),n=i[t.name]??[];return new GraphQLInputObjectType({...t,fields:()=>({...j(t.fields,(e=>({...e,type:d(e.type)}))),...g(n)}),extensionASTNodes:t.extensionASTNodes.concat(n)})}(e):void re(0,"Unexpected type: "+l(e))}function m(e){return{...e,type:d(e.type),args:j(e.args,y)}}function y(e){return{...e,type:d(e.type)}}function E(e){const t={};for(const n of e){const e=n.operationTypes??[];for(const n of e)t[n.operation]=T(n.type)}return t}function T(e){const t=e.name.value,n=vn[t]??u[t];if(void 0===n)throw new Error(`Unknown type: "${t}".`);return n}function N(e){return e.kind===c.LIST_TYPE?new GraphQLList(N(e.type)):e.kind===c.NON_NULL_TYPE?new GraphQLNonNull(N(e.type)):T(e)}function v(e){const t=Object.create(null);for(const n of e){const e=n.fields??[];for(const n of e)t[n.name.value]={type:N(n.type),description:n.description?.value,args:I(n.arguments),deprecationReason:In(n),astNode:n}}return t}function I(e){const t=e??[],n=Object.create(null);for(const e of t){const t=N(e.type);n[e.name.value]={type:t,description:e.description?.value,defaultValue:mn(e.defaultValue,t),deprecationReason:In(e),astNode:e}}return n}function g(e){const t=Object.create(null);for(const n of e){const e=n.fields??[];for(const n of e){const e=N(n.type);t[n.name.value]={type:e,description:n.description?.value,defaultValue:mn(n.defaultValue,e),deprecationReason:In(n),astNode:n}}}return t}function _(e){const t=Object.create(null);for(const n of e){const e=n.values??[];for(const n of e)t[n.name.value]={description:n.description?.value,deprecationReason:In(n),astNode:n}}return t}function O(e){const t=[];for(const n of e){const e=n.interfaces??[];for(const n of e)t.push(T(n))}return t}function b(e){const t=[];for(const n of e){const e=n.types??[];for(const n of e)t.push(T(n))}return t}function L(e){const t=e.name.value,n=i[t]??[];switch(e.kind){case c.OBJECT_TYPE_DEFINITION:{const r=n,i=[e,...r];return new GraphQLObjectType({name:t,description:e.description?.value,interfaces:()=>O(i),fields:()=>v(i),astNode:e,extensionASTNodes:r})}case c.INTERFACE_TYPE_DEFINITION:{const r=n,i=[e,...r];return new GraphQLInterfaceType({name:t,description:e.description?.value,interfaces:()=>O(i),fields:()=>v(i),astNode:e,extensionASTNodes:r})}case c.ENUM_TYPE_DEFINITION:{const r=n,i=[e,...r];return new GraphQLEnumType({name:t,description:e.description?.value,values:_(i),astNode:e,extensionASTNodes:r})}case c.UNION_TYPE_DEFINITION:{const r=n,i=[e,...r];return new GraphQLUnionType({name:t,description:e.description?.value,types:()=>b(i),astNode:e,extensionASTNodes:r})}case c.SCALAR_TYPE_DEFINITION:{const r=n;return new GraphQLScalarType({name:t,description:e.description?.value,specifiedByUrl:gn(e),astNode:e,extensionASTNodes:r})}case c.INPUT_OBJECT_TYPE_DEFINITION:{const r=n,i=[e,...r];return new GraphQLInputObjectType({name:t,description:e.description?.value,fields:()=>g(i),astNode:e,extensionASTNodes:r})}}re(0,"Unexpected type definition node: "+l(e))}}const vn=U(qe.concat(ut),(e=>e.name));function In(e){return En(mt,e)?.reason}function gn(e){return En(yt,e)?.url}function _n(e,t){null!=e&&e.kind===c.DOCUMENT||f(0,"Must provide valid Document AST."),!0!==t?.assumeValid&&!0!==t?.assumeValidSDL&&function(e){const t=hn(e);if(0!==t.length)throw new Error(t.map((e=>e.message)).join("\n\n"))}(e);const n=Nn({description:void 0,types:[],directives:[],extensions:void 0,extensionASTNodes:[],assumeValid:!1},e,t);if(null==n.astNode)for(const e of n.types)switch(e.name){case"Query":n.query=e;break;case"Mutation":n.mutation=e;break;case"Subscription":n.subscription=e}const{directives:r}=n;for(const e of Et)r.every((t=>t.name!==e.name))&&r.push(e);return new GraphQLSchema(n)}function On(e){return function(e,t,n){const r=e.getDirectives().filter(t),i=C(e.getTypeMap()).filter(n);return[Ln(e)].concat(r.map((e=>function(e){return Fn(e)+"directive @"+e.name+wn(e.args)+(e.isRepeatable?" repeatable":"")+" on "+e.locations.join(" | ")}(e))),i.map((e=>function(e){if(se(e))return function(e){return Fn(e)+`scalar ${e.name}`+function(e){if(null==e.specifiedByUrl)return"";const t=Xe(e.specifiedByUrl,Be);return t||re(0,"Unexpected null value returned from `astFromValue` for specifiedByUrl")," @specifiedBy(url: "+K(t)+")"}(e)}(e);if(ae(e))return function(e){return Fn(e)+`type ${e.name}`+Sn(e)+An(e)}(e);if(ce(e))return function(e){return Fn(e)+`interface ${e.name}`+Sn(e)+An(e)}(e);if(ue(e))return function(e){const t=e.getTypes(),n=t.length?" = "+t.join(" | "):"";return Fn(e)+"union "+e.name+n}(e);if(pe(e))return function(e){const t=e.getValues().map(((e,t)=>Fn(e," ",!t)+" "+e.name+xn(e.deprecationReason)));return Fn(e)+`enum ${e.name}`+Dn(t)}(e);if(le(e))return function(e){const t=C(e.getFields()).map(((e,t)=>Fn(e," ",!t)+" "+kn(e)));return Fn(e)+`input ${e.name}`+Dn(t)}(e);re(0,"Unexpected type: "+l(e))}(e)))).filter(Boolean).join("\n\n")+"\n"}(e,(e=>{return t=e,!Et.some((({name:e})=>e===t.name));var t}),bn)}function bn(e){return!Ke(e)&&!pt(e)}function Ln(e){if(null==e.description&&function(e){const t=e.getQueryType();if(t&&"Query"!==t.name)return!1;const n=e.getMutationType();if(n&&"Mutation"!==n.name)return!1;const r=e.getSubscriptionType();if(r&&"Subscription"!==r.name)return!1;return!0}(e))return;const t=[],n=e.getQueryType();n&&t.push(` query: ${n.name}`);const r=e.getMutationType();r&&t.push(` mutation: ${r.name}`);const i=e.getSubscriptionType();return i&&t.push(` subscription: ${i.name}`),Fn(e)+`schema {\n${t.join("\n")}\n}`}function Sn(e){const t=e.getInterfaces();return t.length?" implements "+t.map((e=>e.name)).join(" & "):""}function An(e){return Dn(C(e.getFields()).map(((e,t)=>Fn(e," ",!t)+" "+e.name+wn(e.args," ")+": "+String(e.type)+xn(e.deprecationReason))))}function Dn(e){return 0!==e.length?" {\n"+e.join("\n")+"\n}":""}function wn(e,t=""){return 0===e.length?"":e.every((e=>!e.description))?"("+e.map(kn).join(", ")+")":"(\n"+e.map(((e,n)=>Fn(e," "+t,!n)+" "+t+kn(e))).join("\n")+"\n"+t+")"}function kn(e){const t=Xe(e.defaultValue,e.type);let n=e.name+": "+String(e.type);return t&&(n+=` = ${K(t)}`),n+xn(e.deprecationReason)}function xn(e){if(null==e)return"";const t=Xe(e,Be);return t&&e!==ht?" @deprecated(reason: "+K(t)+")":" @deprecated"}function Fn(e,t="",n=!0){const{description:r}=e;if(null==r)return"";return(t&&!n?"\n"+t:t)+T(r,"",r.length>70).replace(/\n/g,"\n"+t)+"\n"}const Rn=[Pt],Gn=[function(e){return{OperationDefinition:t=>(t.name||e.reportError(new GraphQLError("Apollo does not support anonymous operations because operation names are used during code generation. Please give this operation a name.",t)),!1)}},function(e){return{Field(t){"__typename"==(t.alias&&t.alias.value)&&e.reportError(new GraphQLError("Apollo needs to be able to insert __typename when needed, so using it as an alias is not supported.",t))}}},...ln.filter((e=>!Rn.includes(e)))];class GraphQLSchemaValidationError extends Error{constructor(e){super(e.map((e=>e.message)).join("\n\n")),this.validationErrors=e,this.name="GraphQLSchemaValidationError"}}function $n(e){const t=vt(e);if(0!==t.length)throw new GraphQLSchemaValidationError(t)}function Cn(e){return e.startsWith("__")}function Qn(e){return null!=e}function Vn(e){switch(e.kind){case"Variable":return{kind:e.kind,value:e.name.value};case"ListValue":return{kind:e.kind,value:e.values.map(Vn)};case"ObjectValue":return{kind:e.kind,value:e.fields.reduce(((e,t)=>(e[t.name.value]=Vn(t.value),e)),{})};default:return e}}function Un(e){var t,n;return null===(n=null===(t=e.loc)||void 0===t?void 0:t.source)||void 0===n?void 0:n.name}function jn(e,t){const n=new Map;for(const e of t.definitions)e.kind===c.FRAGMENT_DEFINITION&&n.set(e.name.value,e);const r=[],i=new Map,o=new Set;for(const e of t.definitions)e.kind===c.OPERATION_DEFINITION&&r.push(s(e));for(const[e,t]of n.entries())i.set(e,a(t));return{operations:r,fragments:Array.from(i.values()),referencedTypes:Array.from(o.values())};function s(t){if(!t.name)throw new GraphQLError("Operations should be named",t);const n=Un(t),r=t.name.value,i=t.operation,s=(t.variableDefinitions||[]).map((t=>{const n=t.variable.name.value,r=Gt(e,t.type);if(!r)throw new GraphQLError(`Couldn't get type from type node "${t.type}"`,t);return o.add(_e(r)),{name:n,type:r}})),a=K(t),c=function(e,t){if("query"===t.operation){const n=e.getQueryType();if(!n)throw new GraphQLError("Schema does not define the required query root type.",t);return n}if("mutation"===t.operation){const n=e.getMutationType();if(!n)throw new GraphQLError("Schema is not configured for mutations.",t);return n}if("subscription"===t.operation){const n=e.getSubscriptionType();if(!n)throw new GraphQLError("Schema is not configured for subscriptions.",t);return n}throw new GraphQLError("Can only have query, mutation and subscription operations.",t)}(e,t);return{filePath:n,name:r,operationType:i,rootType:c,variables:s,source:a,selectionSet:u(t.selectionSet,c)}}function a(t){const n=t.name.value,r=Un(t),i=K(t),o=Gt(e,t.typeCondition);return{name:n,filePath:r,source:i,typeCondition:o,selectionSet:u(t.selectionSet,o)}}function u(t,r,s=new Set){return{parentType:r,selections:t.selections.map((t=>function(t,r,s){var p;switch(t.kind){case c.FIELD:{const n=t.name.value,i=null===(p=t.alias)||void 0===p?void 0:p.value,s=function(e,t,n){return n===st.name&&e.getQueryType()===t?st:n===at.name&&e.getQueryType()===t?at:n===ct.name&&(ae(t)||ce(t)||ue(t))?ct:ae(t)||ce(t)?t.getFields()[n]:void 0}(e,r,n);if(!s)throw new GraphQLError(`Cannot query field "${n}" on type "${String(r)}"`,t);const a=s.type,c=_e(a);o.add(c);const{description:l,deprecationReason:d}=s;let f={kind:"Field",name:n,alias:i,arguments:t.arguments&&t.arguments.length>0?t.arguments.map((e=>{const t=e.name.value,n=s.args.find((t=>t.name===e.name.value)),r=n&&n.type||void 0;return{name:t,value:Vn(e.value),type:r}})):void 0,type:a,description:!Cn(n)&&l?l:void 0,deprecationReason:d||void 0};if(Ee(c)){const e=t.selectionSet;if(!e)throw new GraphQLError(`Composite field "${n}" on type "${String(r)}" requires selection set`,t);f.selectionSet=u(e,c)}return f}case c.INLINE_FRAGMENT:{const n=t.typeCondition,i=n?Gt(e,n):r;return{kind:"InlineFragment",selectionSet:u(t.selectionSet,i)}}case c.FRAGMENT_SPREAD:{const e=t.name.value;if(s.has(e))return;s.add(e);const r=function(e){let t=i.get(e);if(t)return t;const r=n.get(e);return r?(n.delete(e),t=a(r),i.set(e,t),t):void 0}(e);if(!r)throw new GraphQLError(`Unknown fragment "${e}".`,t.name);return{kind:"FragmentSpread",fragment:r}}}}(t,r,s))).filter(Qn)}}}return c.FIELD,c.NAME,e.GraphQLEnumType=GraphQLEnumType,e.GraphQLError=GraphQLError,e.GraphQLInputObjectType=GraphQLInputObjectType,e.GraphQLInterfaceType=GraphQLInterfaceType,e.GraphQLObjectType=GraphQLObjectType,e.GraphQLScalarType=GraphQLScalarType,e.GraphQLSchema=GraphQLSchema,e.GraphQLSchemaValidationError=GraphQLSchemaValidationError,e.GraphQLUnionType=GraphQLUnionType,e.Source=Source,e.compileDocument=function(e,t){return jn(e,t)},e.loadSchemaFromIntrospectionResult=function(e){let t=JSON.parse(e);t.data&&(t=t.data);const n=Tn(t);return $n(n),n},e.loadSchemaFromSDL=function(e){const t=D(e);!function(e){const t=hn(e);if(0!==t.length)throw new GraphQLSchemaValidationError(t)}(t);const n=_n(t,{assumeValidSDL:!0});return $n(n),n},e.mergeDocuments=function(e){return function(e){let t=[];for(const n of e)t=t.concat(n.definitions);return{kind:"Document",definitions:t}}(e)},e.parseDocument=function(e){return D(e)},e.printSchemaToSDL=function(e){return On(e)},e.validateDocument=function(e,t){return fn(e,t,Gn)},Object.defineProperty(e,"__esModule",{value:!0}),e}({}); -//# sourceMappingURL=ApolloCodegenFrontend.bundle.js.map diff --git a/Sources/ApolloCodegenLib/Frontend/dist/ApolloCodegenFrontend.bundle.js.map b/Sources/ApolloCodegenLib/Frontend/dist/ApolloCodegenFrontend.bundle.js.map deleted file mode 100644 index 03ac05b23d..0000000000 --- a/Sources/ApolloCodegenLib/Frontend/dist/ApolloCodegenFrontend.bundle.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ApolloCodegenFrontend.bundle.js","sources":["../JavaScript/node_modules/graphql/jsutils/isObjectLike.mjs","../JavaScript/node_modules/graphql/language/location.mjs","../JavaScript/node_modules/graphql/language/printLocation.mjs","../JavaScript/node_modules/graphql/error/GraphQLError.mjs","../JavaScript/node_modules/graphql/error/syntaxError.mjs","../JavaScript/node_modules/graphql/language/kinds.mjs","../JavaScript/node_modules/graphql/language/ast.mjs","../JavaScript/node_modules/graphql/language/tokenKind.mjs","../JavaScript/node_modules/graphql/jsutils/inspect.mjs","../JavaScript/node_modules/graphql/jsutils/devAssert.mjs","../JavaScript/node_modules/graphql/jsutils/instanceOf.mjs","../JavaScript/node_modules/graphql/language/source.mjs","../JavaScript/node_modules/graphql/language/directiveLocation.mjs","../JavaScript/node_modules/graphql/language/blockString.mjs","../JavaScript/node_modules/graphql/language/lexer.mjs","../JavaScript/node_modules/graphql/language/parser.mjs","../JavaScript/node_modules/graphql/language/visitor.mjs","../JavaScript/node_modules/graphql/polyfills/objectValues.mjs","../JavaScript/node_modules/graphql/utilities/assertValidName.mjs","../JavaScript/node_modules/graphql/polyfills/objectEntries.mjs","../JavaScript/node_modules/graphql/jsutils/keyMap.mjs","../JavaScript/node_modules/graphql/jsutils/mapValue.mjs","../JavaScript/node_modules/graphql/jsutils/toObjMap.mjs","../JavaScript/node_modules/graphql/jsutils/keyValMap.mjs","../JavaScript/node_modules/graphql/jsutils/didYouMean.mjs","../JavaScript/node_modules/graphql/jsutils/identityFunc.mjs","../JavaScript/node_modules/graphql/jsutils/suggestionList.mjs","../JavaScript/node_modules/graphql/language/printer.mjs","../JavaScript/node_modules/graphql/jsutils/invariant.mjs","../JavaScript/node_modules/graphql/utilities/valueFromASTUntyped.mjs","../JavaScript/node_modules/graphql/type/definition.mjs","../JavaScript/node_modules/graphql/utilities/typeComparators.mjs","../JavaScript/node_modules/graphql/type/scalars.mjs","../JavaScript/node_modules/graphql/utilities/astFromValue.mjs","../JavaScript/node_modules/graphql/jsutils/isCollection.mjs","../JavaScript/node_modules/graphql/type/introspection.mjs","../JavaScript/node_modules/graphql/type/directives.mjs","../JavaScript/node_modules/graphql/type/schema.mjs","../JavaScript/node_modules/graphql/type/validate.mjs","../JavaScript/node_modules/graphql/error/locatedError.mjs","../JavaScript/node_modules/graphql/utilities/typeFromAST.mjs","../JavaScript/node_modules/graphql/utilities/TypeInfo.mjs","../JavaScript/node_modules/graphql/language/predicates.mjs","../JavaScript/node_modules/graphql/validation/rules/KnownTypeNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/NoUnusedFragmentsRule.mjs","../JavaScript/node_modules/graphql/validation/rules/KnownDirectivesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueDirectivesPerLocationRule.mjs","../JavaScript/node_modules/graphql/validation/rules/KnownArgumentNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueArgumentNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/ValuesOfCorrectTypeRule.mjs","../JavaScript/node_modules/graphql/validation/rules/ProvidedRequiredArgumentsRule.mjs","../JavaScript/node_modules/graphql/validation/rules/VariablesInAllowedPositionRule.mjs","../JavaScript/node_modules/graphql/validation/rules/OverlappingFieldsCanBeMergedRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueInputFieldNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueFieldDefinitionNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/PossibleTypeExtensionsRule.mjs","../JavaScript/node_modules/graphql/validation/specifiedRules.mjs","../JavaScript/node_modules/graphql/validation/rules/ExecutableDefinitionsRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueOperationNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/LoneAnonymousOperationRule.mjs","../JavaScript/node_modules/graphql/validation/rules/SingleFieldSubscriptionsRule.mjs","../JavaScript/node_modules/graphql/validation/rules/FragmentsOnCompositeTypesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/VariablesAreInputTypesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/ScalarLeafsRule.mjs","../JavaScript/node_modules/graphql/validation/rules/FieldsOnCorrectTypeRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueFragmentNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/KnownFragmentNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/PossibleFragmentSpreadsRule.mjs","../JavaScript/node_modules/graphql/validation/rules/NoFragmentCyclesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueVariableNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/NoUndefinedVariablesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/NoUnusedVariablesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/LoneSchemaDefinitionRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueOperationTypesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueTypeNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueEnumValueNamesRule.mjs","../JavaScript/node_modules/graphql/validation/rules/UniqueDirectiveNamesRule.mjs","../JavaScript/node_modules/graphql/validation/ValidationContext.mjs","../JavaScript/node_modules/graphql/validation/validate.mjs","../JavaScript/node_modules/graphql/utilities/valueFromAST.mjs","../JavaScript/node_modules/graphql/execution/values.mjs","../JavaScript/node_modules/graphql/utilities/buildClientSchema.mjs","../JavaScript/node_modules/graphql/utilities/extendSchema.mjs","../JavaScript/node_modules/graphql/utilities/buildASTSchema.mjs","../JavaScript/node_modules/graphql/utilities/printSchema.mjs","../JavaScript/src/validationRules.ts","../JavaScript/src/utilities/graphql.ts","../JavaScript/src/utilities/predicates.ts","../JavaScript/src/compiler/values.ts","../JavaScript/src/compiler/index.ts","../JavaScript/node_modules/graphql/utilities/getOperationRootType.mjs","../JavaScript/src/index.ts","../JavaScript/node_modules/graphql/utilities/concatAST.mjs"],"sourcesContent":["/**\n * Return true if `value` is object-like. A value is object-like if it's not\n * `null` and has a `typeof` result of \"object\".\n */\nexport default function isObjectLike(value) {\n return typeof value == 'object' && value !== null;\n}\n","/**\n * Represents a location in a Source.\n */\n\n/**\n * Takes a Source and a UTF-8 character offset, and returns the corresponding\n * line and column as a SourceLocation.\n */\nexport function getLocation(source, position) {\n const lineRegexp = /\\r\\n|[\\n\\r]/g;\n let line = 1;\n let column = position + 1;\n let match;\n\n while ((match = lineRegexp.exec(source.body)) && match.index < position) {\n line += 1;\n column = position + 1 - (match.index + match[0].length);\n }\n\n return {\n line,\n column\n };\n}\n","import { getLocation } from \"./location.mjs\";\n/**\n * Render a helpful description of the location in the GraphQL Source document.\n */\n\nexport function printLocation(location) {\n return printSourceLocation(location.source, getLocation(location.source, location.start));\n}\n/**\n * Render a helpful description of the location in the GraphQL Source document.\n */\n\nexport function printSourceLocation(source, sourceLocation) {\n const firstLineColumnOffset = source.locationOffset.column - 1;\n const body = whitespace(firstLineColumnOffset) + source.body;\n const lineIndex = sourceLocation.line - 1;\n const lineOffset = source.locationOffset.line - 1;\n const lineNum = sourceLocation.line + lineOffset;\n const columnOffset = sourceLocation.line === 1 ? firstLineColumnOffset : 0;\n const columnNum = sourceLocation.column + columnOffset;\n const locationStr = `${source.name}:${lineNum}:${columnNum}\\n`;\n const lines = body.split(/\\r\\n|[\\n\\r]/g);\n const locationLine = lines[lineIndex]; // Special case for minified documents\n\n if (locationLine.length > 120) {\n const subLineIndex = Math.floor(columnNum / 80);\n const subLineColumnNum = columnNum % 80;\n const subLines = [];\n\n for (let i = 0; i < locationLine.length; i += 80) {\n subLines.push(locationLine.slice(i, i + 80));\n }\n\n return locationStr + printPrefixedLines([[`${lineNum}`, subLines[0]], ...subLines.slice(1, subLineIndex + 1).map(subLine => ['', subLine]), [' ', whitespace(subLineColumnNum - 1) + '^'], ['', subLines[subLineIndex + 1]]]);\n }\n\n return locationStr + printPrefixedLines([// Lines specified like this: [\"prefix\", \"string\"],\n [`${lineNum - 1}`, lines[lineIndex - 1]], [`${lineNum}`, locationLine], ['', whitespace(columnNum - 1) + '^'], [`${lineNum + 1}`, lines[lineIndex + 1]]]);\n}\n\nfunction printPrefixedLines(lines) {\n const existingLines = lines.filter(([_, line]) => line !== undefined);\n const padLen = Math.max(...existingLines.map(([prefix]) => prefix.length));\n return existingLines.map(([prefix, line]) => leftPad(padLen, prefix) + (line ? ' | ' + line : ' |')).join('\\n');\n}\n\nfunction whitespace(len) {\n return Array(len + 1).join(' ');\n}\n\nfunction leftPad(len, str) {\n return whitespace(len - str.length) + str;\n}\n","// FIXME:\n// flowlint uninitialized-instance-property:off\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport { getLocation } from \"../language/location.mjs\";\nimport { printLocation, printSourceLocation } from \"../language/printLocation.mjs\";\n/**\n * A GraphQLError describes an Error found during the parse, validate, or\n * execute phases of performing a GraphQL operation. In addition to a message\n * and stack trace, it also includes information about the locations in a\n * GraphQL document and/or execution result that correspond to the Error.\n */\n\nexport class GraphQLError extends Error {\n /**\n * A message describing the Error for debugging purposes.\n *\n * Enumerable, and appears in the result of JSON.stringify().\n *\n * Note: should be treated as readonly, despite invariant usage.\n */\n\n /**\n * An array of { line, column } locations within the source GraphQL document\n * which correspond to this error.\n *\n * Errors during validation often contain multiple locations, for example to\n * point out two things with the same name. Errors during execution include a\n * single location, the field which produced the error.\n *\n * Enumerable, and appears in the result of JSON.stringify().\n */\n\n /**\n * An array describing the JSON-path into the execution response which\n * corresponds to this error. Only included for errors during execution.\n *\n * Enumerable, and appears in the result of JSON.stringify().\n */\n\n /**\n * An array of GraphQL AST Nodes corresponding to this error.\n */\n\n /**\n * The source GraphQL document for the first location of this error.\n *\n * Note that if this Error represents more than one node, the source may not\n * represent nodes after the first node.\n */\n\n /**\n * An array of character offsets within the source GraphQL document\n * which correspond to this error.\n */\n\n /**\n * The original error thrown from a field resolver during execution.\n */\n\n /**\n * Extension fields to add to the formatted error.\n */\n constructor(message, nodes, source, positions, path, originalError, extensions) {\n super(message); // Compute list of blame nodes.\n\n const _nodes = Array.isArray(nodes) ? nodes.length !== 0 ? nodes : undefined : nodes ? [nodes] : undefined; // Compute locations in the source for the given nodes/positions.\n\n\n let _source = source;\n\n if (!_source && _nodes) {\n _source = _nodes[0].loc?.source;\n }\n\n let _positions = positions;\n\n if (!_positions && _nodes) {\n _positions = _nodes.reduce((list, node) => {\n if (node.loc) {\n list.push(node.loc.start);\n }\n\n return list;\n }, []);\n }\n\n if (_positions && _positions.length === 0) {\n _positions = undefined;\n }\n\n let _locations;\n\n if (positions && source) {\n _locations = positions.map(pos => getLocation(source, pos));\n } else if (_nodes) {\n _locations = _nodes.reduce((list, node) => {\n if (node.loc) {\n list.push(getLocation(node.loc.source, node.loc.start));\n }\n\n return list;\n }, []);\n }\n\n let _extensions = extensions;\n\n if (_extensions == null && originalError != null) {\n const originalExtensions = originalError.extensions;\n\n if (isObjectLike(originalExtensions)) {\n _extensions = originalExtensions;\n }\n }\n\n Object.defineProperties(this, {\n name: {\n value: 'GraphQLError'\n },\n message: {\n value: message,\n // By being enumerable, JSON.stringify will include `message` in the\n // resulting output. This ensures that the simplest possible GraphQL\n // service adheres to the spec.\n enumerable: true,\n writable: true\n },\n locations: {\n // Coercing falsy values to undefined ensures they will not be included\n // in JSON.stringify() when not provided.\n value: _locations ?? undefined,\n // By being enumerable, JSON.stringify will include `locations` in the\n // resulting output. This ensures that the simplest possible GraphQL\n // service adheres to the spec.\n enumerable: _locations != null\n },\n path: {\n // Coercing falsy values to undefined ensures they will not be included\n // in JSON.stringify() when not provided.\n value: path ?? undefined,\n // By being enumerable, JSON.stringify will include `path` in the\n // resulting output. This ensures that the simplest possible GraphQL\n // service adheres to the spec.\n enumerable: path != null\n },\n nodes: {\n value: _nodes ?? undefined\n },\n source: {\n value: _source ?? undefined\n },\n positions: {\n value: _positions ?? undefined\n },\n originalError: {\n value: originalError\n },\n extensions: {\n // Coercing falsy values to undefined ensures they will not be included\n // in JSON.stringify() when not provided.\n value: _extensions ?? undefined,\n // By being enumerable, JSON.stringify will include `path` in the\n // resulting output. This ensures that the simplest possible GraphQL\n // service adheres to the spec.\n enumerable: _extensions != null\n }\n }); // Include (non-enumerable) stack trace.\n\n if (originalError?.stack) {\n Object.defineProperty(this, 'stack', {\n value: originalError.stack,\n writable: true,\n configurable: true\n });\n return;\n } // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317')\n\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, GraphQLError);\n } else {\n Object.defineProperty(this, 'stack', {\n value: Error().stack,\n writable: true,\n configurable: true\n });\n }\n }\n\n toString() {\n return printError(this);\n } // FIXME: workaround to not break chai comparisons, should be remove in v16\n // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'Object';\n }\n\n}\n/**\n * Prints a GraphQLError to a string, representing useful location information\n * about the error's position in the source.\n */\n\nexport function printError(error) {\n let output = error.message;\n\n if (error.nodes) {\n for (const node of error.nodes) {\n if (node.loc) {\n output += '\\n\\n' + printLocation(node.loc);\n }\n }\n } else if (error.source && error.locations) {\n for (const location of error.locations) {\n output += '\\n\\n' + printSourceLocation(error.source, location);\n }\n }\n\n return output;\n}\n","import { GraphQLError } from \"./GraphQLError.mjs\";\n/**\n * Produces a GraphQLError representing a syntax error, containing useful\n * descriptive information about the syntax error's position in the source.\n */\n\nexport function syntaxError(source, position, description) {\n return new GraphQLError(`Syntax Error: ${description}`, undefined, source, [position]);\n}\n","/**\n * The set of allowed kind values for AST nodes.\n */\nexport const Kind = Object.freeze({\n // Name\n NAME: 'Name',\n // Document\n DOCUMENT: 'Document',\n OPERATION_DEFINITION: 'OperationDefinition',\n VARIABLE_DEFINITION: 'VariableDefinition',\n SELECTION_SET: 'SelectionSet',\n FIELD: 'Field',\n ARGUMENT: 'Argument',\n // Fragments\n FRAGMENT_SPREAD: 'FragmentSpread',\n INLINE_FRAGMENT: 'InlineFragment',\n FRAGMENT_DEFINITION: 'FragmentDefinition',\n // Values\n VARIABLE: 'Variable',\n INT: 'IntValue',\n FLOAT: 'FloatValue',\n STRING: 'StringValue',\n BOOLEAN: 'BooleanValue',\n NULL: 'NullValue',\n ENUM: 'EnumValue',\n LIST: 'ListValue',\n OBJECT: 'ObjectValue',\n OBJECT_FIELD: 'ObjectField',\n // Directives\n DIRECTIVE: 'Directive',\n // Types\n NAMED_TYPE: 'NamedType',\n LIST_TYPE: 'ListType',\n NON_NULL_TYPE: 'NonNullType',\n // Type System Definitions\n SCHEMA_DEFINITION: 'SchemaDefinition',\n OPERATION_TYPE_DEFINITION: 'OperationTypeDefinition',\n // Type Definitions\n SCALAR_TYPE_DEFINITION: 'ScalarTypeDefinition',\n OBJECT_TYPE_DEFINITION: 'ObjectTypeDefinition',\n FIELD_DEFINITION: 'FieldDefinition',\n INPUT_VALUE_DEFINITION: 'InputValueDefinition',\n INTERFACE_TYPE_DEFINITION: 'InterfaceTypeDefinition',\n UNION_TYPE_DEFINITION: 'UnionTypeDefinition',\n ENUM_TYPE_DEFINITION: 'EnumTypeDefinition',\n ENUM_VALUE_DEFINITION: 'EnumValueDefinition',\n INPUT_OBJECT_TYPE_DEFINITION: 'InputObjectTypeDefinition',\n // Directive Definitions\n DIRECTIVE_DEFINITION: 'DirectiveDefinition',\n // Type System Extensions\n SCHEMA_EXTENSION: 'SchemaExtension',\n // Type Extensions\n SCALAR_TYPE_EXTENSION: 'ScalarTypeExtension',\n OBJECT_TYPE_EXTENSION: 'ObjectTypeExtension',\n INTERFACE_TYPE_EXTENSION: 'InterfaceTypeExtension',\n UNION_TYPE_EXTENSION: 'UnionTypeExtension',\n ENUM_TYPE_EXTENSION: 'EnumTypeExtension',\n INPUT_OBJECT_TYPE_EXTENSION: 'InputObjectTypeExtension'\n});\n/**\n * The enum type representing the possible kind values of AST nodes.\n */\n","/**\n * Contains a range of UTF-8 character offsets and token references that\n * identify the region of the source from which the AST derived.\n */\nexport class Location {\n /**\n * The character offset at which this Node begins.\n */\n\n /**\n * The character offset at which this Node ends.\n */\n\n /**\n * The Token at which this Node begins.\n */\n\n /**\n * The Token at which this Node ends.\n */\n\n /**\n * The Source document the AST represents.\n */\n constructor(startToken, endToken, source) {\n this.start = startToken.start;\n this.end = endToken.end;\n this.startToken = startToken;\n this.endToken = endToken;\n this.source = source;\n }\n\n toJSON() {\n return {\n start: this.start,\n end: this.end\n };\n } // @deprecated: Will be removed in v17\n // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return this.toJSON();\n }\n\n}\n/**\n * Represents a range of characters represented by a lexical token\n * within a Source.\n */\n\nexport class Token {\n /**\n * The kind of Token.\n */\n\n /**\n * The character offset at which this Node begins.\n */\n\n /**\n * The character offset at which this Node ends.\n */\n\n /**\n * The 1-indexed line number on which this Token appears.\n */\n\n /**\n * The 1-indexed column number at which this Token begins.\n */\n\n /**\n * For non-punctuation tokens, represents the interpreted value of the token.\n */\n\n /**\n * Tokens exist as nodes in a double-linked-list amongst all tokens\n * including ignored tokens. is always the first node and \n * the last.\n */\n constructor(kind, start, end, line, column, prev, value) {\n this.kind = kind;\n this.start = start;\n this.end = end;\n this.line = line;\n this.column = column;\n this.value = value;\n this.prev = prev;\n this.next = null;\n }\n\n toJSON() {\n return {\n kind: this.kind,\n value: this.value,\n line: this.line,\n column: this.column\n };\n } // @deprecated: Will be removed in v17\n // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return this.toJSON();\n }\n\n}\n/**\n * @internal\n */\n\nexport function isNode(maybeNode) {\n return maybeNode != null && typeof maybeNode.kind === 'string';\n}\n/**\n * The list of all possible AST node types.\n */\n","/**\n * An exported enum describing the different kinds of tokens that the\n * lexer emits.\n */\nexport const TokenKind = Object.freeze({\n SOF: '',\n EOF: '',\n BANG: '!',\n DOLLAR: '$',\n AMP: '&',\n PAREN_L: '(',\n PAREN_R: ')',\n SPREAD: '...',\n COLON: ':',\n EQUALS: '=',\n AT: '@',\n BRACKET_L: '[',\n BRACKET_R: ']',\n BRACE_L: '{',\n PIPE: '|',\n BRACE_R: '}',\n NAME: 'Name',\n INT: 'Int',\n FLOAT: 'Float',\n STRING: 'String',\n BLOCK_STRING: 'BlockString',\n COMMENT: 'Comment'\n});\n/**\n * The enum type representing the token kinds values.\n */\n","/* eslint-disable flowtype/no-weak-types */\nconst MAX_ARRAY_LENGTH = 10;\nconst MAX_RECURSIVE_DEPTH = 2;\n/**\n * Used to print values in error messages.\n */\n\nexport default function inspect(value) {\n return formatValue(value, []);\n}\n\nfunction formatValue(value, seenValues) {\n switch (typeof value) {\n case 'string':\n return JSON.stringify(value);\n\n case 'function':\n return value.name ? `[function ${value.name}]` : '[function]';\n\n case 'object':\n if (value === null) {\n return 'null';\n }\n\n return formatObjectValue(value, seenValues);\n\n default:\n return String(value);\n }\n}\n\nfunction formatObjectValue(value, previouslySeenValues) {\n if (previouslySeenValues.indexOf(value) !== -1) {\n return '[Circular]';\n }\n\n const seenValues = [...previouslySeenValues, value];\n\n if (typeof value.toJSON === 'function') {\n const jsonValue = value.toJSON(value); // check for infinite recursion\n\n if (jsonValue !== value) {\n return typeof jsonValue === 'string' ? jsonValue : formatValue(jsonValue, seenValues);\n }\n } else if (Array.isArray(value)) {\n return formatArray(value, seenValues);\n }\n\n return formatObject(value, seenValues);\n}\n\nfunction formatObject(object, seenValues) {\n const keys = Object.keys(object);\n\n if (keys.length === 0) {\n return '{}';\n }\n\n if (seenValues.length > MAX_RECURSIVE_DEPTH) {\n return '[' + getObjectTag(object) + ']';\n }\n\n const properties = keys.map(key => {\n const value = formatValue(object[key], seenValues);\n return key + ': ' + value;\n });\n return '{ ' + properties.join(', ') + ' }';\n}\n\nfunction formatArray(array, seenValues) {\n if (array.length === 0) {\n return '[]';\n }\n\n if (seenValues.length > MAX_RECURSIVE_DEPTH) {\n return '[Array]';\n }\n\n const len = Math.min(MAX_ARRAY_LENGTH, array.length);\n const remaining = array.length - len;\n const items = [];\n\n for (let i = 0; i < len; ++i) {\n items.push(formatValue(array[i], seenValues));\n }\n\n if (remaining === 1) {\n items.push('... 1 more item');\n } else if (remaining > 1) {\n items.push(`... ${remaining} more items`);\n }\n\n return '[' + items.join(', ') + ']';\n}\n\nfunction getObjectTag(object) {\n const tag = Object.prototype.toString.call(object).replace(/^\\[object /, '').replace(/]$/, '');\n\n if (tag === 'Object' && typeof object.constructor === 'function') {\n const name = object.constructor.name;\n\n if (typeof name === 'string' && name !== '') {\n return name;\n }\n }\n\n return tag;\n}\n","export default function devAssert(condition, message) {\n const booleanCondition = Boolean(condition); // istanbul ignore else (See transformation done in './resources/inlineInvariant.js')\n\n if (!booleanCondition) {\n throw new Error(message);\n }\n}\n","/**\n * A replacement for instanceof which includes an error warning when multi-realm\n * constructors are detected.\n */\n// See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production\n// See: https://webpack.js.org/guides/production/\nexport default process.env.NODE_ENV === 'production' ? // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2317')\n// eslint-disable-next-line no-shadow\nfunction instanceOf(value, constructor) {\n return value instanceof constructor;\n} : // eslint-disable-next-line no-shadow\nfunction instanceOf(value, constructor) {\n if (value instanceof constructor) {\n return true;\n }\n\n if (value) {\n const valueClass = value.constructor;\n const className = constructor.name;\n\n if (className && valueClass && valueClass.name === className) {\n throw new Error(`Cannot use ${className} \"${value}\" from another module or realm.\n\nEnsure that there is only one instance of \"graphql\" in the node_modules\ndirectory. If different versions of \"graphql\" are the dependencies of other\nrelied on modules, use \"resolutions\" to ensure only one version is installed.\n\nhttps://yarnpkg.com/en/docs/selective-version-resolutions\n\nDuplicate \"graphql\" modules cannot be used at the same time since different\nversions may have different capabilities and behavior. The data from one\nversion used in the function from another could produce confusing and\nspurious results.`);\n }\n }\n\n return false;\n};\n","import inspect from \"../jsutils/inspect.mjs\";\nimport devAssert from \"../jsutils/devAssert.mjs\";\nimport instanceOf from \"../jsutils/instanceOf.mjs\";\n\n/**\n * A representation of source input to GraphQL. The `name` and `locationOffset` parameters are\n * optional, but they are useful for clients who store GraphQL documents in source files.\n * For example, if the GraphQL input starts at line 40 in a file named `Foo.graphql`, it might\n * be useful for `name` to be `\"Foo.graphql\"` and location to be `{ line: 40, column: 1 }`.\n * The `line` and `column` properties in `locationOffset` are 1-indexed.\n */\nexport class Source {\n constructor(body, name = 'GraphQL request', locationOffset = {\n line: 1,\n column: 1\n }) {\n typeof body === 'string' || devAssert(0, `Body must be a string. Received: ${inspect(body)}.`);\n this.body = body;\n this.name = name;\n this.locationOffset = locationOffset;\n this.locationOffset.line > 0 || devAssert(0, 'line in locationOffset is 1-indexed and must be positive.');\n this.locationOffset.column > 0 || devAssert(0, 'column in locationOffset is 1-indexed and must be positive.');\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'Source';\n }\n\n}\n/**\n * Test if the given value is a Source object.\n *\n * @internal\n */\n\n// eslint-disable-next-line no-redeclare\nexport function isSource(source) {\n return instanceOf(source, Source);\n}\n","/**\n * The set of allowed directive location values.\n */\nexport const DirectiveLocation = Object.freeze({\n // Request Definitions\n QUERY: 'QUERY',\n MUTATION: 'MUTATION',\n SUBSCRIPTION: 'SUBSCRIPTION',\n FIELD: 'FIELD',\n FRAGMENT_DEFINITION: 'FRAGMENT_DEFINITION',\n FRAGMENT_SPREAD: 'FRAGMENT_SPREAD',\n INLINE_FRAGMENT: 'INLINE_FRAGMENT',\n VARIABLE_DEFINITION: 'VARIABLE_DEFINITION',\n // Type System Definitions\n SCHEMA: 'SCHEMA',\n SCALAR: 'SCALAR',\n OBJECT: 'OBJECT',\n FIELD_DEFINITION: 'FIELD_DEFINITION',\n ARGUMENT_DEFINITION: 'ARGUMENT_DEFINITION',\n INTERFACE: 'INTERFACE',\n UNION: 'UNION',\n ENUM: 'ENUM',\n ENUM_VALUE: 'ENUM_VALUE',\n INPUT_OBJECT: 'INPUT_OBJECT',\n INPUT_FIELD_DEFINITION: 'INPUT_FIELD_DEFINITION'\n});\n/**\n * The enum type representing the directive location values.\n */\n","/**\n * Produces the value of a block string from its parsed raw value, similar to\n * CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc.\n *\n * This implements the GraphQL spec's BlockStringValue() static algorithm.\n *\n * @internal\n */\nexport function dedentBlockStringValue(rawString) {\n // Expand a block string's raw value into independent lines.\n const lines = rawString.split(/\\r\\n|[\\n\\r]/g); // Remove common indentation from all lines but first.\n\n const commonIndent = getBlockStringIndentation(rawString);\n\n if (commonIndent !== 0) {\n for (let i = 1; i < lines.length; i++) {\n lines[i] = lines[i].slice(commonIndent);\n }\n } // Remove leading and trailing blank lines.\n\n\n let startLine = 0;\n\n while (startLine < lines.length && isBlank(lines[startLine])) {\n ++startLine;\n }\n\n let endLine = lines.length;\n\n while (endLine > startLine && isBlank(lines[endLine - 1])) {\n --endLine;\n } // Return a string of the lines joined with U+000A.\n\n\n return lines.slice(startLine, endLine).join('\\n');\n}\n\nfunction isBlank(str) {\n for (let i = 0; i < str.length; ++i) {\n if (str[i] !== ' ' && str[i] !== '\\t') {\n return false;\n }\n }\n\n return true;\n}\n/**\n * @internal\n */\n\n\nexport function getBlockStringIndentation(value) {\n let isFirstLine = true;\n let isEmptyLine = true;\n let indent = 0;\n let commonIndent = null;\n\n for (let i = 0; i < value.length; ++i) {\n switch (value.charCodeAt(i)) {\n case 13:\n // \\r\n if (value.charCodeAt(i + 1) === 10) {\n ++i; // skip \\r\\n as one symbol\n }\n\n // falls through\n\n case 10:\n // \\n\n isFirstLine = false;\n isEmptyLine = true;\n indent = 0;\n break;\n\n case 9: // \\t\n\n case 32:\n // \n ++indent;\n break;\n\n default:\n if (isEmptyLine && !isFirstLine && (commonIndent === null || indent < commonIndent)) {\n commonIndent = indent;\n }\n\n isEmptyLine = false;\n }\n }\n\n return commonIndent ?? 0;\n}\n/**\n * Print a block string in the indented block form by adding a leading and\n * trailing blank line. However, if a block string starts with whitespace and is\n * a single-line, adding a leading blank line would strip that whitespace.\n *\n * @internal\n */\n\nexport function printBlockString(value, indentation = '', preferMultipleLines = false) {\n const isSingleLine = value.indexOf('\\n') === -1;\n const hasLeadingSpace = value[0] === ' ' || value[0] === '\\t';\n const hasTrailingQuote = value[value.length - 1] === '\"';\n const hasTrailingSlash = value[value.length - 1] === '\\\\';\n const printAsMultipleLines = !isSingleLine || hasTrailingQuote || hasTrailingSlash || preferMultipleLines;\n let result = ''; // Format a multi-line block quote to account for leading space.\n\n if (printAsMultipleLines && !(isSingleLine && hasLeadingSpace)) {\n result += '\\n' + indentation;\n }\n\n result += indentation ? value.replace(/\\n/g, '\\n' + indentation) : value;\n\n if (printAsMultipleLines) {\n result += '\\n';\n }\n\n return '\"\"\"' + result.replace(/\"\"\"/g, '\\\\\"\"\"') + '\"\"\"';\n}\n","import { syntaxError } from \"../error/syntaxError.mjs\";\nimport { Token } from \"./ast.mjs\";\nimport { TokenKind } from \"./tokenKind.mjs\";\nimport { dedentBlockStringValue } from \"./blockString.mjs\";\n/**\n * Given a Source object, creates a Lexer for that source.\n * A Lexer is a stateful stream generator in that every time\n * it is advanced, it returns the next token in the Source. Assuming the\n * source lexes, the final Token emitted by the lexer will be of kind\n * EOF, after which the lexer will repeatedly return the same EOF token\n * whenever called.\n */\n\nexport class Lexer {\n /**\n * The previously focused non-ignored token.\n */\n\n /**\n * The currently focused non-ignored token.\n */\n\n /**\n * The (1-indexed) line containing the current token.\n */\n\n /**\n * The character offset at which the current line begins.\n */\n constructor(source) {\n const startOfFileToken = new Token(TokenKind.SOF, 0, 0, 0, 0, null);\n this.source = source;\n this.lastToken = startOfFileToken;\n this.token = startOfFileToken;\n this.line = 1;\n this.lineStart = 0;\n }\n /**\n * Advances the token stream to the next non-ignored token.\n */\n\n\n advance() {\n this.lastToken = this.token;\n const token = this.token = this.lookahead();\n return token;\n }\n /**\n * Looks ahead and returns the next non-ignored token, but does not change\n * the state of Lexer.\n */\n\n\n lookahead() {\n let token = this.token;\n\n if (token.kind !== TokenKind.EOF) {\n do {\n // Note: next is only mutable during parsing, so we cast to allow this.\n token = token.next ?? (token.next = readToken(this, token));\n } while (token.kind === TokenKind.COMMENT);\n }\n\n return token;\n }\n\n}\n/**\n * @internal\n */\n\nexport function isPunctuatorTokenKind(kind) {\n return kind === TokenKind.BANG || kind === TokenKind.DOLLAR || kind === TokenKind.AMP || kind === TokenKind.PAREN_L || kind === TokenKind.PAREN_R || kind === TokenKind.SPREAD || kind === TokenKind.COLON || kind === TokenKind.EQUALS || kind === TokenKind.AT || kind === TokenKind.BRACKET_L || kind === TokenKind.BRACKET_R || kind === TokenKind.BRACE_L || kind === TokenKind.PIPE || kind === TokenKind.BRACE_R;\n}\n\nfunction printCharCode(code) {\n return (// NaN/undefined represents access beyond the end of the file.\n isNaN(code) ? TokenKind.EOF : // Trust JSON for ASCII.\n code < 0x007f ? JSON.stringify(String.fromCharCode(code)) : // Otherwise print the escaped form.\n `\"\\\\u${('00' + code.toString(16).toUpperCase()).slice(-4)}\"`\n );\n}\n/**\n * Gets the next token from the source starting at the given position.\n *\n * This skips over whitespace until it finds the next lexable token, then lexes\n * punctuators immediately or calls the appropriate helper function for more\n * complicated tokens.\n */\n\n\nfunction readToken(lexer, prev) {\n const source = lexer.source;\n const body = source.body;\n const bodyLength = body.length;\n let pos = prev.end;\n\n while (pos < bodyLength) {\n const code = body.charCodeAt(pos);\n const line = lexer.line;\n const col = 1 + pos - lexer.lineStart; // SourceCharacter\n\n switch (code) {\n case 0xfeff: // \n\n case 9: // \\t\n\n case 32: // \n\n case 44:\n // ,\n ++pos;\n continue;\n\n case 10:\n // \\n\n ++pos;\n ++lexer.line;\n lexer.lineStart = pos;\n continue;\n\n case 13:\n // \\r\n if (body.charCodeAt(pos + 1) === 10) {\n pos += 2;\n } else {\n ++pos;\n }\n\n ++lexer.line;\n lexer.lineStart = pos;\n continue;\n\n case 33:\n // !\n return new Token(TokenKind.BANG, pos, pos + 1, line, col, prev);\n\n case 35:\n // #\n return readComment(source, pos, line, col, prev);\n\n case 36:\n // $\n return new Token(TokenKind.DOLLAR, pos, pos + 1, line, col, prev);\n\n case 38:\n // &\n return new Token(TokenKind.AMP, pos, pos + 1, line, col, prev);\n\n case 40:\n // (\n return new Token(TokenKind.PAREN_L, pos, pos + 1, line, col, prev);\n\n case 41:\n // )\n return new Token(TokenKind.PAREN_R, pos, pos + 1, line, col, prev);\n\n case 46:\n // .\n if (body.charCodeAt(pos + 1) === 46 && body.charCodeAt(pos + 2) === 46) {\n return new Token(TokenKind.SPREAD, pos, pos + 3, line, col, prev);\n }\n\n break;\n\n case 58:\n // :\n return new Token(TokenKind.COLON, pos, pos + 1, line, col, prev);\n\n case 61:\n // =\n return new Token(TokenKind.EQUALS, pos, pos + 1, line, col, prev);\n\n case 64:\n // @\n return new Token(TokenKind.AT, pos, pos + 1, line, col, prev);\n\n case 91:\n // [\n return new Token(TokenKind.BRACKET_L, pos, pos + 1, line, col, prev);\n\n case 93:\n // ]\n return new Token(TokenKind.BRACKET_R, pos, pos + 1, line, col, prev);\n\n case 123:\n // {\n return new Token(TokenKind.BRACE_L, pos, pos + 1, line, col, prev);\n\n case 124:\n // |\n return new Token(TokenKind.PIPE, pos, pos + 1, line, col, prev);\n\n case 125:\n // }\n return new Token(TokenKind.BRACE_R, pos, pos + 1, line, col, prev);\n\n case 34:\n // \"\n if (body.charCodeAt(pos + 1) === 34 && body.charCodeAt(pos + 2) === 34) {\n return readBlockString(source, pos, line, col, prev, lexer);\n }\n\n return readString(source, pos, line, col, prev);\n\n case 45: // -\n\n case 48: // 0\n\n case 49: // 1\n\n case 50: // 2\n\n case 51: // 3\n\n case 52: // 4\n\n case 53: // 5\n\n case 54: // 6\n\n case 55: // 7\n\n case 56: // 8\n\n case 57:\n // 9\n return readNumber(source, pos, code, line, col, prev);\n\n case 65: // A\n\n case 66: // B\n\n case 67: // C\n\n case 68: // D\n\n case 69: // E\n\n case 70: // F\n\n case 71: // G\n\n case 72: // H\n\n case 73: // I\n\n case 74: // J\n\n case 75: // K\n\n case 76: // L\n\n case 77: // M\n\n case 78: // N\n\n case 79: // O\n\n case 80: // P\n\n case 81: // Q\n\n case 82: // R\n\n case 83: // S\n\n case 84: // T\n\n case 85: // U\n\n case 86: // V\n\n case 87: // W\n\n case 88: // X\n\n case 89: // Y\n\n case 90: // Z\n\n case 95: // _\n\n case 97: // a\n\n case 98: // b\n\n case 99: // c\n\n case 100: // d\n\n case 101: // e\n\n case 102: // f\n\n case 103: // g\n\n case 104: // h\n\n case 105: // i\n\n case 106: // j\n\n case 107: // k\n\n case 108: // l\n\n case 109: // m\n\n case 110: // n\n\n case 111: // o\n\n case 112: // p\n\n case 113: // q\n\n case 114: // r\n\n case 115: // s\n\n case 116: // t\n\n case 117: // u\n\n case 118: // v\n\n case 119: // w\n\n case 120: // x\n\n case 121: // y\n\n case 122:\n // z\n return readName(source, pos, line, col, prev);\n }\n\n throw syntaxError(source, pos, unexpectedCharacterMessage(code));\n }\n\n const line = lexer.line;\n const col = 1 + pos - lexer.lineStart;\n return new Token(TokenKind.EOF, bodyLength, bodyLength, line, col, prev);\n}\n/**\n * Report a message that an unexpected character was encountered.\n */\n\n\nfunction unexpectedCharacterMessage(code) {\n if (code < 0x0020 && code !== 0x0009 && code !== 0x000a && code !== 0x000d) {\n return `Cannot contain the invalid character ${printCharCode(code)}.`;\n }\n\n if (code === 39) {\n // '\n return 'Unexpected single quote character (\\'), did you mean to use a double quote (\")?';\n }\n\n return `Cannot parse the unexpected character ${printCharCode(code)}.`;\n}\n/**\n * Reads a comment token from the source file.\n *\n * #[\\u0009\\u0020-\\uFFFF]*\n */\n\n\nfunction readComment(source, start, line, col, prev) {\n const body = source.body;\n let code;\n let position = start;\n\n do {\n code = body.charCodeAt(++position);\n } while (!isNaN(code) && ( // SourceCharacter but not LineTerminator\n code > 0x001f || code === 0x0009));\n\n return new Token(TokenKind.COMMENT, start, position, line, col, prev, body.slice(start + 1, position));\n}\n/**\n * Reads a number token from the source file, either a float\n * or an int depending on whether a decimal point appears.\n *\n * Int: -?(0|[1-9][0-9]*)\n * Float: -?(0|[1-9][0-9]*)(\\.[0-9]+)?((E|e)(+|-)?[0-9]+)?\n */\n\n\nfunction readNumber(source, start, firstCode, line, col, prev) {\n const body = source.body;\n let code = firstCode;\n let position = start;\n let isFloat = false;\n\n if (code === 45) {\n // -\n code = body.charCodeAt(++position);\n }\n\n if (code === 48) {\n // 0\n code = body.charCodeAt(++position);\n\n if (code >= 48 && code <= 57) {\n throw syntaxError(source, position, `Invalid number, unexpected digit after 0: ${printCharCode(code)}.`);\n }\n } else {\n position = readDigits(source, position, code);\n code = body.charCodeAt(position);\n }\n\n if (code === 46) {\n // .\n isFloat = true;\n code = body.charCodeAt(++position);\n position = readDigits(source, position, code);\n code = body.charCodeAt(position);\n }\n\n if (code === 69 || code === 101) {\n // E e\n isFloat = true;\n code = body.charCodeAt(++position);\n\n if (code === 43 || code === 45) {\n // + -\n code = body.charCodeAt(++position);\n }\n\n position = readDigits(source, position, code);\n code = body.charCodeAt(position);\n } // Numbers cannot be followed by . or NameStart\n\n\n if (code === 46 || isNameStart(code)) {\n throw syntaxError(source, position, `Invalid number, expected digit but got: ${printCharCode(code)}.`);\n }\n\n return new Token(isFloat ? TokenKind.FLOAT : TokenKind.INT, start, position, line, col, prev, body.slice(start, position));\n}\n/**\n * Returns the new position in the source after reading digits.\n */\n\n\nfunction readDigits(source, start, firstCode) {\n const body = source.body;\n let position = start;\n let code = firstCode;\n\n if (code >= 48 && code <= 57) {\n // 0 - 9\n do {\n code = body.charCodeAt(++position);\n } while (code >= 48 && code <= 57); // 0 - 9\n\n\n return position;\n }\n\n throw syntaxError(source, position, `Invalid number, expected digit but got: ${printCharCode(code)}.`);\n}\n/**\n * Reads a string token from the source file.\n *\n * \"([^\"\\\\\\u000A\\u000D]|(\\\\(u[0-9a-fA-F]{4}|[\"\\\\/bfnrt])))*\"\n */\n\n\nfunction readString(source, start, line, col, prev) {\n const body = source.body;\n let position = start + 1;\n let chunkStart = position;\n let code = 0;\n let value = '';\n\n while (position < body.length && !isNaN(code = body.charCodeAt(position)) && // not LineTerminator\n code !== 0x000a && code !== 0x000d) {\n // Closing Quote (\")\n if (code === 34) {\n value += body.slice(chunkStart, position);\n return new Token(TokenKind.STRING, start, position + 1, line, col, prev, value);\n } // SourceCharacter\n\n\n if (code < 0x0020 && code !== 0x0009) {\n throw syntaxError(source, position, `Invalid character within String: ${printCharCode(code)}.`);\n }\n\n ++position;\n\n if (code === 92) {\n // \\\n value += body.slice(chunkStart, position - 1);\n code = body.charCodeAt(position);\n\n switch (code) {\n case 34:\n value += '\"';\n break;\n\n case 47:\n value += '/';\n break;\n\n case 92:\n value += '\\\\';\n break;\n\n case 98:\n value += '\\b';\n break;\n\n case 102:\n value += '\\f';\n break;\n\n case 110:\n value += '\\n';\n break;\n\n case 114:\n value += '\\r';\n break;\n\n case 116:\n value += '\\t';\n break;\n\n case 117:\n {\n // uXXXX\n const charCode = uniCharCode(body.charCodeAt(position + 1), body.charCodeAt(position + 2), body.charCodeAt(position + 3), body.charCodeAt(position + 4));\n\n if (charCode < 0) {\n const invalidSequence = body.slice(position + 1, position + 5);\n throw syntaxError(source, position, `Invalid character escape sequence: \\\\u${invalidSequence}.`);\n }\n\n value += String.fromCharCode(charCode);\n position += 4;\n break;\n }\n\n default:\n throw syntaxError(source, position, `Invalid character escape sequence: \\\\${String.fromCharCode(code)}.`);\n }\n\n ++position;\n chunkStart = position;\n }\n }\n\n throw syntaxError(source, position, 'Unterminated string.');\n}\n/**\n * Reads a block string token from the source file.\n *\n * \"\"\"(\"?\"?(\\\\\"\"\"|\\\\(?!=\"\"\")|[^\"\\\\]))*\"\"\"\n */\n\n\nfunction readBlockString(source, start, line, col, prev, lexer) {\n const body = source.body;\n let position = start + 3;\n let chunkStart = position;\n let code = 0;\n let rawValue = '';\n\n while (position < body.length && !isNaN(code = body.charCodeAt(position))) {\n // Closing Triple-Quote (\"\"\")\n if (code === 34 && body.charCodeAt(position + 1) === 34 && body.charCodeAt(position + 2) === 34) {\n rawValue += body.slice(chunkStart, position);\n return new Token(TokenKind.BLOCK_STRING, start, position + 3, line, col, prev, dedentBlockStringValue(rawValue));\n } // SourceCharacter\n\n\n if (code < 0x0020 && code !== 0x0009 && code !== 0x000a && code !== 0x000d) {\n throw syntaxError(source, position, `Invalid character within String: ${printCharCode(code)}.`);\n }\n\n if (code === 10) {\n // new line\n ++position;\n ++lexer.line;\n lexer.lineStart = position;\n } else if (code === 13) {\n // carriage return\n if (body.charCodeAt(position + 1) === 10) {\n position += 2;\n } else {\n ++position;\n }\n\n ++lexer.line;\n lexer.lineStart = position;\n } else if ( // Escape Triple-Quote (\\\"\"\")\n code === 92 && body.charCodeAt(position + 1) === 34 && body.charCodeAt(position + 2) === 34 && body.charCodeAt(position + 3) === 34) {\n rawValue += body.slice(chunkStart, position) + '\"\"\"';\n position += 4;\n chunkStart = position;\n } else {\n ++position;\n }\n }\n\n throw syntaxError(source, position, 'Unterminated string.');\n}\n/**\n * Converts four hexadecimal chars to the integer that the\n * string represents. For example, uniCharCode('0','0','0','f')\n * will return 15, and uniCharCode('0','0','f','f') returns 255.\n *\n * Returns a negative number on error, if a char was invalid.\n *\n * This is implemented by noting that char2hex() returns -1 on error,\n * which means the result of ORing the char2hex() will also be negative.\n */\n\n\nfunction uniCharCode(a, b, c, d) {\n return char2hex(a) << 12 | char2hex(b) << 8 | char2hex(c) << 4 | char2hex(d);\n}\n/**\n * Converts a hex character to its integer value.\n * '0' becomes 0, '9' becomes 9\n * 'A' becomes 10, 'F' becomes 15\n * 'a' becomes 10, 'f' becomes 15\n *\n * Returns -1 on error.\n */\n\n\nfunction char2hex(a) {\n return a >= 48 && a <= 57 ? a - 48 // 0-9\n : a >= 65 && a <= 70 ? a - 55 // A-F\n : a >= 97 && a <= 102 ? a - 87 // a-f\n : -1;\n}\n/**\n * Reads an alphanumeric + underscore name from the source.\n *\n * [_A-Za-z][_0-9A-Za-z]*\n */\n\n\nfunction readName(source, start, line, col, prev) {\n const body = source.body;\n const bodyLength = body.length;\n let position = start + 1;\n let code = 0;\n\n while (position !== bodyLength && !isNaN(code = body.charCodeAt(position)) && (code === 95 || // _\n code >= 48 && code <= 57 || // 0-9\n code >= 65 && code <= 90 || // A-Z\n code >= 97 && code <= 122) // a-z\n ) {\n ++position;\n }\n\n return new Token(TokenKind.NAME, start, position, line, col, prev, body.slice(start, position));\n} // _ A-Z a-z\n\n\nfunction isNameStart(code) {\n return code === 95 || code >= 65 && code <= 90 || code >= 97 && code <= 122;\n}\n","import { syntaxError } from \"../error/syntaxError.mjs\";\nimport { Kind } from \"./kinds.mjs\";\nimport { Location } from \"./ast.mjs\";\nimport { TokenKind } from \"./tokenKind.mjs\";\nimport { Source, isSource } from \"./source.mjs\";\nimport { DirectiveLocation } from \"./directiveLocation.mjs\";\nimport { Lexer, isPunctuatorTokenKind } from \"./lexer.mjs\";\n/**\n * Configuration options to control parser behavior\n */\n\n/**\n * Given a GraphQL source, parses it into a Document.\n * Throws GraphQLError if a syntax error is encountered.\n */\nexport function parse(source, options) {\n const parser = new Parser(source, options);\n return parser.parseDocument();\n}\n/**\n * Given a string containing a GraphQL value (ex. `[42]`), parse the AST for\n * that value.\n * Throws GraphQLError if a syntax error is encountered.\n *\n * This is useful within tools that operate upon GraphQL Values directly and\n * in isolation of complete GraphQL documents.\n *\n * Consider providing the results to the utility function: valueFromAST().\n */\n\nexport function parseValue(source, options) {\n const parser = new Parser(source, options);\n parser.expectToken(TokenKind.SOF);\n const value = parser.parseValueLiteral(false);\n parser.expectToken(TokenKind.EOF);\n return value;\n}\n/**\n * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for\n * that type.\n * Throws GraphQLError if a syntax error is encountered.\n *\n * This is useful within tools that operate upon GraphQL Types directly and\n * in isolation of complete GraphQL documents.\n *\n * Consider providing the results to the utility function: typeFromAST().\n */\n\nexport function parseType(source, options) {\n const parser = new Parser(source, options);\n parser.expectToken(TokenKind.SOF);\n const type = parser.parseTypeReference();\n parser.expectToken(TokenKind.EOF);\n return type;\n}\n/**\n * This class is exported only to assist people in implementing their own parsers\n * without duplicating too much code and should be used only as last resort for cases\n * such as experimental syntax or if certain features could not be contributed upstream.\n *\n * It is still part of the internal API and is versioned, so any changes to it are never\n * considered breaking changes. If you still need to support multiple versions of the\n * library, please use the `versionInfo` variable for version detection.\n *\n * @internal\n */\n\nexport class Parser {\n constructor(source, options) {\n const sourceObj = isSource(source) ? source : new Source(source);\n this._lexer = new Lexer(sourceObj);\n this._options = options;\n }\n /**\n * Converts a name lex token into a name parse node.\n */\n\n\n parseName() {\n const token = this.expectToken(TokenKind.NAME);\n return {\n kind: Kind.NAME,\n value: token.value,\n loc: this.loc(token)\n };\n } // Implements the parsing rules in the Document section.\n\n /**\n * Document : Definition+\n */\n\n\n parseDocument() {\n const start = this._lexer.token;\n return {\n kind: Kind.DOCUMENT,\n definitions: this.many(TokenKind.SOF, this.parseDefinition, TokenKind.EOF),\n loc: this.loc(start)\n };\n }\n /**\n * Definition :\n * - ExecutableDefinition\n * - TypeSystemDefinition\n * - TypeSystemExtension\n *\n * ExecutableDefinition :\n * - OperationDefinition\n * - FragmentDefinition\n */\n\n\n parseDefinition() {\n if (this.peek(TokenKind.NAME)) {\n switch (this._lexer.token.value) {\n case 'query':\n case 'mutation':\n case 'subscription':\n return this.parseOperationDefinition();\n\n case 'fragment':\n return this.parseFragmentDefinition();\n\n case 'schema':\n case 'scalar':\n case 'type':\n case 'interface':\n case 'union':\n case 'enum':\n case 'input':\n case 'directive':\n return this.parseTypeSystemDefinition();\n\n case 'extend':\n return this.parseTypeSystemExtension();\n }\n } else if (this.peek(TokenKind.BRACE_L)) {\n return this.parseOperationDefinition();\n } else if (this.peekDescription()) {\n return this.parseTypeSystemDefinition();\n }\n\n throw this.unexpected();\n } // Implements the parsing rules in the Operations section.\n\n /**\n * OperationDefinition :\n * - SelectionSet\n * - OperationType Name? VariableDefinitions? Directives? SelectionSet\n */\n\n\n parseOperationDefinition() {\n const start = this._lexer.token;\n\n if (this.peek(TokenKind.BRACE_L)) {\n return {\n kind: Kind.OPERATION_DEFINITION,\n operation: 'query',\n name: undefined,\n variableDefinitions: [],\n directives: [],\n selectionSet: this.parseSelectionSet(),\n loc: this.loc(start)\n };\n }\n\n const operation = this.parseOperationType();\n let name;\n\n if (this.peek(TokenKind.NAME)) {\n name = this.parseName();\n }\n\n return {\n kind: Kind.OPERATION_DEFINITION,\n operation,\n name,\n variableDefinitions: this.parseVariableDefinitions(),\n directives: this.parseDirectives(false),\n selectionSet: this.parseSelectionSet(),\n loc: this.loc(start)\n };\n }\n /**\n * OperationType : one of query mutation subscription\n */\n\n\n parseOperationType() {\n const operationToken = this.expectToken(TokenKind.NAME);\n\n switch (operationToken.value) {\n case 'query':\n return 'query';\n\n case 'mutation':\n return 'mutation';\n\n case 'subscription':\n return 'subscription';\n }\n\n throw this.unexpected(operationToken);\n }\n /**\n * VariableDefinitions : ( VariableDefinition+ )\n */\n\n\n parseVariableDefinitions() {\n return this.optionalMany(TokenKind.PAREN_L, this.parseVariableDefinition, TokenKind.PAREN_R);\n }\n /**\n * VariableDefinition : Variable : Type DefaultValue? Directives[Const]?\n */\n\n\n parseVariableDefinition() {\n const start = this._lexer.token;\n return {\n kind: Kind.VARIABLE_DEFINITION,\n variable: this.parseVariable(),\n type: (this.expectToken(TokenKind.COLON), this.parseTypeReference()),\n defaultValue: this.expectOptionalToken(TokenKind.EQUALS) ? this.parseValueLiteral(true) : undefined,\n directives: this.parseDirectives(true),\n loc: this.loc(start)\n };\n }\n /**\n * Variable : $ Name\n */\n\n\n parseVariable() {\n const start = this._lexer.token;\n this.expectToken(TokenKind.DOLLAR);\n return {\n kind: Kind.VARIABLE,\n name: this.parseName(),\n loc: this.loc(start)\n };\n }\n /**\n * SelectionSet : { Selection+ }\n */\n\n\n parseSelectionSet() {\n const start = this._lexer.token;\n return {\n kind: Kind.SELECTION_SET,\n selections: this.many(TokenKind.BRACE_L, this.parseSelection, TokenKind.BRACE_R),\n loc: this.loc(start)\n };\n }\n /**\n * Selection :\n * - Field\n * - FragmentSpread\n * - InlineFragment\n */\n\n\n parseSelection() {\n return this.peek(TokenKind.SPREAD) ? this.parseFragment() : this.parseField();\n }\n /**\n * Field : Alias? Name Arguments? Directives? SelectionSet?\n *\n * Alias : Name :\n */\n\n\n parseField() {\n const start = this._lexer.token;\n const nameOrAlias = this.parseName();\n let alias;\n let name;\n\n if (this.expectOptionalToken(TokenKind.COLON)) {\n alias = nameOrAlias;\n name = this.parseName();\n } else {\n name = nameOrAlias;\n }\n\n return {\n kind: Kind.FIELD,\n alias,\n name,\n arguments: this.parseArguments(false),\n directives: this.parseDirectives(false),\n selectionSet: this.peek(TokenKind.BRACE_L) ? this.parseSelectionSet() : undefined,\n loc: this.loc(start)\n };\n }\n /**\n * Arguments[Const] : ( Argument[?Const]+ )\n */\n\n\n parseArguments(isConst) {\n const item = isConst ? this.parseConstArgument : this.parseArgument;\n return this.optionalMany(TokenKind.PAREN_L, item, TokenKind.PAREN_R);\n }\n /**\n * Argument[Const] : Name : Value[?Const]\n */\n\n\n parseArgument() {\n const start = this._lexer.token;\n const name = this.parseName();\n this.expectToken(TokenKind.COLON);\n return {\n kind: Kind.ARGUMENT,\n name,\n value: this.parseValueLiteral(false),\n loc: this.loc(start)\n };\n }\n\n parseConstArgument() {\n const start = this._lexer.token;\n return {\n kind: Kind.ARGUMENT,\n name: this.parseName(),\n value: (this.expectToken(TokenKind.COLON), this.parseValueLiteral(true)),\n loc: this.loc(start)\n };\n } // Implements the parsing rules in the Fragments section.\n\n /**\n * Corresponds to both FragmentSpread and InlineFragment in the spec.\n *\n * FragmentSpread : ... FragmentName Directives?\n *\n * InlineFragment : ... TypeCondition? Directives? SelectionSet\n */\n\n\n parseFragment() {\n const start = this._lexer.token;\n this.expectToken(TokenKind.SPREAD);\n const hasTypeCondition = this.expectOptionalKeyword('on');\n\n if (!hasTypeCondition && this.peek(TokenKind.NAME)) {\n return {\n kind: Kind.FRAGMENT_SPREAD,\n name: this.parseFragmentName(),\n directives: this.parseDirectives(false),\n loc: this.loc(start)\n };\n }\n\n return {\n kind: Kind.INLINE_FRAGMENT,\n typeCondition: hasTypeCondition ? this.parseNamedType() : undefined,\n directives: this.parseDirectives(false),\n selectionSet: this.parseSelectionSet(),\n loc: this.loc(start)\n };\n }\n /**\n * FragmentDefinition :\n * - fragment FragmentName on TypeCondition Directives? SelectionSet\n *\n * TypeCondition : NamedType\n */\n\n\n parseFragmentDefinition() {\n const start = this._lexer.token;\n this.expectKeyword('fragment'); // Experimental support for defining variables within fragments changes\n // the grammar of FragmentDefinition:\n // - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet\n\n if (this._options?.experimentalFragmentVariables === true) {\n return {\n kind: Kind.FRAGMENT_DEFINITION,\n name: this.parseFragmentName(),\n variableDefinitions: this.parseVariableDefinitions(),\n typeCondition: (this.expectKeyword('on'), this.parseNamedType()),\n directives: this.parseDirectives(false),\n selectionSet: this.parseSelectionSet(),\n loc: this.loc(start)\n };\n }\n\n return {\n kind: Kind.FRAGMENT_DEFINITION,\n name: this.parseFragmentName(),\n typeCondition: (this.expectKeyword('on'), this.parseNamedType()),\n directives: this.parseDirectives(false),\n selectionSet: this.parseSelectionSet(),\n loc: this.loc(start)\n };\n }\n /**\n * FragmentName : Name but not `on`\n */\n\n\n parseFragmentName() {\n if (this._lexer.token.value === 'on') {\n throw this.unexpected();\n }\n\n return this.parseName();\n } // Implements the parsing rules in the Values section.\n\n /**\n * Value[Const] :\n * - [~Const] Variable\n * - IntValue\n * - FloatValue\n * - StringValue\n * - BooleanValue\n * - NullValue\n * - EnumValue\n * - ListValue[?Const]\n * - ObjectValue[?Const]\n *\n * BooleanValue : one of `true` `false`\n *\n * NullValue : `null`\n *\n * EnumValue : Name but not `true`, `false` or `null`\n */\n\n\n parseValueLiteral(isConst) {\n const token = this._lexer.token;\n\n switch (token.kind) {\n case TokenKind.BRACKET_L:\n return this.parseList(isConst);\n\n case TokenKind.BRACE_L:\n return this.parseObject(isConst);\n\n case TokenKind.INT:\n this._lexer.advance();\n\n return {\n kind: Kind.INT,\n value: token.value,\n loc: this.loc(token)\n };\n\n case TokenKind.FLOAT:\n this._lexer.advance();\n\n return {\n kind: Kind.FLOAT,\n value: token.value,\n loc: this.loc(token)\n };\n\n case TokenKind.STRING:\n case TokenKind.BLOCK_STRING:\n return this.parseStringLiteral();\n\n case TokenKind.NAME:\n this._lexer.advance();\n\n switch (token.value) {\n case 'true':\n return {\n kind: Kind.BOOLEAN,\n value: true,\n loc: this.loc(token)\n };\n\n case 'false':\n return {\n kind: Kind.BOOLEAN,\n value: false,\n loc: this.loc(token)\n };\n\n case 'null':\n return {\n kind: Kind.NULL,\n loc: this.loc(token)\n };\n\n default:\n return {\n kind: Kind.ENUM,\n value: token.value,\n loc: this.loc(token)\n };\n }\n\n case TokenKind.DOLLAR:\n if (!isConst) {\n return this.parseVariable();\n }\n\n break;\n }\n\n throw this.unexpected();\n }\n\n parseStringLiteral() {\n const token = this._lexer.token;\n\n this._lexer.advance();\n\n return {\n kind: Kind.STRING,\n value: token.value,\n block: token.kind === TokenKind.BLOCK_STRING,\n loc: this.loc(token)\n };\n }\n /**\n * ListValue[Const] :\n * - [ ]\n * - [ Value[?Const]+ ]\n */\n\n\n parseList(isConst) {\n const start = this._lexer.token;\n\n const item = () => this.parseValueLiteral(isConst);\n\n return {\n kind: Kind.LIST,\n values: this.any(TokenKind.BRACKET_L, item, TokenKind.BRACKET_R),\n loc: this.loc(start)\n };\n }\n /**\n * ObjectValue[Const] :\n * - { }\n * - { ObjectField[?Const]+ }\n */\n\n\n parseObject(isConst) {\n const start = this._lexer.token;\n\n const item = () => this.parseObjectField(isConst);\n\n return {\n kind: Kind.OBJECT,\n fields: this.any(TokenKind.BRACE_L, item, TokenKind.BRACE_R),\n loc: this.loc(start)\n };\n }\n /**\n * ObjectField[Const] : Name : Value[?Const]\n */\n\n\n parseObjectField(isConst) {\n const start = this._lexer.token;\n const name = this.parseName();\n this.expectToken(TokenKind.COLON);\n return {\n kind: Kind.OBJECT_FIELD,\n name,\n value: this.parseValueLiteral(isConst),\n loc: this.loc(start)\n };\n } // Implements the parsing rules in the Directives section.\n\n /**\n * Directives[Const] : Directive[?Const]+\n */\n\n\n parseDirectives(isConst) {\n const directives = [];\n\n while (this.peek(TokenKind.AT)) {\n directives.push(this.parseDirective(isConst));\n }\n\n return directives;\n }\n /**\n * Directive[Const] : @ Name Arguments[?Const]?\n */\n\n\n parseDirective(isConst) {\n const start = this._lexer.token;\n this.expectToken(TokenKind.AT);\n return {\n kind: Kind.DIRECTIVE,\n name: this.parseName(),\n arguments: this.parseArguments(isConst),\n loc: this.loc(start)\n };\n } // Implements the parsing rules in the Types section.\n\n /**\n * Type :\n * - NamedType\n * - ListType\n * - NonNullType\n */\n\n\n parseTypeReference() {\n const start = this._lexer.token;\n let type;\n\n if (this.expectOptionalToken(TokenKind.BRACKET_L)) {\n type = this.parseTypeReference();\n this.expectToken(TokenKind.BRACKET_R);\n type = {\n kind: Kind.LIST_TYPE,\n type,\n loc: this.loc(start)\n };\n } else {\n type = this.parseNamedType();\n }\n\n if (this.expectOptionalToken(TokenKind.BANG)) {\n return {\n kind: Kind.NON_NULL_TYPE,\n type,\n loc: this.loc(start)\n };\n }\n\n return type;\n }\n /**\n * NamedType : Name\n */\n\n\n parseNamedType() {\n const start = this._lexer.token;\n return {\n kind: Kind.NAMED_TYPE,\n name: this.parseName(),\n loc: this.loc(start)\n };\n } // Implements the parsing rules in the Type Definition section.\n\n /**\n * TypeSystemDefinition :\n * - SchemaDefinition\n * - TypeDefinition\n * - DirectiveDefinition\n *\n * TypeDefinition :\n * - ScalarTypeDefinition\n * - ObjectTypeDefinition\n * - InterfaceTypeDefinition\n * - UnionTypeDefinition\n * - EnumTypeDefinition\n * - InputObjectTypeDefinition\n */\n\n\n parseTypeSystemDefinition() {\n // Many definitions begin with a description and require a lookahead.\n const keywordToken = this.peekDescription() ? this._lexer.lookahead() : this._lexer.token;\n\n if (keywordToken.kind === TokenKind.NAME) {\n switch (keywordToken.value) {\n case 'schema':\n return this.parseSchemaDefinition();\n\n case 'scalar':\n return this.parseScalarTypeDefinition();\n\n case 'type':\n return this.parseObjectTypeDefinition();\n\n case 'interface':\n return this.parseInterfaceTypeDefinition();\n\n case 'union':\n return this.parseUnionTypeDefinition();\n\n case 'enum':\n return this.parseEnumTypeDefinition();\n\n case 'input':\n return this.parseInputObjectTypeDefinition();\n\n case 'directive':\n return this.parseDirectiveDefinition();\n }\n }\n\n throw this.unexpected(keywordToken);\n }\n\n peekDescription() {\n return this.peek(TokenKind.STRING) || this.peek(TokenKind.BLOCK_STRING);\n }\n /**\n * Description : StringValue\n */\n\n\n parseDescription() {\n if (this.peekDescription()) {\n return this.parseStringLiteral();\n }\n }\n /**\n * SchemaDefinition : Description? schema Directives[Const]? { OperationTypeDefinition+ }\n */\n\n\n parseSchemaDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('schema');\n const directives = this.parseDirectives(true);\n const operationTypes = this.many(TokenKind.BRACE_L, this.parseOperationTypeDefinition, TokenKind.BRACE_R);\n return {\n kind: Kind.SCHEMA_DEFINITION,\n description,\n directives,\n operationTypes,\n loc: this.loc(start)\n };\n }\n /**\n * OperationTypeDefinition : OperationType : NamedType\n */\n\n\n parseOperationTypeDefinition() {\n const start = this._lexer.token;\n const operation = this.parseOperationType();\n this.expectToken(TokenKind.COLON);\n const type = this.parseNamedType();\n return {\n kind: Kind.OPERATION_TYPE_DEFINITION,\n operation,\n type,\n loc: this.loc(start)\n };\n }\n /**\n * ScalarTypeDefinition : Description? scalar Name Directives[Const]?\n */\n\n\n parseScalarTypeDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('scalar');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n return {\n kind: Kind.SCALAR_TYPE_DEFINITION,\n description,\n name,\n directives,\n loc: this.loc(start)\n };\n }\n /**\n * ObjectTypeDefinition :\n * Description?\n * type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?\n */\n\n\n parseObjectTypeDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('type');\n const name = this.parseName();\n const interfaces = this.parseImplementsInterfaces();\n const directives = this.parseDirectives(true);\n const fields = this.parseFieldsDefinition();\n return {\n kind: Kind.OBJECT_TYPE_DEFINITION,\n description,\n name,\n interfaces,\n directives,\n fields,\n loc: this.loc(start)\n };\n }\n /**\n * ImplementsInterfaces :\n * - implements `&`? NamedType\n * - ImplementsInterfaces & NamedType\n */\n\n\n parseImplementsInterfaces() {\n return this.expectOptionalKeyword('implements') ? this.delimitedMany(TokenKind.AMP, this.parseNamedType) : [];\n }\n /**\n * FieldsDefinition : { FieldDefinition+ }\n */\n\n\n parseFieldsDefinition() {\n return this.optionalMany(TokenKind.BRACE_L, this.parseFieldDefinition, TokenKind.BRACE_R);\n }\n /**\n * FieldDefinition :\n * - Description? Name ArgumentsDefinition? : Type Directives[Const]?\n */\n\n\n parseFieldDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n const name = this.parseName();\n const args = this.parseArgumentDefs();\n this.expectToken(TokenKind.COLON);\n const type = this.parseTypeReference();\n const directives = this.parseDirectives(true);\n return {\n kind: Kind.FIELD_DEFINITION,\n description,\n name,\n arguments: args,\n type,\n directives,\n loc: this.loc(start)\n };\n }\n /**\n * ArgumentsDefinition : ( InputValueDefinition+ )\n */\n\n\n parseArgumentDefs() {\n return this.optionalMany(TokenKind.PAREN_L, this.parseInputValueDef, TokenKind.PAREN_R);\n }\n /**\n * InputValueDefinition :\n * - Description? Name : Type DefaultValue? Directives[Const]?\n */\n\n\n parseInputValueDef() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n const name = this.parseName();\n this.expectToken(TokenKind.COLON);\n const type = this.parseTypeReference();\n let defaultValue;\n\n if (this.expectOptionalToken(TokenKind.EQUALS)) {\n defaultValue = this.parseValueLiteral(true);\n }\n\n const directives = this.parseDirectives(true);\n return {\n kind: Kind.INPUT_VALUE_DEFINITION,\n description,\n name,\n type,\n defaultValue,\n directives,\n loc: this.loc(start)\n };\n }\n /**\n * InterfaceTypeDefinition :\n * - Description? interface Name Directives[Const]? FieldsDefinition?\n */\n\n\n parseInterfaceTypeDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('interface');\n const name = this.parseName();\n const interfaces = this.parseImplementsInterfaces();\n const directives = this.parseDirectives(true);\n const fields = this.parseFieldsDefinition();\n return {\n kind: Kind.INTERFACE_TYPE_DEFINITION,\n description,\n name,\n interfaces,\n directives,\n fields,\n loc: this.loc(start)\n };\n }\n /**\n * UnionTypeDefinition :\n * - Description? union Name Directives[Const]? UnionMemberTypes?\n */\n\n\n parseUnionTypeDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('union');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n const types = this.parseUnionMemberTypes();\n return {\n kind: Kind.UNION_TYPE_DEFINITION,\n description,\n name,\n directives,\n types,\n loc: this.loc(start)\n };\n }\n /**\n * UnionMemberTypes :\n * - = `|`? NamedType\n * - UnionMemberTypes | NamedType\n */\n\n\n parseUnionMemberTypes() {\n return this.expectOptionalToken(TokenKind.EQUALS) ? this.delimitedMany(TokenKind.PIPE, this.parseNamedType) : [];\n }\n /**\n * EnumTypeDefinition :\n * - Description? enum Name Directives[Const]? EnumValuesDefinition?\n */\n\n\n parseEnumTypeDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('enum');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n const values = this.parseEnumValuesDefinition();\n return {\n kind: Kind.ENUM_TYPE_DEFINITION,\n description,\n name,\n directives,\n values,\n loc: this.loc(start)\n };\n }\n /**\n * EnumValuesDefinition : { EnumValueDefinition+ }\n */\n\n\n parseEnumValuesDefinition() {\n return this.optionalMany(TokenKind.BRACE_L, this.parseEnumValueDefinition, TokenKind.BRACE_R);\n }\n /**\n * EnumValueDefinition : Description? EnumValue Directives[Const]?\n *\n * EnumValue : Name\n */\n\n\n parseEnumValueDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n return {\n kind: Kind.ENUM_VALUE_DEFINITION,\n description,\n name,\n directives,\n loc: this.loc(start)\n };\n }\n /**\n * InputObjectTypeDefinition :\n * - Description? input Name Directives[Const]? InputFieldsDefinition?\n */\n\n\n parseInputObjectTypeDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('input');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n const fields = this.parseInputFieldsDefinition();\n return {\n kind: Kind.INPUT_OBJECT_TYPE_DEFINITION,\n description,\n name,\n directives,\n fields,\n loc: this.loc(start)\n };\n }\n /**\n * InputFieldsDefinition : { InputValueDefinition+ }\n */\n\n\n parseInputFieldsDefinition() {\n return this.optionalMany(TokenKind.BRACE_L, this.parseInputValueDef, TokenKind.BRACE_R);\n }\n /**\n * TypeSystemExtension :\n * - SchemaExtension\n * - TypeExtension\n *\n * TypeExtension :\n * - ScalarTypeExtension\n * - ObjectTypeExtension\n * - InterfaceTypeExtension\n * - UnionTypeExtension\n * - EnumTypeExtension\n * - InputObjectTypeDefinition\n */\n\n\n parseTypeSystemExtension() {\n const keywordToken = this._lexer.lookahead();\n\n if (keywordToken.kind === TokenKind.NAME) {\n switch (keywordToken.value) {\n case 'schema':\n return this.parseSchemaExtension();\n\n case 'scalar':\n return this.parseScalarTypeExtension();\n\n case 'type':\n return this.parseObjectTypeExtension();\n\n case 'interface':\n return this.parseInterfaceTypeExtension();\n\n case 'union':\n return this.parseUnionTypeExtension();\n\n case 'enum':\n return this.parseEnumTypeExtension();\n\n case 'input':\n return this.parseInputObjectTypeExtension();\n }\n }\n\n throw this.unexpected(keywordToken);\n }\n /**\n * SchemaExtension :\n * - extend schema Directives[Const]? { OperationTypeDefinition+ }\n * - extend schema Directives[Const]\n */\n\n\n parseSchemaExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('schema');\n const directives = this.parseDirectives(true);\n const operationTypes = this.optionalMany(TokenKind.BRACE_L, this.parseOperationTypeDefinition, TokenKind.BRACE_R);\n\n if (directives.length === 0 && operationTypes.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.SCHEMA_EXTENSION,\n directives,\n operationTypes,\n loc: this.loc(start)\n };\n }\n /**\n * ScalarTypeExtension :\n * - extend scalar Name Directives[Const]\n */\n\n\n parseScalarTypeExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('scalar');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n\n if (directives.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.SCALAR_TYPE_EXTENSION,\n name,\n directives,\n loc: this.loc(start)\n };\n }\n /**\n * ObjectTypeExtension :\n * - extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition\n * - extend type Name ImplementsInterfaces? Directives[Const]\n * - extend type Name ImplementsInterfaces\n */\n\n\n parseObjectTypeExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('type');\n const name = this.parseName();\n const interfaces = this.parseImplementsInterfaces();\n const directives = this.parseDirectives(true);\n const fields = this.parseFieldsDefinition();\n\n if (interfaces.length === 0 && directives.length === 0 && fields.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.OBJECT_TYPE_EXTENSION,\n name,\n interfaces,\n directives,\n fields,\n loc: this.loc(start)\n };\n }\n /**\n * InterfaceTypeExtension :\n * - extend interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition\n * - extend interface Name ImplementsInterfaces? Directives[Const]\n * - extend interface Name ImplementsInterfaces\n */\n\n\n parseInterfaceTypeExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('interface');\n const name = this.parseName();\n const interfaces = this.parseImplementsInterfaces();\n const directives = this.parseDirectives(true);\n const fields = this.parseFieldsDefinition();\n\n if (interfaces.length === 0 && directives.length === 0 && fields.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.INTERFACE_TYPE_EXTENSION,\n name,\n interfaces,\n directives,\n fields,\n loc: this.loc(start)\n };\n }\n /**\n * UnionTypeExtension :\n * - extend union Name Directives[Const]? UnionMemberTypes\n * - extend union Name Directives[Const]\n */\n\n\n parseUnionTypeExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('union');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n const types = this.parseUnionMemberTypes();\n\n if (directives.length === 0 && types.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.UNION_TYPE_EXTENSION,\n name,\n directives,\n types,\n loc: this.loc(start)\n };\n }\n /**\n * EnumTypeExtension :\n * - extend enum Name Directives[Const]? EnumValuesDefinition\n * - extend enum Name Directives[Const]\n */\n\n\n parseEnumTypeExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('enum');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n const values = this.parseEnumValuesDefinition();\n\n if (directives.length === 0 && values.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.ENUM_TYPE_EXTENSION,\n name,\n directives,\n values,\n loc: this.loc(start)\n };\n }\n /**\n * InputObjectTypeExtension :\n * - extend input Name Directives[Const]? InputFieldsDefinition\n * - extend input Name Directives[Const]\n */\n\n\n parseInputObjectTypeExtension() {\n const start = this._lexer.token;\n this.expectKeyword('extend');\n this.expectKeyword('input');\n const name = this.parseName();\n const directives = this.parseDirectives(true);\n const fields = this.parseInputFieldsDefinition();\n\n if (directives.length === 0 && fields.length === 0) {\n throw this.unexpected();\n }\n\n return {\n kind: Kind.INPUT_OBJECT_TYPE_EXTENSION,\n name,\n directives,\n fields,\n loc: this.loc(start)\n };\n }\n /**\n * DirectiveDefinition :\n * - Description? directive @ Name ArgumentsDefinition? `repeatable`? on DirectiveLocations\n */\n\n\n parseDirectiveDefinition() {\n const start = this._lexer.token;\n const description = this.parseDescription();\n this.expectKeyword('directive');\n this.expectToken(TokenKind.AT);\n const name = this.parseName();\n const args = this.parseArgumentDefs();\n const repeatable = this.expectOptionalKeyword('repeatable');\n this.expectKeyword('on');\n const locations = this.parseDirectiveLocations();\n return {\n kind: Kind.DIRECTIVE_DEFINITION,\n description,\n name,\n arguments: args,\n repeatable,\n locations,\n loc: this.loc(start)\n };\n }\n /**\n * DirectiveLocations :\n * - `|`? DirectiveLocation\n * - DirectiveLocations | DirectiveLocation\n */\n\n\n parseDirectiveLocations() {\n return this.delimitedMany(TokenKind.PIPE, this.parseDirectiveLocation);\n }\n /*\n * DirectiveLocation :\n * - ExecutableDirectiveLocation\n * - TypeSystemDirectiveLocation\n *\n * ExecutableDirectiveLocation : one of\n * `QUERY`\n * `MUTATION`\n * `SUBSCRIPTION`\n * `FIELD`\n * `FRAGMENT_DEFINITION`\n * `FRAGMENT_SPREAD`\n * `INLINE_FRAGMENT`\n *\n * TypeSystemDirectiveLocation : one of\n * `SCHEMA`\n * `SCALAR`\n * `OBJECT`\n * `FIELD_DEFINITION`\n * `ARGUMENT_DEFINITION`\n * `INTERFACE`\n * `UNION`\n * `ENUM`\n * `ENUM_VALUE`\n * `INPUT_OBJECT`\n * `INPUT_FIELD_DEFINITION`\n */\n\n\n parseDirectiveLocation() {\n const start = this._lexer.token;\n const name = this.parseName();\n\n if (DirectiveLocation[name.value] !== undefined) {\n return name;\n }\n\n throw this.unexpected(start);\n } // Core parsing utility functions\n\n /**\n * Returns a location object, used to identify the place in the source that created a given parsed object.\n */\n\n\n loc(startToken) {\n if (this._options?.noLocation !== true) {\n return new Location(startToken, this._lexer.lastToken, this._lexer.source);\n }\n }\n /**\n * Determines if the next token is of a given kind\n */\n\n\n peek(kind) {\n return this._lexer.token.kind === kind;\n }\n /**\n * If the next token is of the given kind, return that token after advancing the lexer.\n * Otherwise, do not change the parser state and throw an error.\n */\n\n\n expectToken(kind) {\n const token = this._lexer.token;\n\n if (token.kind === kind) {\n this._lexer.advance();\n\n return token;\n }\n\n throw syntaxError(this._lexer.source, token.start, `Expected ${getTokenKindDesc(kind)}, found ${getTokenDesc(token)}.`);\n }\n /**\n * If the next token is of the given kind, return that token after advancing the lexer.\n * Otherwise, do not change the parser state and return undefined.\n */\n\n\n expectOptionalToken(kind) {\n const token = this._lexer.token;\n\n if (token.kind === kind) {\n this._lexer.advance();\n\n return token;\n }\n\n return undefined;\n }\n /**\n * If the next token is a given keyword, advance the lexer.\n * Otherwise, do not change the parser state and throw an error.\n */\n\n\n expectKeyword(value) {\n const token = this._lexer.token;\n\n if (token.kind === TokenKind.NAME && token.value === value) {\n this._lexer.advance();\n } else {\n throw syntaxError(this._lexer.source, token.start, `Expected \"${value}\", found ${getTokenDesc(token)}.`);\n }\n }\n /**\n * If the next token is a given keyword, return \"true\" after advancing the lexer.\n * Otherwise, do not change the parser state and return \"false\".\n */\n\n\n expectOptionalKeyword(value) {\n const token = this._lexer.token;\n\n if (token.kind === TokenKind.NAME && token.value === value) {\n this._lexer.advance();\n\n return true;\n }\n\n return false;\n }\n /**\n * Helper function for creating an error when an unexpected lexed token is encountered.\n */\n\n\n unexpected(atToken) {\n const token = atToken ?? this._lexer.token;\n return syntaxError(this._lexer.source, token.start, `Unexpected ${getTokenDesc(token)}.`);\n }\n /**\n * Returns a possibly empty list of parse nodes, determined by the parseFn.\n * This list begins with a lex token of openKind and ends with a lex token of closeKind.\n * Advances the parser to the next lex token after the closing token.\n */\n\n\n any(openKind, parseFn, closeKind) {\n this.expectToken(openKind);\n const nodes = [];\n\n while (!this.expectOptionalToken(closeKind)) {\n nodes.push(parseFn.call(this));\n }\n\n return nodes;\n }\n /**\n * Returns a list of parse nodes, determined by the parseFn.\n * It can be empty only if open token is missing otherwise it will always return non-empty list\n * that begins with a lex token of openKind and ends with a lex token of closeKind.\n * Advances the parser to the next lex token after the closing token.\n */\n\n\n optionalMany(openKind, parseFn, closeKind) {\n if (this.expectOptionalToken(openKind)) {\n const nodes = [];\n\n do {\n nodes.push(parseFn.call(this));\n } while (!this.expectOptionalToken(closeKind));\n\n return nodes;\n }\n\n return [];\n }\n /**\n * Returns a non-empty list of parse nodes, determined by the parseFn.\n * This list begins with a lex token of openKind and ends with a lex token of closeKind.\n * Advances the parser to the next lex token after the closing token.\n */\n\n\n many(openKind, parseFn, closeKind) {\n this.expectToken(openKind);\n const nodes = [];\n\n do {\n nodes.push(parseFn.call(this));\n } while (!this.expectOptionalToken(closeKind));\n\n return nodes;\n }\n /**\n * Returns a non-empty list of parse nodes, determined by the parseFn.\n * This list may begin with a lex token of delimiterKind followed by items separated by lex tokens of tokenKind.\n * Advances the parser to the next lex token after last item in the list.\n */\n\n\n delimitedMany(delimiterKind, parseFn) {\n this.expectOptionalToken(delimiterKind);\n const nodes = [];\n\n do {\n nodes.push(parseFn.call(this));\n } while (this.expectOptionalToken(delimiterKind));\n\n return nodes;\n }\n\n}\n/**\n * A helper function to describe a token as a string for debugging.\n */\n\nfunction getTokenDesc(token) {\n const value = token.value;\n return getTokenKindDesc(token.kind) + (value != null ? ` \"${value}\"` : '');\n}\n/**\n * A helper function to describe a token kind as a string for debugging.\n */\n\n\nfunction getTokenKindDesc(kind) {\n return isPunctuatorTokenKind(kind) ? `\"${kind}\"` : kind;\n}\n","import inspect from \"../jsutils/inspect.mjs\";\nimport { isNode } from \"./ast.mjs\";\n/**\n * A visitor is provided to visit, it contains the collection of\n * relevant functions to be called during the visitor's traversal.\n */\n\nexport const QueryDocumentKeys = {\n Name: [],\n Document: ['definitions'],\n OperationDefinition: ['name', 'variableDefinitions', 'directives', 'selectionSet'],\n VariableDefinition: ['variable', 'type', 'defaultValue', 'directives'],\n Variable: ['name'],\n SelectionSet: ['selections'],\n Field: ['alias', 'name', 'arguments', 'directives', 'selectionSet'],\n Argument: ['name', 'value'],\n FragmentSpread: ['name', 'directives'],\n InlineFragment: ['typeCondition', 'directives', 'selectionSet'],\n FragmentDefinition: ['name', // Note: fragment variable definitions are experimental and may be changed\n // or removed in the future.\n 'variableDefinitions', 'typeCondition', 'directives', 'selectionSet'],\n IntValue: [],\n FloatValue: [],\n StringValue: [],\n BooleanValue: [],\n NullValue: [],\n EnumValue: [],\n ListValue: ['values'],\n ObjectValue: ['fields'],\n ObjectField: ['name', 'value'],\n Directive: ['name', 'arguments'],\n NamedType: ['name'],\n ListType: ['type'],\n NonNullType: ['type'],\n SchemaDefinition: ['description', 'directives', 'operationTypes'],\n OperationTypeDefinition: ['type'],\n ScalarTypeDefinition: ['description', 'name', 'directives'],\n ObjectTypeDefinition: ['description', 'name', 'interfaces', 'directives', 'fields'],\n FieldDefinition: ['description', 'name', 'arguments', 'type', 'directives'],\n InputValueDefinition: ['description', 'name', 'type', 'defaultValue', 'directives'],\n InterfaceTypeDefinition: ['description', 'name', 'interfaces', 'directives', 'fields'],\n UnionTypeDefinition: ['description', 'name', 'directives', 'types'],\n EnumTypeDefinition: ['description', 'name', 'directives', 'values'],\n EnumValueDefinition: ['description', 'name', 'directives'],\n InputObjectTypeDefinition: ['description', 'name', 'directives', 'fields'],\n DirectiveDefinition: ['description', 'name', 'arguments', 'locations'],\n SchemaExtension: ['directives', 'operationTypes'],\n ScalarTypeExtension: ['name', 'directives'],\n ObjectTypeExtension: ['name', 'interfaces', 'directives', 'fields'],\n InterfaceTypeExtension: ['name', 'interfaces', 'directives', 'fields'],\n UnionTypeExtension: ['name', 'directives', 'types'],\n EnumTypeExtension: ['name', 'directives', 'values'],\n InputObjectTypeExtension: ['name', 'directives', 'fields']\n};\nexport const BREAK = Object.freeze({});\n/**\n * visit() will walk through an AST using a depth-first traversal, calling\n * the visitor's enter function at each node in the traversal, and calling the\n * leave function after visiting that node and all of its child nodes.\n *\n * By returning different values from the enter and leave functions, the\n * behavior of the visitor can be altered, including skipping over a sub-tree of\n * the AST (by returning false), editing the AST by returning a value or null\n * to remove the value, or to stop the whole traversal by returning BREAK.\n *\n * When using visit() to edit an AST, the original AST will not be modified, and\n * a new version of the AST with the changes applied will be returned from the\n * visit function.\n *\n * const editedAST = visit(ast, {\n * enter(node, key, parent, path, ancestors) {\n * // @return\n * // undefined: no action\n * // false: skip visiting this node\n * // visitor.BREAK: stop visiting altogether\n * // null: delete this node\n * // any value: replace this node with the returned value\n * },\n * leave(node, key, parent, path, ancestors) {\n * // @return\n * // undefined: no action\n * // false: no action\n * // visitor.BREAK: stop visiting altogether\n * // null: delete this node\n * // any value: replace this node with the returned value\n * }\n * });\n *\n * Alternatively to providing enter() and leave() functions, a visitor can\n * instead provide functions named the same as the kinds of AST nodes, or\n * enter/leave visitors at a named key, leading to four permutations of the\n * visitor API:\n *\n * 1) Named visitors triggered when entering a node of a specific kind.\n *\n * visit(ast, {\n * Kind(node) {\n * // enter the \"Kind\" node\n * }\n * })\n *\n * 2) Named visitors that trigger upon entering and leaving a node of\n * a specific kind.\n *\n * visit(ast, {\n * Kind: {\n * enter(node) {\n * // enter the \"Kind\" node\n * }\n * leave(node) {\n * // leave the \"Kind\" node\n * }\n * }\n * })\n *\n * 3) Generic visitors that trigger upon entering and leaving any node.\n *\n * visit(ast, {\n * enter(node) {\n * // enter any node\n * },\n * leave(node) {\n * // leave any node\n * }\n * })\n *\n * 4) Parallel visitors for entering and leaving nodes of a specific kind.\n *\n * visit(ast, {\n * enter: {\n * Kind(node) {\n * // enter the \"Kind\" node\n * }\n * },\n * leave: {\n * Kind(node) {\n * // leave the \"Kind\" node\n * }\n * }\n * })\n */\n\nexport function visit(root, visitor, visitorKeys = QueryDocumentKeys) {\n /* eslint-disable no-undef-init */\n let stack = undefined;\n let inArray = Array.isArray(root);\n let keys = [root];\n let index = -1;\n let edits = [];\n let node = undefined;\n let key = undefined;\n let parent = undefined;\n const path = [];\n const ancestors = [];\n let newRoot = root;\n /* eslint-enable no-undef-init */\n\n do {\n index++;\n const isLeaving = index === keys.length;\n const isEdited = isLeaving && edits.length !== 0;\n\n if (isLeaving) {\n key = ancestors.length === 0 ? undefined : path[path.length - 1];\n node = parent;\n parent = ancestors.pop();\n\n if (isEdited) {\n if (inArray) {\n node = node.slice();\n } else {\n const clone = {};\n\n for (const k of Object.keys(node)) {\n clone[k] = node[k];\n }\n\n node = clone;\n }\n\n let editOffset = 0;\n\n for (let ii = 0; ii < edits.length; ii++) {\n let editKey = edits[ii][0];\n const editValue = edits[ii][1];\n\n if (inArray) {\n editKey -= editOffset;\n }\n\n if (inArray && editValue === null) {\n node.splice(editKey, 1);\n editOffset++;\n } else {\n node[editKey] = editValue;\n }\n }\n }\n\n index = stack.index;\n keys = stack.keys;\n edits = stack.edits;\n inArray = stack.inArray;\n stack = stack.prev;\n } else {\n key = parent ? inArray ? index : keys[index] : undefined;\n node = parent ? parent[key] : newRoot;\n\n if (node === null || node === undefined) {\n continue;\n }\n\n if (parent) {\n path.push(key);\n }\n }\n\n let result;\n\n if (!Array.isArray(node)) {\n if (!isNode(node)) {\n throw new Error(`Invalid AST Node: ${inspect(node)}.`);\n }\n\n const visitFn = getVisitFn(visitor, node.kind, isLeaving);\n\n if (visitFn) {\n result = visitFn.call(visitor, node, key, parent, path, ancestors);\n\n if (result === BREAK) {\n break;\n }\n\n if (result === false) {\n if (!isLeaving) {\n path.pop();\n continue;\n }\n } else if (result !== undefined) {\n edits.push([key, result]);\n\n if (!isLeaving) {\n if (isNode(result)) {\n node = result;\n } else {\n path.pop();\n continue;\n }\n }\n }\n }\n }\n\n if (result === undefined && isEdited) {\n edits.push([key, node]);\n }\n\n if (isLeaving) {\n path.pop();\n } else {\n stack = {\n inArray,\n index,\n keys,\n edits,\n prev: stack\n };\n inArray = Array.isArray(node);\n keys = inArray ? node : visitorKeys[node.kind] ?? [];\n index = -1;\n edits = [];\n\n if (parent) {\n ancestors.push(parent);\n }\n\n parent = node;\n }\n } while (stack !== undefined);\n\n if (edits.length !== 0) {\n newRoot = edits[edits.length - 1][1];\n }\n\n return newRoot;\n}\n/**\n * Creates a new visitor instance which delegates to many visitors to run in\n * parallel. Each visitor will be visited for each node before moving on.\n *\n * If a prior visitor edits a node, no following visitors will see that node.\n */\n\nexport function visitInParallel(visitors) {\n const skipping = new Array(visitors.length);\n return {\n enter(node) {\n for (let i = 0; i < visitors.length; i++) {\n if (skipping[i] == null) {\n const fn = getVisitFn(visitors[i], node.kind,\n /* isLeaving */\n false);\n\n if (fn) {\n const result = fn.apply(visitors[i], arguments);\n\n if (result === false) {\n skipping[i] = node;\n } else if (result === BREAK) {\n skipping[i] = BREAK;\n } else if (result !== undefined) {\n return result;\n }\n }\n }\n }\n },\n\n leave(node) {\n for (let i = 0; i < visitors.length; i++) {\n if (skipping[i] == null) {\n const fn = getVisitFn(visitors[i], node.kind,\n /* isLeaving */\n true);\n\n if (fn) {\n const result = fn.apply(visitors[i], arguments);\n\n if (result === BREAK) {\n skipping[i] = BREAK;\n } else if (result !== undefined && result !== false) {\n return result;\n }\n }\n } else if (skipping[i] === node) {\n skipping[i] = null;\n }\n }\n }\n\n };\n}\n/**\n * Given a visitor instance, if it is leaving or not, and a node kind, return\n * the function the visitor runtime should call.\n */\n\nexport function getVisitFn(visitor, kind, isLeaving) {\n const kindVisitor = visitor[kind];\n\n if (kindVisitor) {\n if (!isLeaving && typeof kindVisitor === 'function') {\n // { Kind() {} }\n return kindVisitor;\n }\n\n const kindSpecificVisitor = isLeaving ? kindVisitor.leave : kindVisitor.enter;\n\n if (typeof kindSpecificVisitor === 'function') {\n // { Kind: { enter() {}, leave() {} } }\n return kindSpecificVisitor;\n }\n } else {\n const specificVisitor = isLeaving ? visitor.leave : visitor.enter;\n\n if (specificVisitor) {\n if (typeof specificVisitor === 'function') {\n // { enter() {}, leave() {} }\n return specificVisitor;\n }\n\n const specificKindVisitor = specificVisitor[kind];\n\n if (typeof specificKindVisitor === 'function') {\n // { enter: { Kind() {} }, leave: { Kind() {} } }\n return specificKindVisitor;\n }\n }\n }\n}\n","/* eslint-disable no-redeclare */\n// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441\nconst objectValues = Object.values || (obj => Object.keys(obj).map(key => obj[key]));\n\nexport default objectValues;\n","import devAssert from \"../jsutils/devAssert.mjs\";\nimport { GraphQLError } from \"../error/GraphQLError.mjs\";\nconst NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/;\n/**\n * Upholds the spec rules about naming.\n */\n\nexport function assertValidName(name) {\n const error = isValidNameError(name);\n\n if (error) {\n throw error;\n }\n\n return name;\n}\n/**\n * Returns an Error if a name is invalid.\n */\n\nexport function isValidNameError(name) {\n typeof name === 'string' || devAssert(0, 'Expected name to be a string.');\n\n if (name.length > 1 && name[0] === '_' && name[1] === '_') {\n return new GraphQLError(`Name \"${name}\" must not begin with \"__\", which is reserved by GraphQL introspection.`);\n }\n\n if (!NAME_RX.test(name)) {\n return new GraphQLError(`Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"${name}\" does not.`);\n }\n}\n","/* eslint-disable no-redeclare */\n// $FlowFixMe[name-already-bound] workaround for: https://github.com/facebook/flow/issues/4441\nconst objectEntries = Object.entries || (obj => Object.keys(obj).map(key => [key, obj[key]]));\n\nexport default objectEntries;\n","/**\n * Creates a keyed JS object from an array, given a function to produce the keys\n * for each value in the array.\n *\n * This provides a convenient lookup for the array items if the key function\n * produces unique results.\n *\n * const phoneBook = [\n * { name: 'Jon', num: '555-1234' },\n * { name: 'Jenny', num: '867-5309' }\n * ]\n *\n * // { Jon: { name: 'Jon', num: '555-1234' },\n * // Jenny: { name: 'Jenny', num: '867-5309' } }\n * const entriesByName = keyMap(\n * phoneBook,\n * entry => entry.name\n * )\n *\n * // { name: 'Jenny', num: '857-6309' }\n * const jennyEntry = entriesByName['Jenny']\n *\n */\nexport default function keyMap(list, keyFn) {\n return list.reduce((map, item) => {\n map[keyFn(item)] = item;\n return map;\n }, Object.create(null));\n}\n","import objectEntries from \"../polyfills/objectEntries.mjs\";\n\n/**\n * Creates an object map with the same keys as `map` and values generated by\n * running each value of `map` thru `fn`.\n */\nexport default function mapValue(map, fn) {\n const result = Object.create(null);\n\n for (const [key, value] of objectEntries(map)) {\n result[key] = fn(value, key);\n }\n\n return result;\n}\n","import objectEntries from \"../polyfills/objectEntries.mjs\";\nexport default function toObjMap(obj) {\n /* eslint-enable no-redeclare */\n if (Object.getPrototypeOf(obj) === null) {\n return obj;\n }\n\n const map = Object.create(null);\n\n for (const [key, value] of objectEntries(obj)) {\n map[key] = value;\n }\n\n return map;\n}\n","/**\n * Creates a keyed JS object from an array, given a function to produce the keys\n * and a function to produce the values from each item in the array.\n *\n * const phoneBook = [\n * { name: 'Jon', num: '555-1234' },\n * { name: 'Jenny', num: '867-5309' }\n * ]\n *\n * // { Jon: '555-1234', Jenny: '867-5309' }\n * const phonesByName = keyValMap(\n * phoneBook,\n * entry => entry.name,\n * entry => entry.num\n * )\n *\n */\nexport default function keyValMap(list, keyFn, valFn) {\n return list.reduce((map, item) => {\n map[keyFn(item)] = valFn(item);\n return map;\n }, Object.create(null));\n}\n","const MAX_SUGGESTIONS = 5;\n/**\n * Given [ A, B, C ] return ' Did you mean A, B, or C?'.\n */\n\n// eslint-disable-next-line no-redeclare\nexport default function didYouMean(firstArg, secondArg) {\n const [subMessage, suggestionsArg] = typeof firstArg === 'string' ? [firstArg, secondArg] : [undefined, firstArg];\n let message = ' Did you mean ';\n\n if (subMessage) {\n message += subMessage + ' ';\n }\n\n const suggestions = suggestionsArg.map(x => `\"${x}\"`);\n\n switch (suggestions.length) {\n case 0:\n return '';\n\n case 1:\n return message + suggestions[0] + '?';\n\n case 2:\n return message + suggestions[0] + ' or ' + suggestions[1] + '?';\n }\n\n const selected = suggestions.slice(0, MAX_SUGGESTIONS);\n const lastItem = selected.pop();\n return message + selected.join(', ') + ', or ' + lastItem + '?';\n}\n","/**\n * Returns the first argument it receives.\n */\nexport default function identityFunc(x) {\n return x;\n}\n","/**\n * Given an invalid input string and a list of valid options, returns a filtered\n * list of valid options sorted based on their similarity with the input.\n */\nexport default function suggestionList(input, options) {\n const optionsByDistance = Object.create(null);\n const lexicalDistance = new LexicalDistance(input);\n const threshold = Math.floor(input.length * 0.4) + 1;\n\n for (const option of options) {\n const distance = lexicalDistance.measure(option, threshold);\n\n if (distance !== undefined) {\n optionsByDistance[option] = distance;\n }\n }\n\n return Object.keys(optionsByDistance).sort((a, b) => {\n const distanceDiff = optionsByDistance[a] - optionsByDistance[b];\n return distanceDiff !== 0 ? distanceDiff : a.localeCompare(b);\n });\n}\n/**\n * Computes the lexical distance between strings A and B.\n *\n * The \"distance\" between two strings is given by counting the minimum number\n * of edits needed to transform string A into string B. An edit can be an\n * insertion, deletion, or substitution of a single character, or a swap of two\n * adjacent characters.\n *\n * Includes a custom alteration from Damerau-Levenshtein to treat case changes\n * as a single edit which helps identify mis-cased values with an edit distance\n * of 1.\n *\n * This distance can be useful for detecting typos in input or sorting\n */\n\nclass LexicalDistance {\n constructor(input) {\n this._input = input;\n this._inputLowerCase = input.toLowerCase();\n this._inputArray = stringToArray(this._inputLowerCase);\n this._rows = [new Array(input.length + 1).fill(0), new Array(input.length + 1).fill(0), new Array(input.length + 1).fill(0)];\n }\n\n measure(option, threshold) {\n if (this._input === option) {\n return 0;\n }\n\n const optionLowerCase = option.toLowerCase(); // Any case change counts as a single edit\n\n if (this._inputLowerCase === optionLowerCase) {\n return 1;\n }\n\n let a = stringToArray(optionLowerCase);\n let b = this._inputArray;\n\n if (a.length < b.length) {\n const tmp = a;\n a = b;\n b = tmp;\n }\n\n const aLength = a.length;\n const bLength = b.length;\n\n if (aLength - bLength > threshold) {\n return undefined;\n }\n\n const rows = this._rows;\n\n for (let j = 0; j <= bLength; j++) {\n rows[0][j] = j;\n }\n\n for (let i = 1; i <= aLength; i++) {\n const upRow = rows[(i - 1) % 3];\n const currentRow = rows[i % 3];\n let smallestCell = currentRow[0] = i;\n\n for (let j = 1; j <= bLength; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n let currentCell = Math.min(upRow[j] + 1, // delete\n currentRow[j - 1] + 1, // insert\n upRow[j - 1] + cost // substitute\n );\n\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n // transposition\n const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];\n currentCell = Math.min(currentCell, doubleDiagonalCell + 1);\n }\n\n if (currentCell < smallestCell) {\n smallestCell = currentCell;\n }\n\n currentRow[j] = currentCell;\n } // Early exit, since distance can't go smaller than smallest element of the previous row.\n\n\n if (smallestCell > threshold) {\n return undefined;\n }\n }\n\n const distance = rows[aLength % 3][bLength];\n return distance <= threshold ? distance : undefined;\n }\n\n}\n\nfunction stringToArray(str) {\n const strLength = str.length;\n const array = new Array(strLength);\n\n for (let i = 0; i < strLength; ++i) {\n array[i] = str.charCodeAt(i);\n }\n\n return array;\n}\n","import { visit } from \"./visitor.mjs\";\nimport { printBlockString } from \"./blockString.mjs\";\n/**\n * Converts an AST into a string, using one set of reasonable\n * formatting rules.\n */\n\nexport function print(ast) {\n return visit(ast, {\n leave: printDocASTReducer\n });\n}\nconst MAX_LINE_LENGTH = 80; // TODO: provide better type coverage in future\n\nconst printDocASTReducer = {\n Name: node => node.value,\n Variable: node => '$' + node.name,\n // Document\n Document: node => join(node.definitions, '\\n\\n') + '\\n',\n\n OperationDefinition(node) {\n const op = node.operation;\n const name = node.name;\n const varDefs = wrap('(', join(node.variableDefinitions, ', '), ')');\n const directives = join(node.directives, ' ');\n const selectionSet = node.selectionSet; // Anonymous queries with no directives or variable definitions can use\n // the query short form.\n\n return !name && !directives && !varDefs && op === 'query' ? selectionSet : join([op, join([name, varDefs]), directives, selectionSet], ' ');\n },\n\n VariableDefinition: ({\n variable,\n type,\n defaultValue,\n directives\n }) => variable + ': ' + type + wrap(' = ', defaultValue) + wrap(' ', join(directives, ' ')),\n SelectionSet: ({\n selections\n }) => block(selections),\n Field: ({\n alias,\n name,\n arguments: args,\n directives,\n selectionSet\n }) => {\n const prefix = wrap('', alias, ': ') + name;\n let argsLine = prefix + wrap('(', join(args, ', '), ')');\n\n if (argsLine.length > MAX_LINE_LENGTH) {\n argsLine = prefix + wrap('(\\n', indent(join(args, '\\n')), '\\n)');\n }\n\n return join([argsLine, join(directives, ' '), selectionSet], ' ');\n },\n Argument: ({\n name,\n value\n }) => name + ': ' + value,\n // Fragments\n FragmentSpread: ({\n name,\n directives\n }) => '...' + name + wrap(' ', join(directives, ' ')),\n InlineFragment: ({\n typeCondition,\n directives,\n selectionSet\n }) => join(['...', wrap('on ', typeCondition), join(directives, ' '), selectionSet], ' '),\n FragmentDefinition: ({\n name,\n typeCondition,\n variableDefinitions,\n directives,\n selectionSet\n }) => // Note: fragment variable definitions are experimental and may be changed\n // or removed in the future.\n `fragment ${name}${wrap('(', join(variableDefinitions, ', '), ')')} ` + `on ${typeCondition} ${wrap('', join(directives, ' '), ' ')}` + selectionSet,\n // Value\n IntValue: ({\n value\n }) => value,\n FloatValue: ({\n value\n }) => value,\n StringValue: ({\n value,\n block: isBlockString\n }, key) => isBlockString ? printBlockString(value, key === 'description' ? '' : ' ') : JSON.stringify(value),\n BooleanValue: ({\n value\n }) => value ? 'true' : 'false',\n NullValue: () => 'null',\n EnumValue: ({\n value\n }) => value,\n ListValue: ({\n values\n }) => '[' + join(values, ', ') + ']',\n ObjectValue: ({\n fields\n }) => '{' + join(fields, ', ') + '}',\n ObjectField: ({\n name,\n value\n }) => name + ': ' + value,\n // Directive\n Directive: ({\n name,\n arguments: args\n }) => '@' + name + wrap('(', join(args, ', '), ')'),\n // Type\n NamedType: ({\n name\n }) => name,\n ListType: ({\n type\n }) => '[' + type + ']',\n NonNullType: ({\n type\n }) => type + '!',\n // Type System Definitions\n SchemaDefinition: addDescription(({\n directives,\n operationTypes\n }) => join(['schema', join(directives, ' '), block(operationTypes)], ' ')),\n OperationTypeDefinition: ({\n operation,\n type\n }) => operation + ': ' + type,\n ScalarTypeDefinition: addDescription(({\n name,\n directives\n }) => join(['scalar', name, join(directives, ' ')], ' ')),\n ObjectTypeDefinition: addDescription(({\n name,\n interfaces,\n directives,\n fields\n }) => join(['type', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' ')),\n FieldDefinition: addDescription(({\n name,\n arguments: args,\n type,\n directives\n }) => name + (hasMultilineItems(args) ? wrap('(\\n', indent(join(args, '\\n')), '\\n)') : wrap('(', join(args, ', '), ')')) + ': ' + type + wrap(' ', join(directives, ' '))),\n InputValueDefinition: addDescription(({\n name,\n type,\n defaultValue,\n directives\n }) => join([name + ': ' + type, wrap('= ', defaultValue), join(directives, ' ')], ' ')),\n InterfaceTypeDefinition: addDescription(({\n name,\n interfaces,\n directives,\n fields\n }) => join(['interface', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' ')),\n UnionTypeDefinition: addDescription(({\n name,\n directives,\n types\n }) => join(['union', name, join(directives, ' '), types && types.length !== 0 ? '= ' + join(types, ' | ') : ''], ' ')),\n EnumTypeDefinition: addDescription(({\n name,\n directives,\n values\n }) => join(['enum', name, join(directives, ' '), block(values)], ' ')),\n EnumValueDefinition: addDescription(({\n name,\n directives\n }) => join([name, join(directives, ' ')], ' ')),\n InputObjectTypeDefinition: addDescription(({\n name,\n directives,\n fields\n }) => join(['input', name, join(directives, ' '), block(fields)], ' ')),\n DirectiveDefinition: addDescription(({\n name,\n arguments: args,\n repeatable,\n locations\n }) => 'directive @' + name + (hasMultilineItems(args) ? wrap('(\\n', indent(join(args, '\\n')), '\\n)') : wrap('(', join(args, ', '), ')')) + (repeatable ? ' repeatable' : '') + ' on ' + join(locations, ' | ')),\n SchemaExtension: ({\n directives,\n operationTypes\n }) => join(['extend schema', join(directives, ' '), block(operationTypes)], ' '),\n ScalarTypeExtension: ({\n name,\n directives\n }) => join(['extend scalar', name, join(directives, ' ')], ' '),\n ObjectTypeExtension: ({\n name,\n interfaces,\n directives,\n fields\n }) => join(['extend type', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' '),\n InterfaceTypeExtension: ({\n name,\n interfaces,\n directives,\n fields\n }) => join(['extend interface', name, wrap('implements ', join(interfaces, ' & ')), join(directives, ' '), block(fields)], ' '),\n UnionTypeExtension: ({\n name,\n directives,\n types\n }) => join(['extend union', name, join(directives, ' '), types && types.length !== 0 ? '= ' + join(types, ' | ') : ''], ' '),\n EnumTypeExtension: ({\n name,\n directives,\n values\n }) => join(['extend enum', name, join(directives, ' '), block(values)], ' '),\n InputObjectTypeExtension: ({\n name,\n directives,\n fields\n }) => join(['extend input', name, join(directives, ' '), block(fields)], ' ')\n};\n\nfunction addDescription(cb) {\n return node => join([node.description, cb(node)], '\\n');\n}\n/**\n * Given maybeArray, print an empty string if it is null or empty, otherwise\n * print all items together separated by separator if provided\n */\n\n\nfunction join(maybeArray, separator = '') {\n return maybeArray?.filter(x => x).join(separator) ?? '';\n}\n/**\n * Given array, print each item on its own line, wrapped in an\n * indented \"{ }\" block.\n */\n\n\nfunction block(array) {\n return wrap('{\\n', indent(join(array, '\\n')), '\\n}');\n}\n/**\n * If maybeString is not null or empty, then wrap with start and end, otherwise print an empty string.\n */\n\n\nfunction wrap(start, maybeString, end = '') {\n return maybeString != null && maybeString !== '' ? start + maybeString + end : '';\n}\n\nfunction indent(str) {\n return wrap(' ', str.replace(/\\n/g, '\\n '));\n}\n\nfunction isMultiline(str) {\n return str.indexOf('\\n') !== -1;\n}\n\nfunction hasMultilineItems(maybeArray) {\n return maybeArray != null && maybeArray.some(isMultiline);\n}\n","export default function invariant(condition, message) {\n const booleanCondition = Boolean(condition); // istanbul ignore else (See transformation done in './resources/inlineInvariant.js')\n\n if (!booleanCondition) {\n throw new Error(message != null ? message : 'Unexpected invariant triggered.');\n }\n}\n","import inspect from \"../jsutils/inspect.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport keyValMap from \"../jsutils/keyValMap.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\n\n/**\n * Produces a JavaScript value given a GraphQL Value AST.\n *\n * Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value\n * will reflect the provided GraphQL value AST.\n *\n * | GraphQL Value | JavaScript Value |\n * | -------------------- | ---------------- |\n * | Input Object | Object |\n * | List | Array |\n * | Boolean | Boolean |\n * | String / Enum | String |\n * | Int / Float | Number |\n * | Null | null |\n *\n */\nexport function valueFromASTUntyped(valueNode, variables) {\n switch (valueNode.kind) {\n case Kind.NULL:\n return null;\n\n case Kind.INT:\n return parseInt(valueNode.value, 10);\n\n case Kind.FLOAT:\n return parseFloat(valueNode.value);\n\n case Kind.STRING:\n case Kind.ENUM:\n case Kind.BOOLEAN:\n return valueNode.value;\n\n case Kind.LIST:\n return valueNode.values.map(node => valueFromASTUntyped(node, variables));\n\n case Kind.OBJECT:\n return keyValMap(valueNode.fields, field => field.name.value, field => valueFromASTUntyped(field.value, variables));\n\n case Kind.VARIABLE:\n return variables?.[valueNode.name.value];\n } // istanbul ignore next (Not reachable. All possible value nodes have been considered)\n\n\n false || invariant(0, 'Unexpected value node: ' + inspect(valueNode));\n}\n","import objectEntries from \"../polyfills/objectEntries.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport keyMap from \"../jsutils/keyMap.mjs\";\nimport mapValue from \"../jsutils/mapValue.mjs\";\nimport toObjMap from \"../jsutils/toObjMap.mjs\";\nimport devAssert from \"../jsutils/devAssert.mjs\";\nimport keyValMap from \"../jsutils/keyValMap.mjs\";\nimport instanceOf from \"../jsutils/instanceOf.mjs\";\nimport didYouMean from \"../jsutils/didYouMean.mjs\";\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport identityFunc from \"../jsutils/identityFunc.mjs\";\nimport suggestionList from \"../jsutils/suggestionList.mjs\";\nimport { GraphQLError } from \"../error/GraphQLError.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { print } from \"../language/printer.mjs\";\nimport { valueFromASTUntyped } from \"../utilities/valueFromASTUntyped.mjs\";\nexport function isType(type) {\n return isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type) || isListType(type) || isNonNullType(type);\n}\nexport function assertType(type) {\n if (!isType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL type.`);\n }\n\n return type;\n}\n/**\n * There are predicates for each kind of GraphQL type.\n */\n\n// eslint-disable-next-line no-redeclare\nexport function isScalarType(type) {\n return instanceOf(type, GraphQLScalarType);\n}\nexport function assertScalarType(type) {\n if (!isScalarType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Scalar type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isObjectType(type) {\n return instanceOf(type, GraphQLObjectType);\n}\nexport function assertObjectType(type) {\n if (!isObjectType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Object type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isInterfaceType(type) {\n return instanceOf(type, GraphQLInterfaceType);\n}\nexport function assertInterfaceType(type) {\n if (!isInterfaceType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Interface type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isUnionType(type) {\n return instanceOf(type, GraphQLUnionType);\n}\nexport function assertUnionType(type) {\n if (!isUnionType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Union type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isEnumType(type) {\n return instanceOf(type, GraphQLEnumType);\n}\nexport function assertEnumType(type) {\n if (!isEnumType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Enum type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isInputObjectType(type) {\n return instanceOf(type, GraphQLInputObjectType);\n}\nexport function assertInputObjectType(type) {\n if (!isInputObjectType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Input Object type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isListType(type) {\n return instanceOf(type, GraphQLList);\n}\nexport function assertListType(type) {\n if (!isListType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL List type.`);\n }\n\n return type;\n}\n// eslint-disable-next-line no-redeclare\nexport function isNonNullType(type) {\n return instanceOf(type, GraphQLNonNull);\n}\nexport function assertNonNullType(type) {\n if (!isNonNullType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL Non-Null type.`);\n }\n\n return type;\n}\n/**\n * These types may be used as input types for arguments and directives.\n */\n\nexport function isInputType(type) {\n return isScalarType(type) || isEnumType(type) || isInputObjectType(type) || isWrappingType(type) && isInputType(type.ofType);\n}\nexport function assertInputType(type) {\n if (!isInputType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL input type.`);\n }\n\n return type;\n}\n/**\n * These types may be used as output types as the result of fields.\n */\n\nexport function isOutputType(type) {\n return isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isWrappingType(type) && isOutputType(type.ofType);\n}\nexport function assertOutputType(type) {\n if (!isOutputType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL output type.`);\n }\n\n return type;\n}\n/**\n * These types may describe types which may be leaf values.\n */\n\nexport function isLeafType(type) {\n return isScalarType(type) || isEnumType(type);\n}\nexport function assertLeafType(type) {\n if (!isLeafType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL leaf type.`);\n }\n\n return type;\n}\n/**\n * These types may describe the parent context of a selection set.\n */\n\nexport function isCompositeType(type) {\n return isObjectType(type) || isInterfaceType(type) || isUnionType(type);\n}\nexport function assertCompositeType(type) {\n if (!isCompositeType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL composite type.`);\n }\n\n return type;\n}\n/**\n * These types may describe the parent context of a selection set.\n */\n\nexport function isAbstractType(type) {\n return isInterfaceType(type) || isUnionType(type);\n}\nexport function assertAbstractType(type) {\n if (!isAbstractType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL abstract type.`);\n }\n\n return type;\n}\n/**\n * List Type Wrapper\n *\n * A list is a wrapping type which points to another type.\n * Lists are often created within the context of defining the fields of\n * an object type.\n *\n * Example:\n *\n * const PersonType = new GraphQLObjectType({\n * name: 'Person',\n * fields: () => ({\n * parents: { type: new GraphQLList(PersonType) },\n * children: { type: new GraphQLList(PersonType) },\n * })\n * })\n *\n */\n\nexport class GraphQLList {\n constructor(ofType) {\n isType(ofType) || devAssert(0, `Expected ${inspect(ofType)} to be a GraphQL type.`);\n this.ofType = ofType;\n }\n\n toString() {\n return '[' + String(this.ofType) + ']';\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLList';\n }\n\n}\n/**\n * Non-Null Type Wrapper\n *\n * A non-null is a wrapping type which points to another type.\n * Non-null types enforce that their values are never null and can ensure\n * an error is raised if this ever occurs during a request. It is useful for\n * fields which you can make a strong guarantee on non-nullability, for example\n * usually the id field of a database row will never be null.\n *\n * Example:\n *\n * const RowType = new GraphQLObjectType({\n * name: 'Row',\n * fields: () => ({\n * id: { type: new GraphQLNonNull(GraphQLString) },\n * })\n * })\n *\n * Note: the enforcement of non-nullability occurs within the executor.\n */\n\nexport class GraphQLNonNull {\n constructor(ofType) {\n isNullableType(ofType) || devAssert(0, `Expected ${inspect(ofType)} to be a GraphQL nullable type.`);\n this.ofType = ofType;\n }\n\n toString() {\n return String(this.ofType) + '!';\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLNonNull';\n }\n\n}\n/**\n * These types wrap and modify other types\n */\n\nexport function isWrappingType(type) {\n return isListType(type) || isNonNullType(type);\n}\nexport function assertWrappingType(type) {\n if (!isWrappingType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL wrapping type.`);\n }\n\n return type;\n}\n/**\n * These types can all accept null as a value.\n */\n\nexport function isNullableType(type) {\n return isType(type) && !isNonNullType(type);\n}\nexport function assertNullableType(type) {\n if (!isNullableType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL nullable type.`);\n }\n\n return type;\n}\n/* eslint-disable no-redeclare */\n\nexport function getNullableType(type) {\n /* eslint-enable no-redeclare */\n if (type) {\n return isNonNullType(type) ? type.ofType : type;\n }\n}\n/**\n * These named types do not include modifiers like List or NonNull.\n */\n\nexport function isNamedType(type) {\n return isScalarType(type) || isObjectType(type) || isInterfaceType(type) || isUnionType(type) || isEnumType(type) || isInputObjectType(type);\n}\nexport function assertNamedType(type) {\n if (!isNamedType(type)) {\n throw new Error(`Expected ${inspect(type)} to be a GraphQL named type.`);\n }\n\n return type;\n}\n/* eslint-disable no-redeclare */\n\nexport function getNamedType(type) {\n /* eslint-enable no-redeclare */\n if (type) {\n let unwrappedType = type;\n\n while (isWrappingType(unwrappedType)) {\n unwrappedType = unwrappedType.ofType;\n }\n\n return unwrappedType;\n }\n}\n/**\n * Used while defining GraphQL types to allow for circular references in\n * otherwise immutable type definitions.\n */\n\nfunction resolveThunk(thunk) {\n // $FlowFixMe[incompatible-use]\n return typeof thunk === 'function' ? thunk() : thunk;\n}\n\nfunction undefineIfEmpty(arr) {\n return arr && arr.length > 0 ? arr : undefined;\n}\n/**\n * Scalar Type Definition\n *\n * The leaf values of any request and input values to arguments are\n * Scalars (or Enums) and are defined with a name and a series of functions\n * used to parse input from ast or variables and to ensure validity.\n *\n * If a type's serialize function does not return a value (i.e. it returns\n * `undefined`) then an error will be raised and a `null` value will be returned\n * in the response. If the serialize function returns `null`, then no error will\n * be included in the response.\n *\n * Example:\n *\n * const OddType = new GraphQLScalarType({\n * name: 'Odd',\n * serialize(value) {\n * if (value % 2 === 1) {\n * return value;\n * }\n * }\n * });\n *\n */\n\n\nexport class GraphQLScalarType {\n constructor(config) {\n const parseValue = config.parseValue ?? identityFunc;\n this.name = config.name;\n this.description = config.description;\n this.specifiedByUrl = config.specifiedByUrl;\n this.serialize = config.serialize ?? identityFunc;\n this.parseValue = parseValue;\n\n this.parseLiteral = config.parseLiteral ?? ((node, variables) => parseValue(valueFromASTUntyped(node, variables)));\n\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);\n typeof config.name === 'string' || devAssert(0, 'Must provide name.');\n config.specifiedByUrl == null || typeof config.specifiedByUrl === 'string' || devAssert(0, `${this.name} must provide \"specifiedByUrl\" as a string, ` + `but got: ${inspect(config.specifiedByUrl)}.`);\n config.serialize == null || typeof config.serialize === 'function' || devAssert(0, `${this.name} must provide \"serialize\" function. If this custom Scalar is also used as an input type, ensure \"parseValue\" and \"parseLiteral\" functions are also provided.`);\n\n if (config.parseLiteral) {\n typeof config.parseValue === 'function' && typeof config.parseLiteral === 'function' || devAssert(0, `${this.name} must provide both \"parseValue\" and \"parseLiteral\" functions.`);\n }\n }\n\n toConfig() {\n return {\n name: this.name,\n description: this.description,\n specifiedByUrl: this.specifiedByUrl,\n serialize: this.serialize,\n parseValue: this.parseValue,\n parseLiteral: this.parseLiteral,\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes ?? []\n };\n }\n\n toString() {\n return this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLScalarType';\n }\n\n}\n\n/**\n * Object Type Definition\n *\n * Almost all of the GraphQL types you define will be object types. Object types\n * have a name, but most importantly describe their fields.\n *\n * Example:\n *\n * const AddressType = new GraphQLObjectType({\n * name: 'Address',\n * fields: {\n * street: { type: GraphQLString },\n * number: { type: GraphQLInt },\n * formatted: {\n * type: GraphQLString,\n * resolve(obj) {\n * return obj.number + ' ' + obj.street\n * }\n * }\n * }\n * });\n *\n * When two types need to refer to each other, or a type needs to refer to\n * itself in a field, you can use a function expression (aka a closure or a\n * thunk) to supply the fields lazily.\n *\n * Example:\n *\n * const PersonType = new GraphQLObjectType({\n * name: 'Person',\n * fields: () => ({\n * name: { type: GraphQLString },\n * bestFriend: { type: PersonType },\n * })\n * });\n *\n */\nexport class GraphQLObjectType {\n constructor(config) {\n this.name = config.name;\n this.description = config.description;\n this.isTypeOf = config.isTypeOf;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);\n this._fields = defineFieldMap.bind(undefined, config);\n this._interfaces = defineInterfaces.bind(undefined, config);\n typeof config.name === 'string' || devAssert(0, 'Must provide name.');\n config.isTypeOf == null || typeof config.isTypeOf === 'function' || devAssert(0, `${this.name} must provide \"isTypeOf\" as a function, ` + `but got: ${inspect(config.isTypeOf)}.`);\n }\n\n getFields() {\n if (typeof this._fields === 'function') {\n this._fields = this._fields();\n }\n\n return this._fields;\n }\n\n getInterfaces() {\n if (typeof this._interfaces === 'function') {\n this._interfaces = this._interfaces();\n }\n\n return this._interfaces;\n }\n\n toConfig() {\n return {\n name: this.name,\n description: this.description,\n interfaces: this.getInterfaces(),\n fields: fieldsToFieldsConfig(this.getFields()),\n isTypeOf: this.isTypeOf,\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes || []\n };\n }\n\n toString() {\n return this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLObjectType';\n }\n\n}\n\nfunction defineInterfaces(config) {\n const interfaces = resolveThunk(config.interfaces) ?? [];\n Array.isArray(interfaces) || devAssert(0, `${config.name} interfaces must be an Array or a function which returns an Array.`);\n return interfaces;\n}\n\nfunction defineFieldMap(config) {\n const fieldMap = resolveThunk(config.fields);\n isPlainObj(fieldMap) || devAssert(0, `${config.name} fields must be an object with field names as keys or a function which returns such an object.`);\n return mapValue(fieldMap, (fieldConfig, fieldName) => {\n isPlainObj(fieldConfig) || devAssert(0, `${config.name}.${fieldName} field config must be an object.`);\n fieldConfig.resolve == null || typeof fieldConfig.resolve === 'function' || devAssert(0, `${config.name}.${fieldName} field resolver must be a function if ` + `provided, but got: ${inspect(fieldConfig.resolve)}.`);\n const argsConfig = fieldConfig.args ?? {};\n isPlainObj(argsConfig) || devAssert(0, `${config.name}.${fieldName} args must be an object with argument names as keys.`);\n const args = objectEntries(argsConfig).map(([argName, argConfig]) => ({\n name: argName,\n description: argConfig.description,\n type: argConfig.type,\n defaultValue: argConfig.defaultValue,\n deprecationReason: argConfig.deprecationReason,\n extensions: argConfig.extensions && toObjMap(argConfig.extensions),\n astNode: argConfig.astNode\n }));\n return {\n name: fieldName,\n description: fieldConfig.description,\n type: fieldConfig.type,\n args,\n resolve: fieldConfig.resolve,\n subscribe: fieldConfig.subscribe,\n deprecationReason: fieldConfig.deprecationReason,\n extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions),\n astNode: fieldConfig.astNode\n };\n });\n}\n\nfunction isPlainObj(obj) {\n return isObjectLike(obj) && !Array.isArray(obj);\n}\n\nfunction fieldsToFieldsConfig(fields) {\n return mapValue(fields, field => ({\n description: field.description,\n type: field.type,\n args: argsToArgsConfig(field.args),\n resolve: field.resolve,\n subscribe: field.subscribe,\n deprecationReason: field.deprecationReason,\n extensions: field.extensions,\n astNode: field.astNode\n }));\n}\n/**\n * @internal\n */\n\n\nexport function argsToArgsConfig(args) {\n return keyValMap(args, arg => arg.name, arg => ({\n description: arg.description,\n type: arg.type,\n defaultValue: arg.defaultValue,\n deprecationReason: arg.deprecationReason,\n extensions: arg.extensions,\n astNode: arg.astNode\n }));\n}\nexport function isRequiredArgument(arg) {\n return isNonNullType(arg.type) && arg.defaultValue === undefined;\n}\n\n/**\n * Interface Type Definition\n *\n * When a field can return one of a heterogeneous set of types, a Interface type\n * is used to describe what types are possible, what fields are in common across\n * all types, as well as a function to determine which type is actually used\n * when the field is resolved.\n *\n * Example:\n *\n * const EntityType = new GraphQLInterfaceType({\n * name: 'Entity',\n * fields: {\n * name: { type: GraphQLString }\n * }\n * });\n *\n */\nexport class GraphQLInterfaceType {\n constructor(config) {\n this.name = config.name;\n this.description = config.description;\n this.resolveType = config.resolveType;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);\n this._fields = defineFieldMap.bind(undefined, config);\n this._interfaces = defineInterfaces.bind(undefined, config);\n typeof config.name === 'string' || devAssert(0, 'Must provide name.');\n config.resolveType == null || typeof config.resolveType === 'function' || devAssert(0, `${this.name} must provide \"resolveType\" as a function, ` + `but got: ${inspect(config.resolveType)}.`);\n }\n\n getFields() {\n if (typeof this._fields === 'function') {\n this._fields = this._fields();\n }\n\n return this._fields;\n }\n\n getInterfaces() {\n if (typeof this._interfaces === 'function') {\n this._interfaces = this._interfaces();\n }\n\n return this._interfaces;\n }\n\n toConfig() {\n return {\n name: this.name,\n description: this.description,\n interfaces: this.getInterfaces(),\n fields: fieldsToFieldsConfig(this.getFields()),\n resolveType: this.resolveType,\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes ?? []\n };\n }\n\n toString() {\n return this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLInterfaceType';\n }\n\n}\n\n/**\n * Union Type Definition\n *\n * When a field can return one of a heterogeneous set of types, a Union type\n * is used to describe what types are possible as well as providing a function\n * to determine which type is actually used when the field is resolved.\n *\n * Example:\n *\n * const PetType = new GraphQLUnionType({\n * name: 'Pet',\n * types: [ DogType, CatType ],\n * resolveType(value) {\n * if (value instanceof Dog) {\n * return DogType;\n * }\n * if (value instanceof Cat) {\n * return CatType;\n * }\n * }\n * });\n *\n */\nexport class GraphQLUnionType {\n constructor(config) {\n this.name = config.name;\n this.description = config.description;\n this.resolveType = config.resolveType;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);\n this._types = defineTypes.bind(undefined, config);\n typeof config.name === 'string' || devAssert(0, 'Must provide name.');\n config.resolveType == null || typeof config.resolveType === 'function' || devAssert(0, `${this.name} must provide \"resolveType\" as a function, ` + `but got: ${inspect(config.resolveType)}.`);\n }\n\n getTypes() {\n if (typeof this._types === 'function') {\n this._types = this._types();\n }\n\n return this._types;\n }\n\n toConfig() {\n return {\n name: this.name,\n description: this.description,\n types: this.getTypes(),\n resolveType: this.resolveType,\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes ?? []\n };\n }\n\n toString() {\n return this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLUnionType';\n }\n\n}\n\nfunction defineTypes(config) {\n const types = resolveThunk(config.types);\n Array.isArray(types) || devAssert(0, `Must provide Array of types or a function which returns such an array for Union ${config.name}.`);\n return types;\n}\n\n/**\n * Enum Type Definition\n *\n * Some leaf values of requests and input values are Enums. GraphQL serializes\n * Enum values as strings, however internally Enums can be represented by any\n * kind of type, often integers.\n *\n * Example:\n *\n * const RGBType = new GraphQLEnumType({\n * name: 'RGB',\n * values: {\n * RED: { value: 0 },\n * GREEN: { value: 1 },\n * BLUE: { value: 2 }\n * }\n * });\n *\n * Note: If a value is not provided in a definition, the name of the enum value\n * will be used as its internal value.\n */\nexport class GraphQLEnumType\n/* */\n{\n constructor(config) {\n this.name = config.name;\n this.description = config.description;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);\n this._values = defineEnumValues(this.name, config.values);\n this._valueLookup = new Map(this._values.map(enumValue => [enumValue.value, enumValue]));\n this._nameLookup = keyMap(this._values, value => value.name);\n typeof config.name === 'string' || devAssert(0, 'Must provide name.');\n }\n\n getValues() {\n return this._values;\n }\n\n getValue(name) {\n return this._nameLookup[name];\n }\n\n serialize(outputValue) {\n const enumValue = this._valueLookup.get(outputValue);\n\n if (enumValue === undefined) {\n throw new GraphQLError(`Enum \"${this.name}\" cannot represent value: ${inspect(outputValue)}`);\n }\n\n return enumValue.name;\n }\n\n parseValue(inputValue)\n /* T */\n {\n if (typeof inputValue !== 'string') {\n const valueStr = inspect(inputValue);\n throw new GraphQLError(`Enum \"${this.name}\" cannot represent non-string value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr));\n }\n\n const enumValue = this.getValue(inputValue);\n\n if (enumValue == null) {\n throw new GraphQLError(`Value \"${inputValue}\" does not exist in \"${this.name}\" enum.` + didYouMeanEnumValue(this, inputValue));\n }\n\n return enumValue.value;\n }\n\n parseLiteral(valueNode, _variables)\n /* T */\n {\n // Note: variables will be resolved to a value before calling this function.\n if (valueNode.kind !== Kind.ENUM) {\n const valueStr = print(valueNode);\n throw new GraphQLError(`Enum \"${this.name}\" cannot represent non-enum value: ${valueStr}.` + didYouMeanEnumValue(this, valueStr), valueNode);\n }\n\n const enumValue = this.getValue(valueNode.value);\n\n if (enumValue == null) {\n const valueStr = print(valueNode);\n throw new GraphQLError(`Value \"${valueStr}\" does not exist in \"${this.name}\" enum.` + didYouMeanEnumValue(this, valueStr), valueNode);\n }\n\n return enumValue.value;\n }\n\n toConfig() {\n const values = keyValMap(this.getValues(), value => value.name, value => ({\n description: value.description,\n value: value.value,\n deprecationReason: value.deprecationReason,\n extensions: value.extensions,\n astNode: value.astNode\n }));\n return {\n name: this.name,\n description: this.description,\n values,\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes ?? []\n };\n }\n\n toString() {\n return this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLEnumType';\n }\n\n}\n\nfunction didYouMeanEnumValue(enumType, unknownValueStr) {\n const allNames = enumType.getValues().map(value => value.name);\n const suggestedValues = suggestionList(unknownValueStr, allNames);\n return didYouMean('the enum value', suggestedValues);\n}\n\nfunction defineEnumValues(typeName, valueMap) {\n isPlainObj(valueMap) || devAssert(0, `${typeName} values must be an object with value names as keys.`);\n return objectEntries(valueMap).map(([valueName, valueConfig]) => {\n isPlainObj(valueConfig) || devAssert(0, `${typeName}.${valueName} must refer to an object with a \"value\" key ` + `representing an internal value but got: ${inspect(valueConfig)}.`);\n return {\n name: valueName,\n description: valueConfig.description,\n value: valueConfig.value !== undefined ? valueConfig.value : valueName,\n deprecationReason: valueConfig.deprecationReason,\n extensions: valueConfig.extensions && toObjMap(valueConfig.extensions),\n astNode: valueConfig.astNode\n };\n });\n}\n\n/**\n * Input Object Type Definition\n *\n * An input object defines a structured collection of fields which may be\n * supplied to a field argument.\n *\n * Using `NonNull` will ensure that a value must be provided by the query\n *\n * Example:\n *\n * const GeoPoint = new GraphQLInputObjectType({\n * name: 'GeoPoint',\n * fields: {\n * lat: { type: new GraphQLNonNull(GraphQLFloat) },\n * lon: { type: new GraphQLNonNull(GraphQLFloat) },\n * alt: { type: GraphQLFloat, defaultValue: 0 },\n * }\n * });\n *\n */\nexport class GraphQLInputObjectType {\n constructor(config) {\n this.name = config.name;\n this.description = config.description;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = undefineIfEmpty(config.extensionASTNodes);\n this._fields = defineInputFieldMap.bind(undefined, config);\n typeof config.name === 'string' || devAssert(0, 'Must provide name.');\n }\n\n getFields() {\n if (typeof this._fields === 'function') {\n this._fields = this._fields();\n }\n\n return this._fields;\n }\n\n toConfig() {\n const fields = mapValue(this.getFields(), field => ({\n description: field.description,\n type: field.type,\n defaultValue: field.defaultValue,\n extensions: field.extensions,\n astNode: field.astNode\n }));\n return {\n name: this.name,\n description: this.description,\n fields,\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes ?? []\n };\n }\n\n toString() {\n return this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLInputObjectType';\n }\n\n}\n\nfunction defineInputFieldMap(config) {\n const fieldMap = resolveThunk(config.fields);\n isPlainObj(fieldMap) || devAssert(0, `${config.name} fields must be an object with field names as keys or a function which returns such an object.`);\n return mapValue(fieldMap, (fieldConfig, fieldName) => {\n !('resolve' in fieldConfig) || devAssert(0, `${config.name}.${fieldName} field has a resolve property, but Input Types cannot define resolvers.`);\n return {\n name: fieldName,\n description: fieldConfig.description,\n type: fieldConfig.type,\n defaultValue: fieldConfig.defaultValue,\n deprecationReason: fieldConfig.deprecationReason,\n extensions: fieldConfig.extensions && toObjMap(fieldConfig.extensions),\n astNode: fieldConfig.astNode\n };\n });\n}\n\nexport function isRequiredInputField(field) {\n return isNonNullType(field.type) && field.defaultValue === undefined;\n}\n","import { isInterfaceType, isObjectType, isListType, isNonNullType, isAbstractType } from \"../type/definition.mjs\";\n/**\n * Provided two types, return true if the types are equal (invariant).\n */\n\nexport function isEqualType(typeA, typeB) {\n // Equivalent types are equal.\n if (typeA === typeB) {\n return true;\n } // If either type is non-null, the other must also be non-null.\n\n\n if (isNonNullType(typeA) && isNonNullType(typeB)) {\n return isEqualType(typeA.ofType, typeB.ofType);\n } // If either type is a list, the other must also be a list.\n\n\n if (isListType(typeA) && isListType(typeB)) {\n return isEqualType(typeA.ofType, typeB.ofType);\n } // Otherwise the types are not equal.\n\n\n return false;\n}\n/**\n * Provided a type and a super type, return true if the first type is either\n * equal or a subset of the second super type (covariant).\n */\n\nexport function isTypeSubTypeOf(schema, maybeSubType, superType) {\n // Equivalent type is a valid subtype\n if (maybeSubType === superType) {\n return true;\n } // If superType is non-null, maybeSubType must also be non-null.\n\n\n if (isNonNullType(superType)) {\n if (isNonNullType(maybeSubType)) {\n return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);\n }\n\n return false;\n }\n\n if (isNonNullType(maybeSubType)) {\n // If superType is nullable, maybeSubType may be non-null or nullable.\n return isTypeSubTypeOf(schema, maybeSubType.ofType, superType);\n } // If superType type is a list, maybeSubType type must also be a list.\n\n\n if (isListType(superType)) {\n if (isListType(maybeSubType)) {\n return isTypeSubTypeOf(schema, maybeSubType.ofType, superType.ofType);\n }\n\n return false;\n }\n\n if (isListType(maybeSubType)) {\n // If superType is not a list, maybeSubType must also be not a list.\n return false;\n } // If superType type is an abstract type, check if it is super type of maybeSubType.\n // Otherwise, the child type is not a valid subtype of the parent type.\n\n\n return isAbstractType(superType) && (isInterfaceType(maybeSubType) || isObjectType(maybeSubType)) && schema.isSubType(superType, maybeSubType);\n}\n/**\n * Provided two composite types, determine if they \"overlap\". Two composite\n * types overlap when the Sets of possible concrete types for each intersect.\n *\n * This is often used to determine if a fragment of a given type could possibly\n * be visited in a context of another type.\n *\n * This function is commutative.\n */\n\nexport function doTypesOverlap(schema, typeA, typeB) {\n // Equivalent types overlap\n if (typeA === typeB) {\n return true;\n }\n\n if (isAbstractType(typeA)) {\n if (isAbstractType(typeB)) {\n // If both types are abstract, then determine if there is any intersection\n // between possible concrete types of each.\n return schema.getPossibleTypes(typeA).some(type => schema.isSubType(typeB, type));\n } // Determine if the latter type is a possible concrete type of the former.\n\n\n return schema.isSubType(typeA, typeB);\n }\n\n if (isAbstractType(typeB)) {\n // Determine if the former type is a possible concrete type of the latter.\n return schema.isSubType(typeB, typeA);\n } // Otherwise the types do not overlap.\n\n\n return false;\n}\n","import inspect from \"../jsutils/inspect.mjs\";\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { print } from \"../language/printer.mjs\";\nimport { GraphQLError } from \"../error/GraphQLError.mjs\";\nimport { GraphQLScalarType } from \"./definition.mjs\"; // As per the GraphQL Spec, Integers are only treated as valid when a valid\n// 32-bit signed integer, providing the broadest support across platforms.\n//\n// n.b. JavaScript's integers are safe between -(2^53 - 1) and 2^53 - 1 because\n// they are internally represented as IEEE 754 doubles.\n\nconst MAX_INT = 2147483647;\nconst MIN_INT = -2147483648;\n\nfunction serializeInt(outputValue) {\n const coercedValue = serializeObject(outputValue);\n\n if (typeof coercedValue === 'boolean') {\n return coercedValue ? 1 : 0;\n }\n\n let num = coercedValue;\n\n if (typeof coercedValue === 'string' && coercedValue !== '') {\n num = Number(coercedValue);\n }\n\n if (typeof num !== 'number' || !Number.isInteger(num)) {\n throw new GraphQLError(`Int cannot represent non-integer value: ${inspect(coercedValue)}`);\n }\n\n if (num > MAX_INT || num < MIN_INT) {\n throw new GraphQLError('Int cannot represent non 32-bit signed integer value: ' + inspect(coercedValue));\n }\n\n return num;\n}\n\nfunction coerceInt(inputValue) {\n if (typeof inputValue !== 'number' || !Number.isInteger(inputValue)) {\n throw new GraphQLError(`Int cannot represent non-integer value: ${inspect(inputValue)}`);\n }\n\n if (inputValue > MAX_INT || inputValue < MIN_INT) {\n throw new GraphQLError(`Int cannot represent non 32-bit signed integer value: ${inputValue}`);\n }\n\n return inputValue;\n}\n\nexport const GraphQLInt = new GraphQLScalarType({\n name: 'Int',\n description: 'The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.',\n serialize: serializeInt,\n parseValue: coerceInt,\n\n parseLiteral(valueNode) {\n if (valueNode.kind !== Kind.INT) {\n throw new GraphQLError(`Int cannot represent non-integer value: ${print(valueNode)}`, valueNode);\n }\n\n const num = parseInt(valueNode.value, 10);\n\n if (num > MAX_INT || num < MIN_INT) {\n throw new GraphQLError(`Int cannot represent non 32-bit signed integer value: ${valueNode.value}`, valueNode);\n }\n\n return num;\n }\n\n});\n\nfunction serializeFloat(outputValue) {\n const coercedValue = serializeObject(outputValue);\n\n if (typeof coercedValue === 'boolean') {\n return coercedValue ? 1 : 0;\n }\n\n let num = coercedValue;\n\n if (typeof coercedValue === 'string' && coercedValue !== '') {\n num = Number(coercedValue);\n }\n\n if (typeof num !== 'number' || !Number.isFinite(num)) {\n throw new GraphQLError(`Float cannot represent non numeric value: ${inspect(coercedValue)}`);\n }\n\n return num;\n}\n\nfunction coerceFloat(inputValue) {\n if (typeof inputValue !== 'number' || !Number.isFinite(inputValue)) {\n throw new GraphQLError(`Float cannot represent non numeric value: ${inspect(inputValue)}`);\n }\n\n return inputValue;\n}\n\nexport const GraphQLFloat = new GraphQLScalarType({\n name: 'Float',\n description: 'The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).',\n serialize: serializeFloat,\n parseValue: coerceFloat,\n\n parseLiteral(valueNode) {\n if (valueNode.kind !== Kind.FLOAT && valueNode.kind !== Kind.INT) {\n throw new GraphQLError(`Float cannot represent non numeric value: ${print(valueNode)}`, valueNode);\n }\n\n return parseFloat(valueNode.value);\n }\n\n}); // Support serializing objects with custom valueOf() or toJSON() functions -\n// a common way to represent a complex value which can be represented as\n// a string (ex: MongoDB id objects).\n\nfunction serializeObject(outputValue) {\n if (isObjectLike(outputValue)) {\n if (typeof outputValue.valueOf === 'function') {\n const valueOfResult = outputValue.valueOf();\n\n if (!isObjectLike(valueOfResult)) {\n return valueOfResult;\n }\n }\n\n if (typeof outputValue.toJSON === 'function') {\n // $FlowFixMe[incompatible-use]\n return outputValue.toJSON();\n }\n }\n\n return outputValue;\n}\n\nfunction serializeString(outputValue) {\n const coercedValue = serializeObject(outputValue); // Serialize string, boolean and number values to a string, but do not\n // attempt to coerce object, function, symbol, or other types as strings.\n\n if (typeof coercedValue === 'string') {\n return coercedValue;\n }\n\n if (typeof coercedValue === 'boolean') {\n return coercedValue ? 'true' : 'false';\n }\n\n if (typeof coercedValue === 'number' && Number.isFinite(coercedValue)) {\n return coercedValue.toString();\n }\n\n throw new GraphQLError(`String cannot represent value: ${inspect(outputValue)}`);\n}\n\nfunction coerceString(inputValue) {\n if (typeof inputValue !== 'string') {\n throw new GraphQLError(`String cannot represent a non string value: ${inspect(inputValue)}`);\n }\n\n return inputValue;\n}\n\nexport const GraphQLString = new GraphQLScalarType({\n name: 'String',\n description: 'The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.',\n serialize: serializeString,\n parseValue: coerceString,\n\n parseLiteral(valueNode) {\n if (valueNode.kind !== Kind.STRING) {\n throw new GraphQLError(`String cannot represent a non string value: ${print(valueNode)}`, valueNode);\n }\n\n return valueNode.value;\n }\n\n});\n\nfunction serializeBoolean(outputValue) {\n const coercedValue = serializeObject(outputValue);\n\n if (typeof coercedValue === 'boolean') {\n return coercedValue;\n }\n\n if (Number.isFinite(coercedValue)) {\n return coercedValue !== 0;\n }\n\n throw new GraphQLError(`Boolean cannot represent a non boolean value: ${inspect(coercedValue)}`);\n}\n\nfunction coerceBoolean(inputValue) {\n if (typeof inputValue !== 'boolean') {\n throw new GraphQLError(`Boolean cannot represent a non boolean value: ${inspect(inputValue)}`);\n }\n\n return inputValue;\n}\n\nexport const GraphQLBoolean = new GraphQLScalarType({\n name: 'Boolean',\n description: 'The `Boolean` scalar type represents `true` or `false`.',\n serialize: serializeBoolean,\n parseValue: coerceBoolean,\n\n parseLiteral(valueNode) {\n if (valueNode.kind !== Kind.BOOLEAN) {\n throw new GraphQLError(`Boolean cannot represent a non boolean value: ${print(valueNode)}`, valueNode);\n }\n\n return valueNode.value;\n }\n\n});\n\nfunction serializeID(outputValue) {\n const coercedValue = serializeObject(outputValue);\n\n if (typeof coercedValue === 'string') {\n return coercedValue;\n }\n\n if (Number.isInteger(coercedValue)) {\n return String(coercedValue);\n }\n\n throw new GraphQLError(`ID cannot represent value: ${inspect(outputValue)}`);\n}\n\nfunction coerceID(inputValue) {\n if (typeof inputValue === 'string') {\n return inputValue;\n }\n\n if (typeof inputValue === 'number' && Number.isInteger(inputValue)) {\n return inputValue.toString();\n }\n\n throw new GraphQLError(`ID cannot represent value: ${inspect(inputValue)}`);\n}\n\nexport const GraphQLID = new GraphQLScalarType({\n name: 'ID',\n description: 'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.',\n serialize: serializeID,\n parseValue: coerceID,\n\n parseLiteral(valueNode) {\n if (valueNode.kind !== Kind.STRING && valueNode.kind !== Kind.INT) {\n throw new GraphQLError('ID cannot represent a non-string and non-integer value: ' + print(valueNode), valueNode);\n }\n\n return valueNode.value;\n }\n\n});\nexport const specifiedScalarTypes = Object.freeze([GraphQLString, GraphQLInt, GraphQLFloat, GraphQLBoolean, GraphQLID]);\nexport function isSpecifiedScalarType(type) {\n return specifiedScalarTypes.some(({\n name\n }) => type.name === name);\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport isCollection from \"../jsutils/isCollection.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { GraphQLID } from \"../type/scalars.mjs\";\nimport { isLeafType, isEnumType, isInputObjectType, isListType, isNonNullType } from \"../type/definition.mjs\";\n/**\n * Produces a GraphQL Value AST given a JavaScript object.\n * Function will match JavaScript/JSON values to GraphQL AST schema format\n * by using suggested GraphQLInputType. For example:\n *\n * astFromValue(\"value\", GraphQLString)\n *\n * A GraphQL type must be provided, which will be used to interpret different\n * JavaScript values.\n *\n * | JSON Value | GraphQL Value |\n * | ------------- | -------------------- |\n * | Object | Input Object |\n * | Array | List |\n * | Boolean | Boolean |\n * | String | String / Enum Value |\n * | Number | Int / Float |\n * | Mixed | Enum Value |\n * | null | NullValue |\n *\n */\n\nexport function astFromValue(value, type) {\n if (isNonNullType(type)) {\n const astValue = astFromValue(value, type.ofType);\n\n if (astValue?.kind === Kind.NULL) {\n return null;\n }\n\n return astValue;\n } // only explicit null, not undefined, NaN\n\n\n if (value === null) {\n return {\n kind: Kind.NULL\n };\n } // undefined\n\n\n if (value === undefined) {\n return null;\n } // Convert JavaScript array to GraphQL list. If the GraphQLType is a list, but\n // the value is not an array, convert the value using the list's item type.\n\n\n if (isListType(type)) {\n const itemType = type.ofType;\n\n if (isCollection(value)) {\n const valuesNodes = []; // Since we transpile for-of in loose mode it doesn't support iterators\n // and it's required to first convert iteratable into array\n\n for (const item of Array.from(value)) {\n const itemNode = astFromValue(item, itemType);\n\n if (itemNode != null) {\n valuesNodes.push(itemNode);\n }\n }\n\n return {\n kind: Kind.LIST,\n values: valuesNodes\n };\n }\n\n return astFromValue(value, itemType);\n } // Populate the fields of the input object by creating ASTs from each value\n // in the JavaScript object according to the fields in the input type.\n\n\n if (isInputObjectType(type)) {\n if (!isObjectLike(value)) {\n return null;\n }\n\n const fieldNodes = [];\n\n for (const field of objectValues(type.getFields())) {\n const fieldValue = astFromValue(value[field.name], field.type);\n\n if (fieldValue) {\n fieldNodes.push({\n kind: Kind.OBJECT_FIELD,\n name: {\n kind: Kind.NAME,\n value: field.name\n },\n value: fieldValue\n });\n }\n }\n\n return {\n kind: Kind.OBJECT,\n fields: fieldNodes\n };\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (isLeafType(type)) {\n // Since value is an internally represented value, it must be serialized\n // to an externally represented value before converting into an AST.\n const serialized = type.serialize(value);\n\n if (serialized == null) {\n return null;\n } // Others serialize based on their corresponding JavaScript scalar types.\n\n\n if (typeof serialized === 'boolean') {\n return {\n kind: Kind.BOOLEAN,\n value: serialized\n };\n } // JavaScript numbers can be Int or Float values.\n\n\n if (typeof serialized === 'number' && Number.isFinite(serialized)) {\n const stringNum = String(serialized);\n return integerStringRegExp.test(stringNum) ? {\n kind: Kind.INT,\n value: stringNum\n } : {\n kind: Kind.FLOAT,\n value: stringNum\n };\n }\n\n if (typeof serialized === 'string') {\n // Enum types use Enum literals.\n if (isEnumType(type)) {\n return {\n kind: Kind.ENUM,\n value: serialized\n };\n } // ID types can use Int literals.\n\n\n if (type === GraphQLID && integerStringRegExp.test(serialized)) {\n return {\n kind: Kind.INT,\n value: serialized\n };\n }\n\n return {\n kind: Kind.STRING,\n value: serialized\n };\n }\n\n throw new TypeError(`Cannot convert value to AST: ${inspect(serialized)}.`);\n } // istanbul ignore next (Not reachable. All possible input types have been considered)\n\n\n false || invariant(0, 'Unexpected input type: ' + inspect(type));\n}\n/**\n * IntValue:\n * - NegativeSign? 0\n * - NegativeSign? NonZeroDigit ( Digit+ )?\n */\n\nconst integerStringRegExp = /^-?(?:0|[1-9][0-9]*)$/;\n","/**\n * Returns true if the provided object is an Object (i.e. not a string literal)\n * and is either Iterable or Array-like.\n *\n * This may be used in place of [Array.isArray()][isArray] to determine if an\n * object should be iterated-over. It always excludes string literals and\n * includes Arrays (regardless of if it is Iterable). It also includes other\n * Array-like objects such as NodeList, TypedArray, and Buffer.\n *\n * @example\n *\n * isCollection([ 1, 2, 3 ]) // true\n * isCollection('ABC') // false\n * isCollection({ length: 1, 0: 'Alpha' }) // true\n * isCollection({ key: 'value' }) // false\n * isCollection(new Map()) // true\n *\n * @param obj\n * An Object value which might implement the Iterable or Array-like protocols.\n * @return {boolean} true if Iterable or Array-like Object.\n */\n// eslint-disable-next-line no-redeclare\nexport default function isCollection(obj) {\n if (obj == null || typeof obj !== 'object') {\n return false;\n } // Is Array like?\n\n\n const length = obj.length;\n\n if (typeof length === 'number' && length >= 0 && length % 1 === 0) {\n return true;\n } // Is Iterable?\n\n\n return typeof obj[Symbol.iterator] === 'function';\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport { print } from \"../language/printer.mjs\";\nimport { DirectiveLocation } from \"../language/directiveLocation.mjs\";\nimport { astFromValue } from \"../utilities/astFromValue.mjs\";\nimport { GraphQLString, GraphQLBoolean } from \"./scalars.mjs\";\nimport { GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLEnumType, isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType, isListType, isNonNullType, isAbstractType } from \"./definition.mjs\";\nexport const __Schema = new GraphQLObjectType({\n name: '__Schema',\n 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.',\n fields: () => ({\n description: {\n type: GraphQLString,\n resolve: schema => schema.description\n },\n types: {\n description: 'A list of all types supported by this server.',\n type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__Type))),\n\n resolve(schema) {\n return objectValues(schema.getTypeMap());\n }\n\n },\n queryType: {\n description: 'The type that query operations will be rooted at.',\n type: new GraphQLNonNull(__Type),\n resolve: schema => schema.getQueryType()\n },\n mutationType: {\n description: 'If this server supports mutation, the type that mutation operations will be rooted at.',\n type: __Type,\n resolve: schema => schema.getMutationType()\n },\n subscriptionType: {\n description: 'If this server support subscription, the type that subscription operations will be rooted at.',\n type: __Type,\n resolve: schema => schema.getSubscriptionType()\n },\n directives: {\n description: 'A list of all directives supported by this server.',\n type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__Directive))),\n resolve: schema => schema.getDirectives()\n }\n })\n});\nexport const __Directive = new GraphQLObjectType({\n name: '__Directive',\n 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.\",\n fields: () => ({\n name: {\n type: new GraphQLNonNull(GraphQLString),\n resolve: directive => directive.name\n },\n description: {\n type: GraphQLString,\n resolve: directive => directive.description\n },\n isRepeatable: {\n type: new GraphQLNonNull(GraphQLBoolean),\n resolve: directive => directive.isRepeatable\n },\n locations: {\n type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__DirectiveLocation))),\n resolve: directive => directive.locations\n },\n args: {\n type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__InputValue))),\n resolve: directive => directive.args\n }\n })\n});\nexport const __DirectiveLocation = new GraphQLEnumType({\n name: '__DirectiveLocation',\n description: 'A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.',\n values: {\n QUERY: {\n value: DirectiveLocation.QUERY,\n description: 'Location adjacent to a query operation.'\n },\n MUTATION: {\n value: DirectiveLocation.MUTATION,\n description: 'Location adjacent to a mutation operation.'\n },\n SUBSCRIPTION: {\n value: DirectiveLocation.SUBSCRIPTION,\n description: 'Location adjacent to a subscription operation.'\n },\n FIELD: {\n value: DirectiveLocation.FIELD,\n description: 'Location adjacent to a field.'\n },\n FRAGMENT_DEFINITION: {\n value: DirectiveLocation.FRAGMENT_DEFINITION,\n description: 'Location adjacent to a fragment definition.'\n },\n FRAGMENT_SPREAD: {\n value: DirectiveLocation.FRAGMENT_SPREAD,\n description: 'Location adjacent to a fragment spread.'\n },\n INLINE_FRAGMENT: {\n value: DirectiveLocation.INLINE_FRAGMENT,\n description: 'Location adjacent to an inline fragment.'\n },\n VARIABLE_DEFINITION: {\n value: DirectiveLocation.VARIABLE_DEFINITION,\n description: 'Location adjacent to a variable definition.'\n },\n SCHEMA: {\n value: DirectiveLocation.SCHEMA,\n description: 'Location adjacent to a schema definition.'\n },\n SCALAR: {\n value: DirectiveLocation.SCALAR,\n description: 'Location adjacent to a scalar definition.'\n },\n OBJECT: {\n value: DirectiveLocation.OBJECT,\n description: 'Location adjacent to an object type definition.'\n },\n FIELD_DEFINITION: {\n value: DirectiveLocation.FIELD_DEFINITION,\n description: 'Location adjacent to a field definition.'\n },\n ARGUMENT_DEFINITION: {\n value: DirectiveLocation.ARGUMENT_DEFINITION,\n description: 'Location adjacent to an argument definition.'\n },\n INTERFACE: {\n value: DirectiveLocation.INTERFACE,\n description: 'Location adjacent to an interface definition.'\n },\n UNION: {\n value: DirectiveLocation.UNION,\n description: 'Location adjacent to a union definition.'\n },\n ENUM: {\n value: DirectiveLocation.ENUM,\n description: 'Location adjacent to an enum definition.'\n },\n ENUM_VALUE: {\n value: DirectiveLocation.ENUM_VALUE,\n description: 'Location adjacent to an enum value definition.'\n },\n INPUT_OBJECT: {\n value: DirectiveLocation.INPUT_OBJECT,\n description: 'Location adjacent to an input object type definition.'\n },\n INPUT_FIELD_DEFINITION: {\n value: DirectiveLocation.INPUT_FIELD_DEFINITION,\n description: 'Location adjacent to an input object field definition.'\n }\n }\n});\nexport const __Type = new GraphQLObjectType({\n name: '__Type',\n description: 'The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\\n\\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByUrl`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.',\n fields: () => ({\n kind: {\n type: new GraphQLNonNull(__TypeKind),\n\n resolve(type) {\n if (isScalarType(type)) {\n return TypeKind.SCALAR;\n }\n\n if (isObjectType(type)) {\n return TypeKind.OBJECT;\n }\n\n if (isInterfaceType(type)) {\n return TypeKind.INTERFACE;\n }\n\n if (isUnionType(type)) {\n return TypeKind.UNION;\n }\n\n if (isEnumType(type)) {\n return TypeKind.ENUM;\n }\n\n if (isInputObjectType(type)) {\n return TypeKind.INPUT_OBJECT;\n }\n\n if (isListType(type)) {\n return TypeKind.LIST;\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (isNonNullType(type)) {\n return TypeKind.NON_NULL;\n } // istanbul ignore next (Not reachable. All possible types have been considered)\n\n\n false || invariant(0, `Unexpected type: \"${inspect(type)}\".`);\n }\n\n },\n name: {\n type: GraphQLString,\n resolve: type => type.name !== undefined ? type.name : undefined\n },\n description: {\n type: GraphQLString,\n resolve: type => type.description !== undefined ? type.description : undefined\n },\n specifiedByUrl: {\n type: GraphQLString,\n resolve: obj => obj.specifiedByUrl !== undefined ? obj.specifiedByUrl : undefined\n },\n fields: {\n type: new GraphQLList(new GraphQLNonNull(__Field)),\n args: {\n includeDeprecated: {\n type: GraphQLBoolean,\n defaultValue: false\n }\n },\n\n resolve(type, {\n includeDeprecated\n }) {\n if (isObjectType(type) || isInterfaceType(type)) {\n const fields = objectValues(type.getFields());\n return includeDeprecated ? fields : fields.filter(field => field.deprecationReason == null);\n }\n }\n\n },\n interfaces: {\n type: new GraphQLList(new GraphQLNonNull(__Type)),\n\n resolve(type) {\n if (isObjectType(type) || isInterfaceType(type)) {\n return type.getInterfaces();\n }\n }\n\n },\n possibleTypes: {\n type: new GraphQLList(new GraphQLNonNull(__Type)),\n\n resolve(type, _args, _context, {\n schema\n }) {\n if (isAbstractType(type)) {\n return schema.getPossibleTypes(type);\n }\n }\n\n },\n enumValues: {\n type: new GraphQLList(new GraphQLNonNull(__EnumValue)),\n args: {\n includeDeprecated: {\n type: GraphQLBoolean,\n defaultValue: false\n }\n },\n\n resolve(type, {\n includeDeprecated\n }) {\n if (isEnumType(type)) {\n const values = type.getValues();\n return includeDeprecated ? values : values.filter(field => field.deprecationReason == null);\n }\n }\n\n },\n inputFields: {\n type: new GraphQLList(new GraphQLNonNull(__InputValue)),\n args: {\n includeDeprecated: {\n type: GraphQLBoolean,\n defaultValue: false\n }\n },\n\n resolve(type, {\n includeDeprecated\n }) {\n if (isInputObjectType(type)) {\n const values = objectValues(type.getFields());\n return includeDeprecated ? values : values.filter(field => field.deprecationReason == null);\n }\n }\n\n },\n ofType: {\n type: __Type,\n resolve: type => type.ofType !== undefined ? type.ofType : undefined\n }\n })\n});\nexport const __Field = new GraphQLObjectType({\n name: '__Field',\n 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.',\n fields: () => ({\n name: {\n type: new GraphQLNonNull(GraphQLString),\n resolve: field => field.name\n },\n description: {\n type: GraphQLString,\n resolve: field => field.description\n },\n args: {\n type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(__InputValue))),\n args: {\n includeDeprecated: {\n type: GraphQLBoolean,\n defaultValue: false\n }\n },\n\n resolve(field, {\n includeDeprecated\n }) {\n return includeDeprecated ? field.args : field.args.filter(arg => arg.deprecationReason == null);\n }\n\n },\n type: {\n type: new GraphQLNonNull(__Type),\n resolve: field => field.type\n },\n isDeprecated: {\n type: new GraphQLNonNull(GraphQLBoolean),\n resolve: field => field.deprecationReason != null\n },\n deprecationReason: {\n type: GraphQLString,\n resolve: field => field.deprecationReason\n }\n })\n});\nexport const __InputValue = new GraphQLObjectType({\n name: '__InputValue',\n description: 'Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.',\n fields: () => ({\n name: {\n type: new GraphQLNonNull(GraphQLString),\n resolve: inputValue => inputValue.name\n },\n description: {\n type: GraphQLString,\n resolve: inputValue => inputValue.description\n },\n type: {\n type: new GraphQLNonNull(__Type),\n resolve: inputValue => inputValue.type\n },\n defaultValue: {\n type: GraphQLString,\n description: 'A GraphQL-formatted string representing the default value for this input value.',\n\n resolve(inputValue) {\n const {\n type,\n defaultValue\n } = inputValue;\n const valueAST = astFromValue(defaultValue, type);\n return valueAST ? print(valueAST) : null;\n }\n\n },\n isDeprecated: {\n type: new GraphQLNonNull(GraphQLBoolean),\n resolve: field => field.deprecationReason != null\n },\n deprecationReason: {\n type: GraphQLString,\n resolve: obj => obj.deprecationReason\n }\n })\n});\nexport const __EnumValue = new GraphQLObjectType({\n name: '__EnumValue',\n 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.',\n fields: () => ({\n name: {\n type: new GraphQLNonNull(GraphQLString),\n resolve: enumValue => enumValue.name\n },\n description: {\n type: GraphQLString,\n resolve: enumValue => enumValue.description\n },\n isDeprecated: {\n type: new GraphQLNonNull(GraphQLBoolean),\n resolve: enumValue => enumValue.deprecationReason != null\n },\n deprecationReason: {\n type: GraphQLString,\n resolve: enumValue => enumValue.deprecationReason\n }\n })\n});\nexport const TypeKind = Object.freeze({\n SCALAR: 'SCALAR',\n OBJECT: 'OBJECT',\n INTERFACE: 'INTERFACE',\n UNION: 'UNION',\n ENUM: 'ENUM',\n INPUT_OBJECT: 'INPUT_OBJECT',\n LIST: 'LIST',\n NON_NULL: 'NON_NULL'\n});\nexport const __TypeKind = new GraphQLEnumType({\n name: '__TypeKind',\n description: 'An enum describing what kind of type a given `__Type` is.',\n values: {\n SCALAR: {\n value: TypeKind.SCALAR,\n description: 'Indicates this type is a scalar.'\n },\n OBJECT: {\n value: TypeKind.OBJECT,\n description: 'Indicates this type is an object. `fields` and `interfaces` are valid fields.'\n },\n INTERFACE: {\n value: TypeKind.INTERFACE,\n description: 'Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields.'\n },\n UNION: {\n value: TypeKind.UNION,\n description: 'Indicates this type is a union. `possibleTypes` is a valid field.'\n },\n ENUM: {\n value: TypeKind.ENUM,\n description: 'Indicates this type is an enum. `enumValues` is a valid field.'\n },\n INPUT_OBJECT: {\n value: TypeKind.INPUT_OBJECT,\n description: 'Indicates this type is an input object. `inputFields` is a valid field.'\n },\n LIST: {\n value: TypeKind.LIST,\n description: 'Indicates this type is a list. `ofType` is a valid field.'\n },\n NON_NULL: {\n value: TypeKind.NON_NULL,\n description: 'Indicates this type is a non-null. `ofType` is a valid field.'\n }\n }\n});\n/**\n * Note that these are GraphQLField and not GraphQLFieldConfig,\n * so the format for args is different.\n */\n\nexport const SchemaMetaFieldDef = {\n name: '__schema',\n type: new GraphQLNonNull(__Schema),\n description: 'Access the current type schema of this server.',\n args: [],\n resolve: (_source, _args, _context, {\n schema\n }) => schema,\n deprecationReason: undefined,\n extensions: undefined,\n astNode: undefined\n};\nexport const TypeMetaFieldDef = {\n name: '__type',\n type: __Type,\n description: 'Request the type information of a single type.',\n args: [{\n name: 'name',\n description: undefined,\n type: new GraphQLNonNull(GraphQLString),\n defaultValue: undefined,\n deprecationReason: undefined,\n extensions: undefined,\n astNode: undefined\n }],\n resolve: (_source, {\n name\n }, _context, {\n schema\n }) => schema.getType(name),\n deprecationReason: undefined,\n extensions: undefined,\n astNode: undefined\n};\nexport const TypeNameMetaFieldDef = {\n name: '__typename',\n type: new GraphQLNonNull(GraphQLString),\n description: 'The name of the current Object type at runtime.',\n args: [],\n resolve: (_source, _args, _context, {\n parentType\n }) => parentType.name,\n deprecationReason: undefined,\n extensions: undefined,\n astNode: undefined\n};\nexport const introspectionTypes = Object.freeze([__Schema, __Directive, __DirectiveLocation, __Type, __Field, __InputValue, __EnumValue, __TypeKind]);\nexport function isIntrospectionType(type) {\n return introspectionTypes.some(({\n name\n }) => type.name === name);\n}\n","import objectEntries from \"../polyfills/objectEntries.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport toObjMap from \"../jsutils/toObjMap.mjs\";\nimport devAssert from \"../jsutils/devAssert.mjs\";\nimport instanceOf from \"../jsutils/instanceOf.mjs\";\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport { DirectiveLocation } from \"../language/directiveLocation.mjs\";\nimport { GraphQLString, GraphQLBoolean } from \"./scalars.mjs\";\nimport { argsToArgsConfig, GraphQLNonNull } from \"./definition.mjs\";\n/**\n * Test if the given value is a GraphQL directive.\n */\n\n// eslint-disable-next-line no-redeclare\nexport function isDirective(directive) {\n return instanceOf(directive, GraphQLDirective);\n}\nexport function assertDirective(directive) {\n if (!isDirective(directive)) {\n throw new Error(`Expected ${inspect(directive)} to be a GraphQL directive.`);\n }\n\n return directive;\n}\n/**\n * Directives are used by the GraphQL runtime as a way of modifying execution\n * behavior. Type system creators will usually not create these directly.\n */\n\nexport class GraphQLDirective {\n constructor(config) {\n this.name = config.name;\n this.description = config.description;\n this.locations = config.locations;\n this.isRepeatable = config.isRepeatable ?? false;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n config.name || devAssert(0, 'Directive must be named.');\n Array.isArray(config.locations) || devAssert(0, `@${config.name} locations must be an Array.`);\n const args = config.args ?? {};\n isObjectLike(args) && !Array.isArray(args) || devAssert(0, `@${config.name} args must be an object with argument names as keys.`);\n this.args = objectEntries(args).map(([argName, argConfig]) => ({\n name: argName,\n description: argConfig.description,\n type: argConfig.type,\n defaultValue: argConfig.defaultValue,\n deprecationReason: argConfig.deprecationReason,\n extensions: argConfig.extensions && toObjMap(argConfig.extensions),\n astNode: argConfig.astNode\n }));\n }\n\n toConfig() {\n return {\n name: this.name,\n description: this.description,\n locations: this.locations,\n args: argsToArgsConfig(this.args),\n isRepeatable: this.isRepeatable,\n extensions: this.extensions,\n astNode: this.astNode\n };\n }\n\n toString() {\n return '@' + this.name;\n }\n\n toJSON() {\n return this.toString();\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLDirective';\n }\n\n}\n\n/**\n * Used to conditionally include fields or fragments.\n */\nexport const GraphQLIncludeDirective = new GraphQLDirective({\n name: 'include',\n description: 'Directs the executor to include this field or fragment only when the `if` argument is true.',\n locations: [DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT],\n args: {\n if: {\n type: new GraphQLNonNull(GraphQLBoolean),\n description: 'Included when true.'\n }\n }\n});\n/**\n * Used to conditionally skip (exclude) fields or fragments.\n */\n\nexport const GraphQLSkipDirective = new GraphQLDirective({\n name: 'skip',\n description: 'Directs the executor to skip this field or fragment when the `if` argument is true.',\n locations: [DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT],\n args: {\n if: {\n type: new GraphQLNonNull(GraphQLBoolean),\n description: 'Skipped when true.'\n }\n }\n});\n/**\n * Constant string used for default reason for a deprecation.\n */\n\nexport const DEFAULT_DEPRECATION_REASON = 'No longer supported';\n/**\n * Used to declare element of a GraphQL schema as deprecated.\n */\n\nexport const GraphQLDeprecatedDirective = new GraphQLDirective({\n name: 'deprecated',\n description: 'Marks an element of a GraphQL schema as no longer supported.',\n locations: [DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ARGUMENT_DEFINITION, DirectiveLocation.INPUT_FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE],\n args: {\n reason: {\n type: GraphQLString,\n description: 'Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).',\n defaultValue: DEFAULT_DEPRECATION_REASON\n }\n }\n});\n/**\n * Used to provide a URL for specifying the behaviour of custom scalar definitions.\n */\n\nexport const GraphQLSpecifiedByDirective = new GraphQLDirective({\n name: 'specifiedBy',\n description: 'Exposes a URL that specifies the behaviour of this scalar.',\n locations: [DirectiveLocation.SCALAR],\n args: {\n url: {\n type: new GraphQLNonNull(GraphQLString),\n description: 'The URL that specifies the behaviour of this scalar.'\n }\n }\n});\n/**\n * The full list of specified directives.\n */\n\nexport const specifiedDirectives = Object.freeze([GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective]);\nexport function isSpecifiedDirective(directive) {\n return specifiedDirectives.some(({\n name\n }) => name === directive.name);\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport toObjMap from \"../jsutils/toObjMap.mjs\";\nimport devAssert from \"../jsutils/devAssert.mjs\";\nimport instanceOf from \"../jsutils/instanceOf.mjs\";\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport { __Schema } from \"./introspection.mjs\";\nimport { GraphQLDirective, isDirective, specifiedDirectives } from \"./directives.mjs\";\nimport { isObjectType, isInterfaceType, isUnionType, isInputObjectType, getNamedType } from \"./definition.mjs\";\n/**\n * Test if the given value is a GraphQL schema.\n */\n\n// eslint-disable-next-line no-redeclare\nexport function isSchema(schema) {\n return instanceOf(schema, GraphQLSchema);\n}\nexport function assertSchema(schema) {\n if (!isSchema(schema)) {\n throw new Error(`Expected ${inspect(schema)} to be a GraphQL schema.`);\n }\n\n return schema;\n}\n/**\n * Schema Definition\n *\n * A Schema is created by supplying the root types of each type of operation,\n * query and mutation (optional). A schema definition is then supplied to the\n * validator and executor.\n *\n * Example:\n *\n * const MyAppSchema = new GraphQLSchema({\n * query: MyAppQueryRootType,\n * mutation: MyAppMutationRootType,\n * })\n *\n * Note: When the schema is constructed, by default only the types that are\n * reachable by traversing the root types are included, other types must be\n * explicitly referenced.\n *\n * Example:\n *\n * const characterInterface = new GraphQLInterfaceType({\n * name: 'Character',\n * ...\n * });\n *\n * const humanType = new GraphQLObjectType({\n * name: 'Human',\n * interfaces: [characterInterface],\n * ...\n * });\n *\n * const droidType = new GraphQLObjectType({\n * name: 'Droid',\n * interfaces: [characterInterface],\n * ...\n * });\n *\n * const schema = new GraphQLSchema({\n * query: new GraphQLObjectType({\n * name: 'Query',\n * fields: {\n * hero: { type: characterInterface, ... },\n * }\n * }),\n * ...\n * // Since this schema references only the `Character` interface it's\n * // necessary to explicitly list the types that implement it if\n * // you want them to be included in the final schema.\n * types: [humanType, droidType],\n * })\n *\n * Note: If an array of `directives` are provided to GraphQLSchema, that will be\n * the exact list of directives represented and allowed. If `directives` is not\n * provided then a default set of the specified directives (e.g. @include and\n * @skip) will be used. If you wish to provide *additional* directives to these\n * specified directives, you must explicitly declare them. Example:\n *\n * const MyAppSchema = new GraphQLSchema({\n * ...\n * directives: specifiedDirectives.concat([ myCustomDirective ]),\n * })\n *\n */\n\nexport class GraphQLSchema {\n // Used as a cache for validateSchema().\n constructor(config) {\n // If this schema was built from a source known to be valid, then it may be\n // marked with assumeValid to avoid an additional type system validation.\n this.__validationErrors = config.assumeValid === true ? [] : undefined; // Check for common mistakes during construction to produce early errors.\n\n isObjectLike(config) || devAssert(0, 'Must provide configuration object.');\n !config.types || Array.isArray(config.types) || devAssert(0, `\"types\" must be Array if provided but got: ${inspect(config.types)}.`);\n !config.directives || Array.isArray(config.directives) || devAssert(0, '\"directives\" must be Array if provided but got: ' + `${inspect(config.directives)}.`);\n this.description = config.description;\n this.extensions = config.extensions && toObjMap(config.extensions);\n this.astNode = config.astNode;\n this.extensionASTNodes = config.extensionASTNodes;\n this._queryType = config.query;\n this._mutationType = config.mutation;\n this._subscriptionType = config.subscription; // Provide specified directives (e.g. @include and @skip) by default.\n\n this._directives = config.directives ?? specifiedDirectives; // To preserve order of user-provided types, we add first to add them to\n // the set of \"collected\" types, so `collectReferencedTypes` ignore them.\n\n const allReferencedTypes = new Set(config.types);\n\n if (config.types != null) {\n for (const type of config.types) {\n // When we ready to process this type, we remove it from \"collected\" types\n // and then add it together with all dependent types in the correct position.\n allReferencedTypes.delete(type);\n collectReferencedTypes(type, allReferencedTypes);\n }\n }\n\n if (this._queryType != null) {\n collectReferencedTypes(this._queryType, allReferencedTypes);\n }\n\n if (this._mutationType != null) {\n collectReferencedTypes(this._mutationType, allReferencedTypes);\n }\n\n if (this._subscriptionType != null) {\n collectReferencedTypes(this._subscriptionType, allReferencedTypes);\n }\n\n for (const directive of this._directives) {\n // Directives are not validated until validateSchema() is called.\n if (isDirective(directive)) {\n for (const arg of directive.args) {\n collectReferencedTypes(arg.type, allReferencedTypes);\n }\n }\n }\n\n collectReferencedTypes(__Schema, allReferencedTypes); // Storing the resulting map for reference by the schema.\n\n this._typeMap = Object.create(null);\n this._subTypeMap = Object.create(null); // Keep track of all implementations by interface name.\n\n this._implementationsMap = Object.create(null);\n\n for (const namedType of Array.from(allReferencedTypes)) {\n if (namedType == null) {\n continue;\n }\n\n const typeName = namedType.name;\n typeName || devAssert(0, 'One of the provided types for building the Schema is missing a name.');\n\n if (this._typeMap[typeName] !== undefined) {\n throw new Error(`Schema must contain uniquely named types but contains multiple types named \"${typeName}\".`);\n }\n\n this._typeMap[typeName] = namedType;\n\n if (isInterfaceType(namedType)) {\n // Store implementations by interface.\n for (const iface of namedType.getInterfaces()) {\n if (isInterfaceType(iface)) {\n let implementations = this._implementationsMap[iface.name];\n\n if (implementations === undefined) {\n implementations = this._implementationsMap[iface.name] = {\n objects: [],\n interfaces: []\n };\n }\n\n implementations.interfaces.push(namedType);\n }\n }\n } else if (isObjectType(namedType)) {\n // Store implementations by objects.\n for (const iface of namedType.getInterfaces()) {\n if (isInterfaceType(iface)) {\n let implementations = this._implementationsMap[iface.name];\n\n if (implementations === undefined) {\n implementations = this._implementationsMap[iface.name] = {\n objects: [],\n interfaces: []\n };\n }\n\n implementations.objects.push(namedType);\n }\n }\n }\n }\n }\n\n getQueryType() {\n return this._queryType;\n }\n\n getMutationType() {\n return this._mutationType;\n }\n\n getSubscriptionType() {\n return this._subscriptionType;\n }\n\n getTypeMap() {\n return this._typeMap;\n }\n\n getType(name) {\n return this.getTypeMap()[name];\n }\n\n getPossibleTypes(abstractType) {\n return isUnionType(abstractType) ? abstractType.getTypes() : this.getImplementations(abstractType).objects;\n }\n\n getImplementations(interfaceType) {\n const implementations = this._implementationsMap[interfaceType.name];\n return implementations ?? {\n objects: [],\n interfaces: []\n };\n }\n\n isSubType(abstractType, maybeSubType) {\n let map = this._subTypeMap[abstractType.name];\n\n if (map === undefined) {\n map = Object.create(null);\n\n if (isUnionType(abstractType)) {\n for (const type of abstractType.getTypes()) {\n map[type.name] = true;\n }\n } else {\n const implementations = this.getImplementations(abstractType);\n\n for (const type of implementations.objects) {\n map[type.name] = true;\n }\n\n for (const type of implementations.interfaces) {\n map[type.name] = true;\n }\n }\n\n this._subTypeMap[abstractType.name] = map;\n }\n\n return map[maybeSubType.name] !== undefined;\n }\n\n getDirectives() {\n return this._directives;\n }\n\n getDirective(name) {\n return this.getDirectives().find(directive => directive.name === name);\n }\n\n toConfig() {\n return {\n description: this.description,\n query: this.getQueryType(),\n mutation: this.getMutationType(),\n subscription: this.getSubscriptionType(),\n types: objectValues(this.getTypeMap()),\n directives: this.getDirectives().slice(),\n extensions: this.extensions,\n astNode: this.astNode,\n extensionASTNodes: this.extensionASTNodes ?? [],\n assumeValid: this.__validationErrors !== undefined\n };\n } // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet\n\n\n get [Symbol.toStringTag]() {\n return 'GraphQLSchema';\n }\n\n}\n\nfunction collectReferencedTypes(type, typeSet) {\n const namedType = getNamedType(type);\n\n if (!typeSet.has(namedType)) {\n typeSet.add(namedType);\n\n if (isUnionType(namedType)) {\n for (const memberType of namedType.getTypes()) {\n collectReferencedTypes(memberType, typeSet);\n }\n } else if (isObjectType(namedType) || isInterfaceType(namedType)) {\n for (const interfaceType of namedType.getInterfaces()) {\n collectReferencedTypes(interfaceType, typeSet);\n }\n\n for (const field of objectValues(namedType.getFields())) {\n collectReferencedTypes(field.type, typeSet);\n\n for (const arg of field.args) {\n collectReferencedTypes(arg.type, typeSet);\n }\n }\n } else if (isInputObjectType(namedType)) {\n for (const field of objectValues(namedType.getFields())) {\n collectReferencedTypes(field.type, typeSet);\n }\n }\n }\n\n return typeSet;\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport { GraphQLError } from \"../error/GraphQLError.mjs\";\nimport { locatedError } from \"../error/locatedError.mjs\";\nimport { isValidNameError } from \"../utilities/assertValidName.mjs\";\nimport { isEqualType, isTypeSubTypeOf } from \"../utilities/typeComparators.mjs\";\nimport { assertSchema } from \"./schema.mjs\";\nimport { isIntrospectionType } from \"./introspection.mjs\";\nimport { isDirective, GraphQLDeprecatedDirective } from \"./directives.mjs\";\nimport { isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType, isNamedType, isNonNullType, isInputType, isOutputType, isRequiredArgument, isRequiredInputField } from \"./definition.mjs\";\n/**\n * Implements the \"Type Validation\" sub-sections of the specification's\n * \"Type System\" section.\n *\n * Validation runs synchronously, returning an array of encountered errors, or\n * an empty array if no errors were encountered and the Schema is valid.\n */\n\nexport function validateSchema(schema) {\n // First check to ensure the provided value is in fact a GraphQLSchema.\n assertSchema(schema); // If this Schema has already been validated, return the previous results.\n\n if (schema.__validationErrors) {\n return schema.__validationErrors;\n } // Validate the schema, producing a list of errors.\n\n\n const context = new SchemaValidationContext(schema);\n validateRootTypes(context);\n validateDirectives(context);\n validateTypes(context); // Persist the results of validation before returning to ensure validation\n // does not run multiple times for this schema.\n\n const errors = context.getErrors();\n schema.__validationErrors = errors;\n return errors;\n}\n/**\n * Utility function which asserts a schema is valid by throwing an error if\n * it is invalid.\n */\n\nexport function assertValidSchema(schema) {\n const errors = validateSchema(schema);\n\n if (errors.length !== 0) {\n throw new Error(errors.map(error => error.message).join('\\n\\n'));\n }\n}\n\nclass SchemaValidationContext {\n constructor(schema) {\n this._errors = [];\n this.schema = schema;\n }\n\n reportError(message, nodes) {\n const _nodes = Array.isArray(nodes) ? nodes.filter(Boolean) : nodes;\n\n this.addError(new GraphQLError(message, _nodes));\n }\n\n addError(error) {\n this._errors.push(error);\n }\n\n getErrors() {\n return this._errors;\n }\n\n}\n\nfunction validateRootTypes(context) {\n const schema = context.schema;\n const queryType = schema.getQueryType();\n\n if (!queryType) {\n context.reportError('Query root type must be provided.', schema.astNode);\n } else if (!isObjectType(queryType)) {\n context.reportError(`Query root type must be Object type, it cannot be ${inspect(queryType)}.`, getOperationTypeNode(schema, 'query') ?? queryType.astNode);\n }\n\n const mutationType = schema.getMutationType();\n\n if (mutationType && !isObjectType(mutationType)) {\n context.reportError('Mutation root type must be Object type if provided, it cannot be ' + `${inspect(mutationType)}.`, getOperationTypeNode(schema, 'mutation') ?? mutationType.astNode);\n }\n\n const subscriptionType = schema.getSubscriptionType();\n\n if (subscriptionType && !isObjectType(subscriptionType)) {\n context.reportError('Subscription root type must be Object type if provided, it cannot be ' + `${inspect(subscriptionType)}.`, getOperationTypeNode(schema, 'subscription') ?? subscriptionType.astNode);\n }\n}\n\nfunction getOperationTypeNode(schema, operation) {\n const operationNodes = getAllSubNodes(schema, node => node.operationTypes);\n\n for (const node of operationNodes) {\n if (node.operation === operation) {\n return node.type;\n }\n }\n\n return undefined;\n}\n\nfunction validateDirectives(context) {\n for (const directive of context.schema.getDirectives()) {\n // Ensure all directives are in fact GraphQL directives.\n if (!isDirective(directive)) {\n context.reportError(`Expected directive but got: ${inspect(directive)}.`, directive?.astNode);\n continue;\n } // Ensure they are named correctly.\n\n\n validateName(context, directive); // TODO: Ensure proper locations.\n // Ensure the arguments are valid.\n\n for (const arg of directive.args) {\n // Ensure they are named correctly.\n validateName(context, arg); // Ensure the type is an input type.\n\n if (!isInputType(arg.type)) {\n context.reportError(`The type of @${directive.name}(${arg.name}:) must be Input Type ` + `but got: ${inspect(arg.type)}.`, arg.astNode);\n }\n\n if (isRequiredArgument(arg) && arg.deprecationReason != null) {\n context.reportError(`Required argument @${directive.name}(${arg.name}:) cannot be deprecated.`, [getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests)\n arg.astNode?.type]);\n }\n }\n }\n}\n\nfunction validateName(context, node) {\n // Ensure names are valid, however introspection types opt out.\n const error = isValidNameError(node.name);\n\n if (error) {\n context.addError(locatedError(error, node.astNode));\n }\n}\n\nfunction validateTypes(context) {\n const validateInputObjectCircularRefs = createInputObjectCircularRefsValidator(context);\n const typeMap = context.schema.getTypeMap();\n\n for (const type of objectValues(typeMap)) {\n // Ensure all provided types are in fact GraphQL type.\n if (!isNamedType(type)) {\n context.reportError(`Expected GraphQL named type but got: ${inspect(type)}.`, type.astNode);\n continue;\n } // Ensure it is named correctly (excluding introspection types).\n\n\n if (!isIntrospectionType(type)) {\n validateName(context, type);\n }\n\n if (isObjectType(type)) {\n // Ensure fields are valid\n validateFields(context, type); // Ensure objects implement the interfaces they claim to.\n\n validateInterfaces(context, type);\n } else if (isInterfaceType(type)) {\n // Ensure fields are valid.\n validateFields(context, type); // Ensure interfaces implement the interfaces they claim to.\n\n validateInterfaces(context, type);\n } else if (isUnionType(type)) {\n // Ensure Unions include valid member types.\n validateUnionMembers(context, type);\n } else if (isEnumType(type)) {\n // Ensure Enums have valid values.\n validateEnumValues(context, type);\n } else if (isInputObjectType(type)) {\n // Ensure Input Object fields are valid.\n validateInputFields(context, type); // Ensure Input Objects do not contain non-nullable circular references\n\n validateInputObjectCircularRefs(type);\n }\n }\n}\n\nfunction validateFields(context, type) {\n const fields = objectValues(type.getFields()); // Objects and Interfaces both must define one or more fields.\n\n if (fields.length === 0) {\n context.reportError(`Type ${type.name} must define one or more fields.`, getAllNodes(type));\n }\n\n for (const field of fields) {\n // Ensure they are named correctly.\n validateName(context, field); // Ensure the type is an output type\n\n if (!isOutputType(field.type)) {\n context.reportError(`The type of ${type.name}.${field.name} must be Output Type ` + `but got: ${inspect(field.type)}.`, field.astNode?.type);\n } // Ensure the arguments are valid\n\n\n for (const arg of field.args) {\n const argName = arg.name; // Ensure they are named correctly.\n\n validateName(context, arg); // Ensure the type is an input type\n\n if (!isInputType(arg.type)) {\n context.reportError(`The type of ${type.name}.${field.name}(${argName}:) must be Input ` + `Type but got: ${inspect(arg.type)}.`, arg.astNode?.type);\n }\n\n if (isRequiredArgument(arg) && arg.deprecationReason != null) {\n context.reportError(`Required argument ${type.name}.${field.name}(${argName}:) cannot be deprecated.`, [getDeprecatedDirectiveNode(arg.astNode), // istanbul ignore next (TODO need to write coverage tests)\n arg.astNode?.type]);\n }\n }\n }\n}\n\nfunction validateInterfaces(context, type) {\n const ifaceTypeNames = Object.create(null);\n\n for (const iface of type.getInterfaces()) {\n if (!isInterfaceType(iface)) {\n context.reportError(`Type ${inspect(type)} must only implement Interface types, ` + `it cannot implement ${inspect(iface)}.`, getAllImplementsInterfaceNodes(type, iface));\n continue;\n }\n\n if (type === iface) {\n context.reportError(`Type ${type.name} cannot implement itself because it would create a circular reference.`, getAllImplementsInterfaceNodes(type, iface));\n continue;\n }\n\n if (ifaceTypeNames[iface.name]) {\n context.reportError(`Type ${type.name} can only implement ${iface.name} once.`, getAllImplementsInterfaceNodes(type, iface));\n continue;\n }\n\n ifaceTypeNames[iface.name] = true;\n validateTypeImplementsAncestors(context, type, iface);\n validateTypeImplementsInterface(context, type, iface);\n }\n}\n\nfunction validateTypeImplementsInterface(context, type, iface) {\n const typeFieldMap = type.getFields(); // Assert each interface field is implemented.\n\n for (const ifaceField of objectValues(iface.getFields())) {\n const fieldName = ifaceField.name;\n const typeField = typeFieldMap[fieldName]; // Assert interface field exists on type.\n\n if (!typeField) {\n context.reportError(`Interface field ${iface.name}.${fieldName} expected but ${type.name} does not provide it.`, [ifaceField.astNode, ...getAllNodes(type)]);\n continue;\n } // Assert interface field type is satisfied by type field type, by being\n // a valid subtype. (covariant)\n\n\n if (!isTypeSubTypeOf(context.schema, typeField.type, ifaceField.type)) {\n context.reportError(`Interface field ${iface.name}.${fieldName} expects type ` + `${inspect(ifaceField.type)} but ${type.name}.${fieldName} ` + `is type ${inspect(typeField.type)}.`, [// istanbul ignore next (TODO need to write coverage tests)\n ifaceField.astNode?.type, // istanbul ignore next (TODO need to write coverage tests)\n typeField.astNode?.type]);\n } // Assert each interface field arg is implemented.\n\n\n for (const ifaceArg of ifaceField.args) {\n const argName = ifaceArg.name;\n const typeArg = typeField.args.find(arg => arg.name === argName); // Assert interface field arg exists on object field.\n\n if (!typeArg) {\n context.reportError(`Interface field argument ${iface.name}.${fieldName}(${argName}:) expected but ${type.name}.${fieldName} does not provide it.`, [ifaceArg.astNode, typeField.astNode]);\n continue;\n } // Assert interface field arg type matches object field arg type.\n // (invariant)\n // TODO: change to contravariant?\n\n\n if (!isEqualType(ifaceArg.type, typeArg.type)) {\n context.reportError(`Interface field argument ${iface.name}.${fieldName}(${argName}:) ` + `expects type ${inspect(ifaceArg.type)} but ` + `${type.name}.${fieldName}(${argName}:) is type ` + `${inspect(typeArg.type)}.`, [// istanbul ignore next (TODO need to write coverage tests)\n ifaceArg.astNode?.type, // istanbul ignore next (TODO need to write coverage tests)\n typeArg.astNode?.type]);\n } // TODO: validate default values?\n\n } // Assert additional arguments must not be required.\n\n\n for (const typeArg of typeField.args) {\n const argName = typeArg.name;\n const ifaceArg = ifaceField.args.find(arg => arg.name === argName);\n\n if (!ifaceArg && isRequiredArgument(typeArg)) {\n context.reportError(`Object field ${type.name}.${fieldName} includes required argument ${argName} that is missing from the Interface field ${iface.name}.${fieldName}.`, [typeArg.astNode, ifaceField.astNode]);\n }\n }\n }\n}\n\nfunction validateTypeImplementsAncestors(context, type, iface) {\n const ifaceInterfaces = type.getInterfaces();\n\n for (const transitive of iface.getInterfaces()) {\n if (ifaceInterfaces.indexOf(transitive) === -1) {\n context.reportError(transitive === type ? `Type ${type.name} cannot implement ${iface.name} because it would create a circular reference.` : `Type ${type.name} must implement ${transitive.name} because it is implemented by ${iface.name}.`, [...getAllImplementsInterfaceNodes(iface, transitive), ...getAllImplementsInterfaceNodes(type, iface)]);\n }\n }\n}\n\nfunction validateUnionMembers(context, union) {\n const memberTypes = union.getTypes();\n\n if (memberTypes.length === 0) {\n context.reportError(`Union type ${union.name} must define one or more member types.`, getAllNodes(union));\n }\n\n const includedTypeNames = Object.create(null);\n\n for (const memberType of memberTypes) {\n if (includedTypeNames[memberType.name]) {\n context.reportError(`Union type ${union.name} can only include type ${memberType.name} once.`, getUnionMemberTypeNodes(union, memberType.name));\n continue;\n }\n\n includedTypeNames[memberType.name] = true;\n\n if (!isObjectType(memberType)) {\n context.reportError(`Union type ${union.name} can only include Object types, ` + `it cannot include ${inspect(memberType)}.`, getUnionMemberTypeNodes(union, String(memberType)));\n }\n }\n}\n\nfunction validateEnumValues(context, enumType) {\n const enumValues = enumType.getValues();\n\n if (enumValues.length === 0) {\n context.reportError(`Enum type ${enumType.name} must define one or more values.`, getAllNodes(enumType));\n }\n\n for (const enumValue of enumValues) {\n const valueName = enumValue.name; // Ensure valid name.\n\n validateName(context, enumValue);\n\n if (valueName === 'true' || valueName === 'false' || valueName === 'null') {\n context.reportError(`Enum type ${enumType.name} cannot include value: ${valueName}.`, enumValue.astNode);\n }\n }\n}\n\nfunction validateInputFields(context, inputObj) {\n const fields = objectValues(inputObj.getFields());\n\n if (fields.length === 0) {\n context.reportError(`Input Object type ${inputObj.name} must define one or more fields.`, getAllNodes(inputObj));\n } // Ensure the arguments are valid\n\n\n for (const field of fields) {\n // Ensure they are named correctly.\n validateName(context, field); // Ensure the type is an input type\n\n if (!isInputType(field.type)) {\n context.reportError(`The type of ${inputObj.name}.${field.name} must be Input Type ` + `but got: ${inspect(field.type)}.`, field.astNode?.type);\n }\n\n if (isRequiredInputField(field) && field.deprecationReason != null) {\n context.reportError(`Required input field ${inputObj.name}.${field.name} cannot be deprecated.`, [getDeprecatedDirectiveNode(field.astNode), // istanbul ignore next (TODO need to write coverage tests)\n field.astNode?.type]);\n }\n }\n}\n\nfunction createInputObjectCircularRefsValidator(context) {\n // Modified copy of algorithm from 'src/validation/rules/NoFragmentCycles.js'.\n // Tracks already visited types to maintain O(N) and to ensure that cycles\n // are not redundantly reported.\n const visitedTypes = Object.create(null); // Array of types nodes used to produce meaningful errors\n\n const fieldPath = []; // Position in the type path\n\n const fieldPathIndexByTypeName = Object.create(null);\n return detectCycleRecursive; // This does a straight-forward DFS to find cycles.\n // It does not terminate when a cycle was found but continues to explore\n // the graph to find all possible cycles.\n\n function detectCycleRecursive(inputObj) {\n if (visitedTypes[inputObj.name]) {\n return;\n }\n\n visitedTypes[inputObj.name] = true;\n fieldPathIndexByTypeName[inputObj.name] = fieldPath.length;\n const fields = objectValues(inputObj.getFields());\n\n for (const field of fields) {\n if (isNonNullType(field.type) && isInputObjectType(field.type.ofType)) {\n const fieldType = field.type.ofType;\n const cycleIndex = fieldPathIndexByTypeName[fieldType.name];\n fieldPath.push(field);\n\n if (cycleIndex === undefined) {\n detectCycleRecursive(fieldType);\n } else {\n const cyclePath = fieldPath.slice(cycleIndex);\n const pathStr = cyclePath.map(fieldObj => fieldObj.name).join('.');\n context.reportError(`Cannot reference Input Object \"${fieldType.name}\" within itself through a series of non-null fields: \"${pathStr}\".`, cyclePath.map(fieldObj => fieldObj.astNode));\n }\n\n fieldPath.pop();\n }\n }\n\n fieldPathIndexByTypeName[inputObj.name] = undefined;\n }\n}\n\nfunction getAllNodes(object) {\n const {\n astNode,\n extensionASTNodes\n } = object;\n return astNode ? extensionASTNodes ? [astNode].concat(extensionASTNodes) : [astNode] : extensionASTNodes ?? [];\n}\n\nfunction getAllSubNodes(object, getter) {\n let subNodes = [];\n\n for (const node of getAllNodes(object)) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n subNodes = subNodes.concat(getter(node) ?? []);\n }\n\n return subNodes;\n}\n\nfunction getAllImplementsInterfaceNodes(type, iface) {\n return getAllSubNodes(type, typeNode => typeNode.interfaces).filter(ifaceNode => ifaceNode.name.value === iface.name);\n}\n\nfunction getUnionMemberTypeNodes(union, typeName) {\n return getAllSubNodes(union, unionNode => unionNode.types).filter(typeNode => typeNode.name.value === typeName);\n}\n\nfunction getDeprecatedDirectiveNode(definitionNode) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n return definitionNode?.directives?.find(node => node.name.value === GraphQLDeprecatedDirective.name);\n}\n","import inspect from \"../jsutils/inspect.mjs\";\nimport { GraphQLError } from \"./GraphQLError.mjs\";\n/**\n * Given an arbitrary value, presumably thrown while attempting to execute a\n * GraphQL operation, produce a new GraphQLError aware of the location in the\n * document responsible for the original Error.\n */\n\nexport function locatedError(rawOriginalError, nodes, path) {\n // Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface.\n const originalError = rawOriginalError instanceof Error ? rawOriginalError : new Error('Unexpected error value: ' + inspect(rawOriginalError)); // Note: this uses a brand-check to support GraphQL errors originating from other contexts.\n\n if (Array.isArray(originalError.path)) {\n return originalError;\n }\n\n return new GraphQLError(originalError.message, originalError.nodes ?? nodes, originalError.source, originalError.positions, path, originalError);\n}\n","import inspect from \"../jsutils/inspect.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { GraphQLList, GraphQLNonNull } from \"../type/definition.mjs\";\n/**\n * Given a Schema and an AST node describing a type, return a GraphQLType\n * definition which applies to that type. For example, if provided the parsed\n * AST node for `[User]`, a GraphQLList instance will be returned, containing\n * the type called \"User\" found in the schema. If a type called \"User\" is not\n * found in the schema, then undefined will be returned.\n */\n\n/* eslint-disable no-redeclare */\n\nexport function typeFromAST(schema, typeNode) {\n /* eslint-enable no-redeclare */\n let innerType;\n\n if (typeNode.kind === Kind.LIST_TYPE) {\n innerType = typeFromAST(schema, typeNode.type);\n return innerType && new GraphQLList(innerType);\n }\n\n if (typeNode.kind === Kind.NON_NULL_TYPE) {\n innerType = typeFromAST(schema, typeNode.type);\n return innerType && new GraphQLNonNull(innerType);\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (typeNode.kind === Kind.NAMED_TYPE) {\n return schema.getType(typeNode.name.value);\n } // istanbul ignore next (Not reachable. All possible type nodes have been considered)\n\n\n false || invariant(0, 'Unexpected type node: ' + inspect(typeNode));\n}\n","import { Kind } from \"../language/kinds.mjs\";\nimport { isNode } from \"../language/ast.mjs\";\nimport { getVisitFn } from \"../language/visitor.mjs\";\nimport { isObjectType, isInterfaceType, isEnumType, isInputObjectType, isListType, isCompositeType, isInputType, isOutputType, getNullableType, getNamedType } from \"../type/definition.mjs\";\nimport { SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef } from \"../type/introspection.mjs\";\nimport { typeFromAST } from \"./typeFromAST.mjs\";\n/**\n * TypeInfo is a utility class which, given a GraphQL schema, can keep track\n * of the current field and type definitions at any point in a GraphQL document\n * AST during a recursive descent by calling `enter(node)` and `leave(node)`.\n */\n\nexport class TypeInfo {\n constructor(schema, // NOTE: this experimental optional second parameter is only needed in order\n // to support non-spec-compliant code bases. You should never need to use it.\n // It may disappear in the future.\n getFieldDefFn, // Initial type may be provided in rare cases to facilitate traversals\n // beginning somewhere other than documents.\n initialType) {\n this._schema = schema;\n this._typeStack = [];\n this._parentTypeStack = [];\n this._inputTypeStack = [];\n this._fieldDefStack = [];\n this._defaultValueStack = [];\n this._directive = null;\n this._argument = null;\n this._enumValue = null;\n this._getFieldDef = getFieldDefFn ?? getFieldDef;\n\n if (initialType) {\n if (isInputType(initialType)) {\n this._inputTypeStack.push(initialType);\n }\n\n if (isCompositeType(initialType)) {\n this._parentTypeStack.push(initialType);\n }\n\n if (isOutputType(initialType)) {\n this._typeStack.push(initialType);\n }\n }\n }\n\n getType() {\n if (this._typeStack.length > 0) {\n return this._typeStack[this._typeStack.length - 1];\n }\n }\n\n getParentType() {\n if (this._parentTypeStack.length > 0) {\n return this._parentTypeStack[this._parentTypeStack.length - 1];\n }\n }\n\n getInputType() {\n if (this._inputTypeStack.length > 0) {\n return this._inputTypeStack[this._inputTypeStack.length - 1];\n }\n }\n\n getParentInputType() {\n if (this._inputTypeStack.length > 1) {\n return this._inputTypeStack[this._inputTypeStack.length - 2];\n }\n }\n\n getFieldDef() {\n if (this._fieldDefStack.length > 0) {\n return this._fieldDefStack[this._fieldDefStack.length - 1];\n }\n }\n\n getDefaultValue() {\n if (this._defaultValueStack.length > 0) {\n return this._defaultValueStack[this._defaultValueStack.length - 1];\n }\n }\n\n getDirective() {\n return this._directive;\n }\n\n getArgument() {\n return this._argument;\n }\n\n getEnumValue() {\n return this._enumValue;\n }\n\n enter(node) {\n const schema = this._schema; // Note: many of the types below are explicitly typed as \"mixed\" to drop\n // any assumptions of a valid schema to ensure runtime types are properly\n // checked before continuing since TypeInfo is used as part of validation\n // which occurs before guarantees of schema and document validity.\n\n switch (node.kind) {\n case Kind.SELECTION_SET:\n {\n const namedType = getNamedType(this.getType());\n\n this._parentTypeStack.push(isCompositeType(namedType) ? namedType : undefined);\n\n break;\n }\n\n case Kind.FIELD:\n {\n const parentType = this.getParentType();\n let fieldDef;\n let fieldType;\n\n if (parentType) {\n fieldDef = this._getFieldDef(schema, parentType, node);\n\n if (fieldDef) {\n fieldType = fieldDef.type;\n }\n }\n\n this._fieldDefStack.push(fieldDef);\n\n this._typeStack.push(isOutputType(fieldType) ? fieldType : undefined);\n\n break;\n }\n\n case Kind.DIRECTIVE:\n this._directive = schema.getDirective(node.name.value);\n break;\n\n case Kind.OPERATION_DEFINITION:\n {\n let type;\n\n switch (node.operation) {\n case 'query':\n type = schema.getQueryType();\n break;\n\n case 'mutation':\n type = schema.getMutationType();\n break;\n\n case 'subscription':\n type = schema.getSubscriptionType();\n break;\n }\n\n this._typeStack.push(isObjectType(type) ? type : undefined);\n\n break;\n }\n\n case Kind.INLINE_FRAGMENT:\n case Kind.FRAGMENT_DEFINITION:\n {\n const typeConditionAST = node.typeCondition;\n const outputType = typeConditionAST ? typeFromAST(schema, typeConditionAST) : getNamedType(this.getType());\n\n this._typeStack.push(isOutputType(outputType) ? outputType : undefined);\n\n break;\n }\n\n case Kind.VARIABLE_DEFINITION:\n {\n const inputType = typeFromAST(schema, node.type);\n\n this._inputTypeStack.push(isInputType(inputType) ? inputType : undefined);\n\n break;\n }\n\n case Kind.ARGUMENT:\n {\n let argDef;\n let argType;\n const fieldOrDirective = this.getDirective() ?? this.getFieldDef();\n\n if (fieldOrDirective) {\n argDef = fieldOrDirective.args.find(arg => arg.name === node.name.value);\n\n if (argDef) {\n argType = argDef.type;\n }\n }\n\n this._argument = argDef;\n\n this._defaultValueStack.push(argDef ? argDef.defaultValue : undefined);\n\n this._inputTypeStack.push(isInputType(argType) ? argType : undefined);\n\n break;\n }\n\n case Kind.LIST:\n {\n const listType = getNullableType(this.getInputType());\n const itemType = isListType(listType) ? listType.ofType : listType; // List positions never have a default value.\n\n this._defaultValueStack.push(undefined);\n\n this._inputTypeStack.push(isInputType(itemType) ? itemType : undefined);\n\n break;\n }\n\n case Kind.OBJECT_FIELD:\n {\n const objectType = getNamedType(this.getInputType());\n let inputFieldType;\n let inputField;\n\n if (isInputObjectType(objectType)) {\n inputField = objectType.getFields()[node.name.value];\n\n if (inputField) {\n inputFieldType = inputField.type;\n }\n }\n\n this._defaultValueStack.push(inputField ? inputField.defaultValue : undefined);\n\n this._inputTypeStack.push(isInputType(inputFieldType) ? inputFieldType : undefined);\n\n break;\n }\n\n case Kind.ENUM:\n {\n const enumType = getNamedType(this.getInputType());\n let enumValue;\n\n if (isEnumType(enumType)) {\n enumValue = enumType.getValue(node.value);\n }\n\n this._enumValue = enumValue;\n break;\n }\n }\n }\n\n leave(node) {\n switch (node.kind) {\n case Kind.SELECTION_SET:\n this._parentTypeStack.pop();\n\n break;\n\n case Kind.FIELD:\n this._fieldDefStack.pop();\n\n this._typeStack.pop();\n\n break;\n\n case Kind.DIRECTIVE:\n this._directive = null;\n break;\n\n case Kind.OPERATION_DEFINITION:\n case Kind.INLINE_FRAGMENT:\n case Kind.FRAGMENT_DEFINITION:\n this._typeStack.pop();\n\n break;\n\n case Kind.VARIABLE_DEFINITION:\n this._inputTypeStack.pop();\n\n break;\n\n case Kind.ARGUMENT:\n this._argument = null;\n\n this._defaultValueStack.pop();\n\n this._inputTypeStack.pop();\n\n break;\n\n case Kind.LIST:\n case Kind.OBJECT_FIELD:\n this._defaultValueStack.pop();\n\n this._inputTypeStack.pop();\n\n break;\n\n case Kind.ENUM:\n this._enumValue = null;\n break;\n }\n }\n\n}\n/**\n * Not exactly the same as the executor's definition of getFieldDef, in this\n * statically evaluated environment we do not always have an Object type,\n * and need to handle Interface and Union types.\n */\n\nfunction getFieldDef(schema, parentType, fieldNode) {\n const name = fieldNode.name.value;\n\n if (name === SchemaMetaFieldDef.name && schema.getQueryType() === parentType) {\n return SchemaMetaFieldDef;\n }\n\n if (name === TypeMetaFieldDef.name && schema.getQueryType() === parentType) {\n return TypeMetaFieldDef;\n }\n\n if (name === TypeNameMetaFieldDef.name && isCompositeType(parentType)) {\n return TypeNameMetaFieldDef;\n }\n\n if (isObjectType(parentType) || isInterfaceType(parentType)) {\n return parentType.getFields()[name];\n }\n}\n/**\n * Creates a new visitor instance which maintains a provided TypeInfo instance\n * along with visiting visitor.\n */\n\n\nexport function visitWithTypeInfo(typeInfo, visitor) {\n return {\n enter(node) {\n typeInfo.enter(node);\n const fn = getVisitFn(visitor, node.kind,\n /* isLeaving */\n false);\n\n if (fn) {\n const result = fn.apply(visitor, arguments);\n\n if (result !== undefined) {\n typeInfo.leave(node);\n\n if (isNode(result)) {\n typeInfo.enter(result);\n }\n }\n\n return result;\n }\n },\n\n leave(node) {\n const fn = getVisitFn(visitor, node.kind,\n /* isLeaving */\n true);\n let result;\n\n if (fn) {\n result = fn.apply(visitor, arguments);\n }\n\n typeInfo.leave(node);\n return result;\n }\n\n };\n}\n","import { Kind } from \"./kinds.mjs\";\nexport function isDefinitionNode(node) {\n return isExecutableDefinitionNode(node) || isTypeSystemDefinitionNode(node) || isTypeSystemExtensionNode(node);\n}\nexport function isExecutableDefinitionNode(node) {\n return node.kind === Kind.OPERATION_DEFINITION || node.kind === Kind.FRAGMENT_DEFINITION;\n}\nexport function isSelectionNode(node) {\n return node.kind === Kind.FIELD || node.kind === Kind.FRAGMENT_SPREAD || node.kind === Kind.INLINE_FRAGMENT;\n}\nexport function isValueNode(node) {\n return node.kind === Kind.VARIABLE || node.kind === Kind.INT || node.kind === Kind.FLOAT || node.kind === Kind.STRING || node.kind === Kind.BOOLEAN || node.kind === Kind.NULL || node.kind === Kind.ENUM || node.kind === Kind.LIST || node.kind === Kind.OBJECT;\n}\nexport function isTypeNode(node) {\n return node.kind === Kind.NAMED_TYPE || node.kind === Kind.LIST_TYPE || node.kind === Kind.NON_NULL_TYPE;\n}\nexport function isTypeSystemDefinitionNode(node) {\n return node.kind === Kind.SCHEMA_DEFINITION || isTypeDefinitionNode(node) || node.kind === Kind.DIRECTIVE_DEFINITION;\n}\nexport function isTypeDefinitionNode(node) {\n return node.kind === Kind.SCALAR_TYPE_DEFINITION || node.kind === Kind.OBJECT_TYPE_DEFINITION || node.kind === Kind.INTERFACE_TYPE_DEFINITION || node.kind === Kind.UNION_TYPE_DEFINITION || node.kind === Kind.ENUM_TYPE_DEFINITION || node.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION;\n}\nexport function isTypeSystemExtensionNode(node) {\n return node.kind === Kind.SCHEMA_EXTENSION || isTypeExtensionNode(node);\n}\nexport function isTypeExtensionNode(node) {\n return node.kind === Kind.SCALAR_TYPE_EXTENSION || node.kind === Kind.OBJECT_TYPE_EXTENSION || node.kind === Kind.INTERFACE_TYPE_EXTENSION || node.kind === Kind.UNION_TYPE_EXTENSION || node.kind === Kind.ENUM_TYPE_EXTENSION || node.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION;\n}\n","import didYouMean from \"../../jsutils/didYouMean.mjs\";\nimport suggestionList from \"../../jsutils/suggestionList.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { isTypeDefinitionNode, isTypeSystemDefinitionNode, isTypeSystemExtensionNode } from \"../../language/predicates.mjs\";\nimport { specifiedScalarTypes } from \"../../type/scalars.mjs\";\nimport { introspectionTypes } from \"../../type/introspection.mjs\";\n\n/**\n * Known type names\n *\n * A GraphQL document is only valid if referenced types (specifically\n * variable definitions and fragment conditions) are defined by the type schema.\n */\nexport function KnownTypeNamesRule(context) {\n const schema = context.getSchema();\n const existingTypesMap = schema ? schema.getTypeMap() : Object.create(null);\n const definedTypes = Object.create(null);\n\n for (const def of context.getDocument().definitions) {\n if (isTypeDefinitionNode(def)) {\n definedTypes[def.name.value] = true;\n }\n }\n\n const typeNames = Object.keys(existingTypesMap).concat(Object.keys(definedTypes));\n return {\n NamedType(node, _1, parent, _2, ancestors) {\n const typeName = node.name.value;\n\n if (!existingTypesMap[typeName] && !definedTypes[typeName]) {\n const definitionNode = ancestors[2] ?? parent;\n const isSDL = definitionNode != null && isSDLNode(definitionNode);\n\n if (isSDL && isStandardTypeName(typeName)) {\n return;\n }\n\n const suggestedTypes = suggestionList(typeName, isSDL ? standardTypeNames.concat(typeNames) : typeNames);\n context.reportError(new GraphQLError(`Unknown type \"${typeName}\".` + didYouMean(suggestedTypes), node));\n }\n }\n\n };\n}\nconst standardTypeNames = [...specifiedScalarTypes, ...introspectionTypes].map(type => type.name);\n\nfunction isStandardTypeName(typeName) {\n return standardTypeNames.indexOf(typeName) !== -1;\n}\n\nfunction isSDLNode(value) {\n return !Array.isArray(value) && (isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value));\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * No unused fragments\n *\n * A GraphQL document is only valid if all fragment definitions are spread\n * within operations, or spread within other fragments spread within operations.\n */\nexport function NoUnusedFragmentsRule(context) {\n const operationDefs = [];\n const fragmentDefs = [];\n return {\n OperationDefinition(node) {\n operationDefs.push(node);\n return false;\n },\n\n FragmentDefinition(node) {\n fragmentDefs.push(node);\n return false;\n },\n\n Document: {\n leave() {\n const fragmentNameUsed = Object.create(null);\n\n for (const operation of operationDefs) {\n for (const fragment of context.getRecursivelyReferencedFragments(operation)) {\n fragmentNameUsed[fragment.name.value] = true;\n }\n }\n\n for (const fragmentDef of fragmentDefs) {\n const fragName = fragmentDef.name.value;\n\n if (fragmentNameUsed[fragName] !== true) {\n context.reportError(new GraphQLError(`Fragment \"${fragName}\" is never used.`, fragmentDef));\n }\n }\n }\n\n }\n };\n}\n","import inspect from \"../../jsutils/inspect.mjs\";\nimport invariant from \"../../jsutils/invariant.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { DirectiveLocation } from \"../../language/directiveLocation.mjs\";\nimport { specifiedDirectives } from \"../../type/directives.mjs\";\n\n/**\n * Known directives\n *\n * A GraphQL document is only valid if all `@directives` are known by the\n * schema and legally positioned.\n */\nexport function KnownDirectivesRule(context) {\n const locationsMap = Object.create(null);\n const schema = context.getSchema();\n const definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;\n\n for (const directive of definedDirectives) {\n locationsMap[directive.name] = directive.locations;\n }\n\n const astDefinitions = context.getDocument().definitions;\n\n for (const def of astDefinitions) {\n if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n locationsMap[def.name.value] = def.locations.map(name => name.value);\n }\n }\n\n return {\n Directive(node, _key, _parent, _path, ancestors) {\n const name = node.name.value;\n const locations = locationsMap[name];\n\n if (!locations) {\n context.reportError(new GraphQLError(`Unknown directive \"@${name}\".`, node));\n return;\n }\n\n const candidateLocation = getDirectiveLocationForASTPath(ancestors);\n\n if (candidateLocation && locations.indexOf(candidateLocation) === -1) {\n context.reportError(new GraphQLError(`Directive \"@${name}\" may not be used on ${candidateLocation}.`, node));\n }\n }\n\n };\n}\n\nfunction getDirectiveLocationForASTPath(ancestors) {\n const appliedTo = ancestors[ancestors.length - 1];\n !Array.isArray(appliedTo) || invariant(0);\n\n switch (appliedTo.kind) {\n case Kind.OPERATION_DEFINITION:\n return getDirectiveLocationForOperation(appliedTo.operation);\n\n case Kind.FIELD:\n return DirectiveLocation.FIELD;\n\n case Kind.FRAGMENT_SPREAD:\n return DirectiveLocation.FRAGMENT_SPREAD;\n\n case Kind.INLINE_FRAGMENT:\n return DirectiveLocation.INLINE_FRAGMENT;\n\n case Kind.FRAGMENT_DEFINITION:\n return DirectiveLocation.FRAGMENT_DEFINITION;\n\n case Kind.VARIABLE_DEFINITION:\n return DirectiveLocation.VARIABLE_DEFINITION;\n\n case Kind.SCHEMA_DEFINITION:\n case Kind.SCHEMA_EXTENSION:\n return DirectiveLocation.SCHEMA;\n\n case Kind.SCALAR_TYPE_DEFINITION:\n case Kind.SCALAR_TYPE_EXTENSION:\n return DirectiveLocation.SCALAR;\n\n case Kind.OBJECT_TYPE_DEFINITION:\n case Kind.OBJECT_TYPE_EXTENSION:\n return DirectiveLocation.OBJECT;\n\n case Kind.FIELD_DEFINITION:\n return DirectiveLocation.FIELD_DEFINITION;\n\n case Kind.INTERFACE_TYPE_DEFINITION:\n case Kind.INTERFACE_TYPE_EXTENSION:\n return DirectiveLocation.INTERFACE;\n\n case Kind.UNION_TYPE_DEFINITION:\n case Kind.UNION_TYPE_EXTENSION:\n return DirectiveLocation.UNION;\n\n case Kind.ENUM_TYPE_DEFINITION:\n case Kind.ENUM_TYPE_EXTENSION:\n return DirectiveLocation.ENUM;\n\n case Kind.ENUM_VALUE_DEFINITION:\n return DirectiveLocation.ENUM_VALUE;\n\n case Kind.INPUT_OBJECT_TYPE_DEFINITION:\n case Kind.INPUT_OBJECT_TYPE_EXTENSION:\n return DirectiveLocation.INPUT_OBJECT;\n\n case Kind.INPUT_VALUE_DEFINITION:\n {\n const parentNode = ancestors[ancestors.length - 3];\n return parentNode.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION ? DirectiveLocation.INPUT_FIELD_DEFINITION : DirectiveLocation.ARGUMENT_DEFINITION;\n }\n }\n}\n\nfunction getDirectiveLocationForOperation(operation) {\n switch (operation) {\n case 'query':\n return DirectiveLocation.QUERY;\n\n case 'mutation':\n return DirectiveLocation.MUTATION;\n\n case 'subscription':\n return DirectiveLocation.SUBSCRIPTION;\n } // istanbul ignore next (Not reachable. All possible types have been considered)\n\n\n false || invariant(0, 'Unexpected operation: ' + inspect(operation));\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { isTypeDefinitionNode, isTypeExtensionNode } from \"../../language/predicates.mjs\";\nimport { specifiedDirectives } from \"../../type/directives.mjs\";\n\n/**\n * Unique directive names per location\n *\n * A GraphQL document is only valid if all non-repeatable directives at\n * a given location are uniquely named.\n */\nexport function UniqueDirectivesPerLocationRule(context) {\n const uniqueDirectiveMap = Object.create(null);\n const schema = context.getSchema();\n const definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;\n\n for (const directive of definedDirectives) {\n uniqueDirectiveMap[directive.name] = !directive.isRepeatable;\n }\n\n const astDefinitions = context.getDocument().definitions;\n\n for (const def of astDefinitions) {\n if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n uniqueDirectiveMap[def.name.value] = !def.repeatable;\n }\n }\n\n const schemaDirectives = Object.create(null);\n const typeDirectivesMap = Object.create(null);\n return {\n // Many different AST nodes may contain directives. Rather than listing\n // them all, just listen for entering any node, and check to see if it\n // defines any directives.\n enter(node) {\n if (node.directives == null) {\n return;\n }\n\n let seenDirectives;\n\n if (node.kind === Kind.SCHEMA_DEFINITION || node.kind === Kind.SCHEMA_EXTENSION) {\n seenDirectives = schemaDirectives;\n } else if (isTypeDefinitionNode(node) || isTypeExtensionNode(node)) {\n const typeName = node.name.value;\n seenDirectives = typeDirectivesMap[typeName];\n\n if (seenDirectives === undefined) {\n typeDirectivesMap[typeName] = seenDirectives = Object.create(null);\n }\n } else {\n seenDirectives = Object.create(null);\n }\n\n for (const directive of node.directives) {\n const directiveName = directive.name.value;\n\n if (uniqueDirectiveMap[directiveName]) {\n if (seenDirectives[directiveName]) {\n context.reportError(new GraphQLError(`The directive \"@${directiveName}\" can only be used once at this location.`, [seenDirectives[directiveName], directive]));\n } else {\n seenDirectives[directiveName] = directive;\n }\n }\n }\n }\n\n };\n}\n","import didYouMean from \"../../jsutils/didYouMean.mjs\";\nimport suggestionList from \"../../jsutils/suggestionList.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { specifiedDirectives } from \"../../type/directives.mjs\";\n\n/**\n * Known argument names\n *\n * A GraphQL field is only valid if all supplied arguments are defined by\n * that field.\n */\nexport function KnownArgumentNamesRule(context) {\n return { // eslint-disable-next-line new-cap\n ...KnownArgumentNamesOnDirectivesRule(context),\n\n Argument(argNode) {\n const argDef = context.getArgument();\n const fieldDef = context.getFieldDef();\n const parentType = context.getParentType();\n\n if (!argDef && fieldDef && parentType) {\n const argName = argNode.name.value;\n const knownArgsNames = fieldDef.args.map(arg => arg.name);\n const suggestions = suggestionList(argName, knownArgsNames);\n context.reportError(new GraphQLError(`Unknown argument \"${argName}\" on field \"${parentType.name}.${fieldDef.name}\".` + didYouMean(suggestions), argNode));\n }\n }\n\n };\n}\n/**\n * @internal\n */\n\nexport function KnownArgumentNamesOnDirectivesRule(context) {\n const directiveArgs = Object.create(null);\n const schema = context.getSchema();\n const definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;\n\n for (const directive of definedDirectives) {\n directiveArgs[directive.name] = directive.args.map(arg => arg.name);\n }\n\n const astDefinitions = context.getDocument().definitions;\n\n for (const def of astDefinitions) {\n if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const argsNodes = def.arguments ?? [];\n directiveArgs[def.name.value] = argsNodes.map(arg => arg.name.value);\n }\n }\n\n return {\n Directive(directiveNode) {\n const directiveName = directiveNode.name.value;\n const knownArgs = directiveArgs[directiveName];\n\n if (directiveNode.arguments && knownArgs) {\n for (const argNode of directiveNode.arguments) {\n const argName = argNode.name.value;\n\n if (knownArgs.indexOf(argName) === -1) {\n const suggestions = suggestionList(argName, knownArgs);\n context.reportError(new GraphQLError(`Unknown argument \"${argName}\" on directive \"@${directiveName}\".` + didYouMean(suggestions), argNode));\n }\n }\n }\n\n return false;\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique argument names\n *\n * A GraphQL field or directive is only valid if all supplied arguments are\n * uniquely named.\n */\nexport function UniqueArgumentNamesRule(context) {\n let knownArgNames = Object.create(null);\n return {\n Field() {\n knownArgNames = Object.create(null);\n },\n\n Directive() {\n knownArgNames = Object.create(null);\n },\n\n Argument(node) {\n const argName = node.name.value;\n\n if (knownArgNames[argName]) {\n context.reportError(new GraphQLError(`There can be only one argument named \"${argName}\".`, [knownArgNames[argName], node.name]));\n } else {\n knownArgNames[argName] = node.name;\n }\n\n return false;\n }\n\n };\n}\n","import objectValues from \"../../polyfills/objectValues.mjs\";\nimport keyMap from \"../../jsutils/keyMap.mjs\";\nimport inspect from \"../../jsutils/inspect.mjs\";\nimport didYouMean from \"../../jsutils/didYouMean.mjs\";\nimport suggestionList from \"../../jsutils/suggestionList.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { print } from \"../../language/printer.mjs\";\nimport { isLeafType, isInputObjectType, isListType, isNonNullType, isRequiredInputField, getNullableType, getNamedType } from \"../../type/definition.mjs\";\n\n/**\n * Value literals of correct type\n *\n * A GraphQL document is only valid if all value literals are of the type\n * expected at their position.\n */\nexport function ValuesOfCorrectTypeRule(context) {\n return {\n ListValue(node) {\n // Note: TypeInfo will traverse into a list's item type, so look to the\n // parent input type to check if it is a list.\n const type = getNullableType(context.getParentInputType());\n\n if (!isListType(type)) {\n isValidValueNode(context, node);\n return false; // Don't traverse further.\n }\n },\n\n ObjectValue(node) {\n const type = getNamedType(context.getInputType());\n\n if (!isInputObjectType(type)) {\n isValidValueNode(context, node);\n return false; // Don't traverse further.\n } // Ensure every required field exists.\n\n\n const fieldNodeMap = keyMap(node.fields, field => field.name.value);\n\n for (const fieldDef of objectValues(type.getFields())) {\n const fieldNode = fieldNodeMap[fieldDef.name];\n\n if (!fieldNode && isRequiredInputField(fieldDef)) {\n const typeStr = inspect(fieldDef.type);\n context.reportError(new GraphQLError(`Field \"${type.name}.${fieldDef.name}\" of required type \"${typeStr}\" was not provided.`, node));\n }\n }\n },\n\n ObjectField(node) {\n const parentType = getNamedType(context.getParentInputType());\n const fieldType = context.getInputType();\n\n if (!fieldType && isInputObjectType(parentType)) {\n const suggestions = suggestionList(node.name.value, Object.keys(parentType.getFields()));\n context.reportError(new GraphQLError(`Field \"${node.name.value}\" is not defined by type \"${parentType.name}\".` + didYouMean(suggestions), node));\n }\n },\n\n NullValue(node) {\n const type = context.getInputType();\n\n if (isNonNullType(type)) {\n context.reportError(new GraphQLError(`Expected value of type \"${inspect(type)}\", found ${print(node)}.`, node));\n }\n },\n\n EnumValue: node => isValidValueNode(context, node),\n IntValue: node => isValidValueNode(context, node),\n FloatValue: node => isValidValueNode(context, node),\n StringValue: node => isValidValueNode(context, node),\n BooleanValue: node => isValidValueNode(context, node)\n };\n}\n/**\n * Any value literal may be a valid representation of a Scalar, depending on\n * that scalar type.\n */\n\nfunction isValidValueNode(context, node) {\n // Report any error at the full type expected by the location.\n const locationType = context.getInputType();\n\n if (!locationType) {\n return;\n }\n\n const type = getNamedType(locationType);\n\n if (!isLeafType(type)) {\n const typeStr = inspect(locationType);\n context.reportError(new GraphQLError(`Expected value of type \"${typeStr}\", found ${print(node)}.`, node));\n return;\n } // Scalars and Enums determine if a literal value is valid via parseLiteral(),\n // which may throw or return an invalid value to indicate failure.\n\n\n try {\n const parseResult = type.parseLiteral(node, undefined\n /* variables */\n );\n\n if (parseResult === undefined) {\n const typeStr = inspect(locationType);\n context.reportError(new GraphQLError(`Expected value of type \"${typeStr}\", found ${print(node)}.`, node));\n }\n } catch (error) {\n const typeStr = inspect(locationType);\n\n if (error instanceof GraphQLError) {\n context.reportError(error);\n } else {\n context.reportError(new GraphQLError(`Expected value of type \"${typeStr}\", found ${print(node)}; ` + error.message, node, undefined, undefined, undefined, error));\n }\n }\n}\n","import inspect from \"../../jsutils/inspect.mjs\";\nimport keyMap from \"../../jsutils/keyMap.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { print } from \"../../language/printer.mjs\";\nimport { specifiedDirectives } from \"../../type/directives.mjs\";\nimport { isType, isRequiredArgument } from \"../../type/definition.mjs\";\n\n/**\n * Provided required arguments\n *\n * A field or directive is only valid if all required (non-null without a\n * default value) field arguments have been provided.\n */\nexport function ProvidedRequiredArgumentsRule(context) {\n return { // eslint-disable-next-line new-cap\n ...ProvidedRequiredArgumentsOnDirectivesRule(context),\n Field: {\n // Validate on leave to allow for deeper errors to appear first.\n leave(fieldNode) {\n const fieldDef = context.getFieldDef();\n\n if (!fieldDef) {\n return false;\n } // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n\n\n const argNodes = fieldNode.arguments ?? [];\n const argNodeMap = keyMap(argNodes, arg => arg.name.value);\n\n for (const argDef of fieldDef.args) {\n const argNode = argNodeMap[argDef.name];\n\n if (!argNode && isRequiredArgument(argDef)) {\n const argTypeStr = inspect(argDef.type);\n context.reportError(new GraphQLError(`Field \"${fieldDef.name}\" argument \"${argDef.name}\" of type \"${argTypeStr}\" is required, but it was not provided.`, fieldNode));\n }\n }\n }\n\n }\n };\n}\n/**\n * @internal\n */\n\nexport function ProvidedRequiredArgumentsOnDirectivesRule(context) {\n const requiredArgsMap = Object.create(null);\n const schema = context.getSchema();\n const definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;\n\n for (const directive of definedDirectives) {\n requiredArgsMap[directive.name] = keyMap(directive.args.filter(isRequiredArgument), arg => arg.name);\n }\n\n const astDefinitions = context.getDocument().definitions;\n\n for (const def of astDefinitions) {\n if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const argNodes = def.arguments ?? [];\n requiredArgsMap[def.name.value] = keyMap(argNodes.filter(isRequiredArgumentNode), arg => arg.name.value);\n }\n }\n\n return {\n Directive: {\n // Validate on leave to allow for deeper errors to appear first.\n leave(directiveNode) {\n const directiveName = directiveNode.name.value;\n const requiredArgs = requiredArgsMap[directiveName];\n\n if (requiredArgs) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const argNodes = directiveNode.arguments ?? [];\n const argNodeMap = keyMap(argNodes, arg => arg.name.value);\n\n for (const argName of Object.keys(requiredArgs)) {\n if (!argNodeMap[argName]) {\n const argType = requiredArgs[argName].type;\n const argTypeStr = isType(argType) ? inspect(argType) : print(argType);\n context.reportError(new GraphQLError(`Directive \"@${directiveName}\" argument \"${argName}\" of type \"${argTypeStr}\" is required, but it was not provided.`, directiveNode));\n }\n }\n }\n }\n\n }\n };\n}\n\nfunction isRequiredArgumentNode(arg) {\n return arg.type.kind === Kind.NON_NULL_TYPE && arg.defaultValue == null;\n}\n","import inspect from \"../../jsutils/inspect.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { isNonNullType } from \"../../type/definition.mjs\";\nimport { typeFromAST } from \"../../utilities/typeFromAST.mjs\";\nimport { isTypeSubTypeOf } from \"../../utilities/typeComparators.mjs\";\n\n/**\n * Variables passed to field arguments conform to type\n */\nexport function VariablesInAllowedPositionRule(context) {\n let varDefMap = Object.create(null);\n return {\n OperationDefinition: {\n enter() {\n varDefMap = Object.create(null);\n },\n\n leave(operation) {\n const usages = context.getRecursiveVariableUsages(operation);\n\n for (const {\n node,\n type,\n defaultValue\n } of usages) {\n const varName = node.name.value;\n const varDef = varDefMap[varName];\n\n if (varDef && type) {\n // A var type is allowed if it is the same or more strict (e.g. is\n // a subtype of) than the expected type. It can be more strict if\n // the variable type is non-null when the expected type is nullable.\n // If both are list types, the variable item type can be more strict\n // than the expected item type (contravariant).\n const schema = context.getSchema();\n const varType = typeFromAST(schema, varDef.type);\n\n if (varType && !allowedVariableUsage(schema, varType, varDef.defaultValue, type, defaultValue)) {\n const varTypeStr = inspect(varType);\n const typeStr = inspect(type);\n context.reportError(new GraphQLError(`Variable \"$${varName}\" of type \"${varTypeStr}\" used in position expecting type \"${typeStr}\".`, [varDef, node]));\n }\n }\n }\n }\n\n },\n\n VariableDefinition(node) {\n varDefMap[node.variable.name.value] = node;\n }\n\n };\n}\n/**\n * Returns true if the variable is allowed in the location it was found,\n * which includes considering if default values exist for either the variable\n * or the location at which it is located.\n */\n\nfunction allowedVariableUsage(schema, varType, varDefaultValue, locationType, locationDefaultValue) {\n if (isNonNullType(locationType) && !isNonNullType(varType)) {\n const hasNonNullVariableDefaultValue = varDefaultValue != null && varDefaultValue.kind !== Kind.NULL;\n const hasLocationDefaultValue = locationDefaultValue !== undefined;\n\n if (!hasNonNullVariableDefaultValue && !hasLocationDefaultValue) {\n return false;\n }\n\n const nullableLocationType = locationType.ofType;\n return isTypeSubTypeOf(schema, varType, nullableLocationType);\n }\n\n return isTypeSubTypeOf(schema, varType, locationType);\n}\n","import objectEntries from \"../../polyfills/objectEntries.mjs\";\nimport inspect from \"../../jsutils/inspect.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { print } from \"../../language/printer.mjs\";\nimport { getNamedType, isNonNullType, isLeafType, isObjectType, isListType, isInterfaceType } from \"../../type/definition.mjs\";\nimport { typeFromAST } from \"../../utilities/typeFromAST.mjs\";\n\nfunction reasonMessage(reason) {\n if (Array.isArray(reason)) {\n return reason.map(([responseName, subReason]) => `subfields \"${responseName}\" conflict because ` + reasonMessage(subReason)).join(' and ');\n }\n\n return reason;\n}\n/**\n * Overlapping fields can be merged\n *\n * A selection set is only valid if all fields (including spreading any\n * fragments) either correspond to distinct response names or can be merged\n * without ambiguity.\n */\n\n\nexport function OverlappingFieldsCanBeMergedRule(context) {\n // A memoization for when two fragments are compared \"between\" each other for\n // conflicts. Two fragments may be compared many times, so memoizing this can\n // dramatically improve the performance of this validator.\n const comparedFragmentPairs = new PairSet(); // A cache for the \"field map\" and list of fragment names found in any given\n // selection set. Selection sets may be asked for this information multiple\n // times, so this improves the performance of this validator.\n\n const cachedFieldsAndFragmentNames = new Map();\n return {\n SelectionSet(selectionSet) {\n const conflicts = findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, context.getParentType(), selectionSet);\n\n for (const [[responseName, reason], fields1, fields2] of conflicts) {\n const reasonMsg = reasonMessage(reason);\n context.reportError(new GraphQLError(`Fields \"${responseName}\" conflict because ${reasonMsg}. Use different aliases on the fields to fetch both if this was intentional.`, fields1.concat(fields2)));\n }\n }\n\n };\n}\n\n/**\n * Algorithm:\n *\n * Conflicts occur when two fields exist in a query which will produce the same\n * response name, but represent differing values, thus creating a conflict.\n * The algorithm below finds all conflicts via making a series of comparisons\n * between fields. In order to compare as few fields as possible, this makes\n * a series of comparisons \"within\" sets of fields and \"between\" sets of fields.\n *\n * Given any selection set, a collection produces both a set of fields by\n * also including all inline fragments, as well as a list of fragments\n * referenced by fragment spreads.\n *\n * A) Each selection set represented in the document first compares \"within\" its\n * collected set of fields, finding any conflicts between every pair of\n * overlapping fields.\n * Note: This is the *only time* that a the fields \"within\" a set are compared\n * to each other. After this only fields \"between\" sets are compared.\n *\n * B) Also, if any fragment is referenced in a selection set, then a\n * comparison is made \"between\" the original set of fields and the\n * referenced fragment.\n *\n * C) Also, if multiple fragments are referenced, then comparisons\n * are made \"between\" each referenced fragment.\n *\n * D) When comparing \"between\" a set of fields and a referenced fragment, first\n * a comparison is made between each field in the original set of fields and\n * each field in the the referenced set of fields.\n *\n * E) Also, if any fragment is referenced in the referenced selection set,\n * then a comparison is made \"between\" the original set of fields and the\n * referenced fragment (recursively referring to step D).\n *\n * F) When comparing \"between\" two fragments, first a comparison is made between\n * each field in the first referenced set of fields and each field in the the\n * second referenced set of fields.\n *\n * G) Also, any fragments referenced by the first must be compared to the\n * second, and any fragments referenced by the second must be compared to the\n * first (recursively referring to step F).\n *\n * H) When comparing two fields, if both have selection sets, then a comparison\n * is made \"between\" both selection sets, first comparing the set of fields in\n * the first selection set with the set of fields in the second.\n *\n * I) Also, if any fragment is referenced in either selection set, then a\n * comparison is made \"between\" the other set of fields and the\n * referenced fragment.\n *\n * J) Also, if two fragments are referenced in both selection sets, then a\n * comparison is made \"between\" the two fragments.\n *\n */\n// Find all conflicts found \"within\" a selection set, including those found\n// via spreading in fragments. Called when visiting each SelectionSet in the\n// GraphQL Document.\nfunction findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentType, selectionSet) {\n const conflicts = [];\n const [fieldMap, fragmentNames] = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet); // (A) Find find all conflicts \"within\" the fields of this selection set.\n // Note: this is the *only place* `collectConflictsWithin` is called.\n\n collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap);\n\n if (fragmentNames.length !== 0) {\n // (B) Then collect conflicts between these fields and those represented by\n // each spread fragment name found.\n for (let i = 0; i < fragmentNames.length; i++) {\n collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fieldMap, fragmentNames[i]); // (C) Then compare this fragment with all other fragments found in this\n // selection set to collect conflicts between fragments spread together.\n // This compares each item in the list of fragment names to every other\n // item in that same list (except for itself).\n\n for (let j = i + 1; j < fragmentNames.length; j++) {\n collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fragmentNames[i], fragmentNames[j]);\n }\n }\n }\n\n return conflicts;\n} // Collect all conflicts found between a set of fields and a fragment reference\n// including via spreading in any nested fragments.\n\n\nfunction collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentName) {\n const fragment = context.getFragment(fragmentName);\n\n if (!fragment) {\n return;\n }\n\n const [fieldMap2, fragmentNames2] = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment); // Do not compare a fragment's fieldMap to itself.\n\n if (fieldMap === fieldMap2) {\n return;\n } // (D) First collect any conflicts between the provided collection of fields\n // and the collection of fields represented by the given fragment.\n\n\n collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fieldMap2); // (E) Then collect any conflicts between the provided collection of fields\n // and any fragment names found in the given fragment.\n\n for (let i = 0; i < fragmentNames2.length; i++) {\n collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentNames2[i]);\n }\n} // Collect all conflicts found between two fragments, including via spreading in\n// any nested fragments.\n\n\nfunction collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentName2) {\n // No need to compare a fragment to itself.\n if (fragmentName1 === fragmentName2) {\n return;\n } // Memoize so two fragments are not compared for conflicts more than once.\n\n\n if (comparedFragmentPairs.has(fragmentName1, fragmentName2, areMutuallyExclusive)) {\n return;\n }\n\n comparedFragmentPairs.add(fragmentName1, fragmentName2, areMutuallyExclusive);\n const fragment1 = context.getFragment(fragmentName1);\n const fragment2 = context.getFragment(fragmentName2);\n\n if (!fragment1 || !fragment2) {\n return;\n }\n\n const [fieldMap1, fragmentNames1] = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment1);\n const [fieldMap2, fragmentNames2] = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment2); // (F) First, collect all conflicts between these two collections of fields\n // (not including any nested fragments).\n\n collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2); // (G) Then collect conflicts between the first fragment and any nested\n // fragments spread in the second fragment.\n\n for (let j = 0; j < fragmentNames2.length; j++) {\n collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentNames2[j]);\n } // (G) Then collect conflicts between the second fragment and any nested\n // fragments spread in the first fragment.\n\n\n for (let i = 0; i < fragmentNames1.length; i++) {\n collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[i], fragmentName2);\n }\n} // Find all conflicts found between two selection sets, including those found\n// via spreading in fragments. Called when determining if conflicts exist\n// between the sub-fields of two overlapping fields.\n\n\nfunction findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, parentType1, selectionSet1, parentType2, selectionSet2) {\n const conflicts = [];\n const [fieldMap1, fragmentNames1] = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType1, selectionSet1);\n const [fieldMap2, fragmentNames2] = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType2, selectionSet2); // (H) First, collect all conflicts between these two collections of field.\n\n collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2); // (I) Then collect conflicts between the first collection of fields and\n // those referenced by each fragment name associated with the second.\n\n if (fragmentNames2.length !== 0) {\n for (let j = 0; j < fragmentNames2.length; j++) {\n collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fragmentNames2[j]);\n }\n } // (I) Then collect conflicts between the second collection of fields and\n // those referenced by each fragment name associated with the first.\n\n\n if (fragmentNames1.length !== 0) {\n for (let i = 0; i < fragmentNames1.length; i++) {\n collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap2, fragmentNames1[i]);\n }\n } // (J) Also collect conflicts between any fragment names by the first and\n // fragment names by the second. This compares each item in the first set of\n // names to each item in the second set of names.\n\n\n for (let i = 0; i < fragmentNames1.length; i++) {\n for (let j = 0; j < fragmentNames2.length; j++) {\n collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[i], fragmentNames2[j]);\n }\n }\n\n return conflicts;\n} // Collect all Conflicts \"within\" one collection of fields.\n\n\nfunction collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap) {\n // A field map is a keyed collection, where each key represents a response\n // name and the value at that key is a list of all fields which provide that\n // response name. For every response name, if there are multiple fields, they\n // must be compared to find a potential conflict.\n for (const [responseName, fields] of objectEntries(fieldMap)) {\n // This compares every field in the list to every other field in this list\n // (except to itself). If the list only has one item, nothing needs to\n // be compared.\n if (fields.length > 1) {\n for (let i = 0; i < fields.length; i++) {\n for (let j = i + 1; j < fields.length; j++) {\n const conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, // within one collection is never mutually exclusive\n responseName, fields[i], fields[j]);\n\n if (conflict) {\n conflicts.push(conflict);\n }\n }\n }\n }\n }\n} // Collect all Conflicts between two collections of fields. This is similar to,\n// but different from the `collectConflictsWithin` function above. This check\n// assumes that `collectConflictsWithin` has already been called on each\n// provided collection of fields. This is true because this validator traverses\n// each individual selection set.\n\n\nfunction collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, fieldMap1, fieldMap2) {\n // A field map is a keyed collection, where each key represents a response\n // name and the value at that key is a list of all fields which provide that\n // response name. For any response name which appears in both provided field\n // maps, each field from the first field map must be compared to every field\n // in the second field map to find potential conflicts.\n for (const responseName of Object.keys(fieldMap1)) {\n const fields2 = fieldMap2[responseName];\n\n if (fields2) {\n const fields1 = fieldMap1[responseName];\n\n for (let i = 0; i < fields1.length; i++) {\n for (let j = 0; j < fields2.length; j++) {\n const conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, fields1[i], fields2[j]);\n\n if (conflict) {\n conflicts.push(conflict);\n }\n }\n }\n }\n }\n} // Determines if there is a conflict between two particular fields, including\n// comparing their sub-fields.\n\n\nfunction findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, field1, field2) {\n const [parentType1, node1, def1] = field1;\n const [parentType2, node2, def2] = field2; // If it is known that two fields could not possibly apply at the same\n // time, due to the parent types, then it is safe to permit them to diverge\n // in aliased field or arguments used as they will not present any ambiguity\n // by differing.\n // It is known that two parent types could never overlap if they are\n // different Object types. Interface or Union types might overlap - if not\n // in the current state of the schema, then perhaps in some future version,\n // thus may not safely diverge.\n\n const areMutuallyExclusive = parentFieldsAreMutuallyExclusive || parentType1 !== parentType2 && isObjectType(parentType1) && isObjectType(parentType2);\n\n if (!areMutuallyExclusive) {\n // Two aliases must refer to the same field.\n const name1 = node1.name.value;\n const name2 = node2.name.value;\n\n if (name1 !== name2) {\n return [[responseName, `\"${name1}\" and \"${name2}\" are different fields`], [node1], [node2]];\n } // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n\n\n const args1 = node1.arguments ?? []; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n\n const args2 = node2.arguments ?? []; // Two field calls must have the same arguments.\n\n if (!sameArguments(args1, args2)) {\n return [[responseName, 'they have differing arguments'], [node1], [node2]];\n }\n } // The return type for each field.\n\n\n const type1 = def1?.type;\n const type2 = def2?.type;\n\n if (type1 && type2 && doTypesConflict(type1, type2)) {\n return [[responseName, `they return conflicting types \"${inspect(type1)}\" and \"${inspect(type2)}\"`], [node1], [node2]];\n } // Collect and compare sub-fields. Use the same \"visited fragment names\" list\n // for both collections so fields in a fragment reference are never\n // compared to themselves.\n\n\n const selectionSet1 = node1.selectionSet;\n const selectionSet2 = node2.selectionSet;\n\n if (selectionSet1 && selectionSet2) {\n const conflicts = findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, getNamedType(type1), selectionSet1, getNamedType(type2), selectionSet2);\n return subfieldConflicts(conflicts, responseName, node1, node2);\n }\n}\n\nfunction sameArguments(arguments1, arguments2) {\n if (arguments1.length !== arguments2.length) {\n return false;\n }\n\n return arguments1.every(argument1 => {\n const argument2 = arguments2.find(argument => argument.name.value === argument1.name.value);\n\n if (!argument2) {\n return false;\n }\n\n return sameValue(argument1.value, argument2.value);\n });\n}\n\nfunction sameValue(value1, value2) {\n return print(value1) === print(value2);\n} // Two types conflict if both types could not apply to a value simultaneously.\n// Composite types are ignored as their individual field types will be compared\n// later recursively. However List and Non-Null types must match.\n\n\nfunction doTypesConflict(type1, type2) {\n if (isListType(type1)) {\n return isListType(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;\n }\n\n if (isListType(type2)) {\n return true;\n }\n\n if (isNonNullType(type1)) {\n return isNonNullType(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;\n }\n\n if (isNonNullType(type2)) {\n return true;\n }\n\n if (isLeafType(type1) || isLeafType(type2)) {\n return type1 !== type2;\n }\n\n return false;\n} // Given a selection set, return the collection of fields (a mapping of response\n// name to field nodes and definitions) as well as a list of fragment names\n// referenced via fragment spreads.\n\n\nfunction getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet) {\n let cached = cachedFieldsAndFragmentNames.get(selectionSet);\n\n if (!cached) {\n const nodeAndDefs = Object.create(null);\n const fragmentNames = Object.create(null);\n\n _collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames);\n\n cached = [nodeAndDefs, Object.keys(fragmentNames)];\n cachedFieldsAndFragmentNames.set(selectionSet, cached);\n }\n\n return cached;\n} // Given a reference to a fragment, return the represented collection of fields\n// as well as a list of nested fragment names referenced via fragment spreads.\n\n\nfunction getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment) {\n // Short-circuit building a type from the node if possible.\n const cached = cachedFieldsAndFragmentNames.get(fragment.selectionSet);\n\n if (cached) {\n return cached;\n }\n\n const fragmentType = typeFromAST(context.getSchema(), fragment.typeCondition);\n return getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragmentType, fragment.selectionSet);\n}\n\nfunction _collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames) {\n for (const selection of selectionSet.selections) {\n switch (selection.kind) {\n case Kind.FIELD:\n {\n const fieldName = selection.name.value;\n let fieldDef;\n\n if (isObjectType(parentType) || isInterfaceType(parentType)) {\n fieldDef = parentType.getFields()[fieldName];\n }\n\n const responseName = selection.alias ? selection.alias.value : fieldName;\n\n if (!nodeAndDefs[responseName]) {\n nodeAndDefs[responseName] = [];\n }\n\n nodeAndDefs[responseName].push([parentType, selection, fieldDef]);\n break;\n }\n\n case Kind.FRAGMENT_SPREAD:\n fragmentNames[selection.name.value] = true;\n break;\n\n case Kind.INLINE_FRAGMENT:\n {\n const typeCondition = selection.typeCondition;\n const inlineFragmentType = typeCondition ? typeFromAST(context.getSchema(), typeCondition) : parentType;\n\n _collectFieldsAndFragmentNames(context, inlineFragmentType, selection.selectionSet, nodeAndDefs, fragmentNames);\n\n break;\n }\n }\n }\n} // Given a series of Conflicts which occurred between two sub-fields, generate\n// a single Conflict.\n\n\nfunction subfieldConflicts(conflicts, responseName, node1, node2) {\n if (conflicts.length > 0) {\n return [[responseName, conflicts.map(([reason]) => reason)], conflicts.reduce((allFields, [, fields1]) => allFields.concat(fields1), [node1]), conflicts.reduce((allFields, [,, fields2]) => allFields.concat(fields2), [node2])];\n }\n}\n/**\n * A way to keep track of pairs of things when the ordering of the pair does\n * not matter. We do this by maintaining a sort of double adjacency sets.\n */\n\n\nclass PairSet {\n constructor() {\n this._data = Object.create(null);\n }\n\n has(a, b, areMutuallyExclusive) {\n const first = this._data[a];\n const result = first && first[b];\n\n if (result === undefined) {\n return false;\n } // areMutuallyExclusive being false is a superset of being true,\n // hence if we want to know if this PairSet \"has\" these two with no\n // exclusivity, we have to ensure it was added as such.\n\n\n if (areMutuallyExclusive === false) {\n return result === false;\n }\n\n return true;\n }\n\n add(a, b, areMutuallyExclusive) {\n this._pairSetAdd(a, b, areMutuallyExclusive);\n\n this._pairSetAdd(b, a, areMutuallyExclusive);\n }\n\n _pairSetAdd(a, b, areMutuallyExclusive) {\n let map = this._data[a];\n\n if (!map) {\n map = Object.create(null);\n this._data[a] = map;\n }\n\n map[b] = areMutuallyExclusive;\n }\n\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique input field names\n *\n * A GraphQL input object value is only valid if all supplied fields are\n * uniquely named.\n */\nexport function UniqueInputFieldNamesRule(context) {\n const knownNameStack = [];\n let knownNames = Object.create(null);\n return {\n ObjectValue: {\n enter() {\n knownNameStack.push(knownNames);\n knownNames = Object.create(null);\n },\n\n leave() {\n knownNames = knownNameStack.pop();\n }\n\n },\n\n ObjectField(node) {\n const fieldName = node.name.value;\n\n if (knownNames[fieldName]) {\n context.reportError(new GraphQLError(`There can be only one input field named \"${fieldName}\".`, [knownNames[fieldName], node.name]));\n } else {\n knownNames[fieldName] = node.name;\n }\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { isObjectType, isInterfaceType, isInputObjectType } from \"../../type/definition.mjs\";\n\n/**\n * Unique field definition names\n *\n * A GraphQL complex type is only valid if all its fields are uniquely named.\n */\nexport function UniqueFieldDefinitionNamesRule(context) {\n const schema = context.getSchema();\n const existingTypeMap = schema ? schema.getTypeMap() : Object.create(null);\n const knownFieldNames = Object.create(null);\n return {\n InputObjectTypeDefinition: checkFieldUniqueness,\n InputObjectTypeExtension: checkFieldUniqueness,\n InterfaceTypeDefinition: checkFieldUniqueness,\n InterfaceTypeExtension: checkFieldUniqueness,\n ObjectTypeDefinition: checkFieldUniqueness,\n ObjectTypeExtension: checkFieldUniqueness\n };\n\n function checkFieldUniqueness(node) {\n const typeName = node.name.value;\n\n if (!knownFieldNames[typeName]) {\n knownFieldNames[typeName] = Object.create(null);\n } // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n\n\n const fieldNodes = node.fields ?? [];\n const fieldNames = knownFieldNames[typeName];\n\n for (const fieldDef of fieldNodes) {\n const fieldName = fieldDef.name.value;\n\n if (hasField(existingTypeMap[typeName], fieldName)) {\n context.reportError(new GraphQLError(`Field \"${typeName}.${fieldName}\" already exists in the schema. It cannot also be defined in this type extension.`, fieldDef.name));\n } else if (fieldNames[fieldName]) {\n context.reportError(new GraphQLError(`Field \"${typeName}.${fieldName}\" can only be defined once.`, [fieldNames[fieldName], fieldDef.name]));\n } else {\n fieldNames[fieldName] = fieldDef.name;\n }\n }\n\n return false;\n }\n}\n\nfunction hasField(type, fieldName) {\n if (isObjectType(type) || isInterfaceType(type) || isInputObjectType(type)) {\n return type.getFields()[fieldName] != null;\n }\n\n return false;\n}\n","import inspect from \"../../jsutils/inspect.mjs\";\nimport invariant from \"../../jsutils/invariant.mjs\";\nimport didYouMean from \"../../jsutils/didYouMean.mjs\";\nimport suggestionList from \"../../jsutils/suggestionList.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { isTypeDefinitionNode } from \"../../language/predicates.mjs\";\nimport { isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType } from \"../../type/definition.mjs\";\n\n/**\n * Possible type extension\n *\n * A type extension is only valid if the type is defined and has the same kind.\n */\nexport function PossibleTypeExtensionsRule(context) {\n const schema = context.getSchema();\n const definedTypes = Object.create(null);\n\n for (const def of context.getDocument().definitions) {\n if (isTypeDefinitionNode(def)) {\n definedTypes[def.name.value] = def;\n }\n }\n\n return {\n ScalarTypeExtension: checkExtension,\n ObjectTypeExtension: checkExtension,\n InterfaceTypeExtension: checkExtension,\n UnionTypeExtension: checkExtension,\n EnumTypeExtension: checkExtension,\n InputObjectTypeExtension: checkExtension\n };\n\n function checkExtension(node) {\n const typeName = node.name.value;\n const defNode = definedTypes[typeName];\n const existingType = schema?.getType(typeName);\n let expectedKind;\n\n if (defNode) {\n expectedKind = defKindToExtKind[defNode.kind];\n } else if (existingType) {\n expectedKind = typeToExtKind(existingType);\n }\n\n if (expectedKind) {\n if (expectedKind !== node.kind) {\n const kindStr = extensionKindToTypeName(node.kind);\n context.reportError(new GraphQLError(`Cannot extend non-${kindStr} type \"${typeName}\".`, defNode ? [defNode, node] : node));\n }\n } else {\n let allTypeNames = Object.keys(definedTypes);\n\n if (schema) {\n allTypeNames = allTypeNames.concat(Object.keys(schema.getTypeMap()));\n }\n\n const suggestedTypes = suggestionList(typeName, allTypeNames);\n context.reportError(new GraphQLError(`Cannot extend type \"${typeName}\" because it is not defined.` + didYouMean(suggestedTypes), node.name));\n }\n }\n}\nconst defKindToExtKind = {\n [Kind.SCALAR_TYPE_DEFINITION]: Kind.SCALAR_TYPE_EXTENSION,\n [Kind.OBJECT_TYPE_DEFINITION]: Kind.OBJECT_TYPE_EXTENSION,\n [Kind.INTERFACE_TYPE_DEFINITION]: Kind.INTERFACE_TYPE_EXTENSION,\n [Kind.UNION_TYPE_DEFINITION]: Kind.UNION_TYPE_EXTENSION,\n [Kind.ENUM_TYPE_DEFINITION]: Kind.ENUM_TYPE_EXTENSION,\n [Kind.INPUT_OBJECT_TYPE_DEFINITION]: Kind.INPUT_OBJECT_TYPE_EXTENSION\n};\n\nfunction typeToExtKind(type) {\n if (isScalarType(type)) {\n return Kind.SCALAR_TYPE_EXTENSION;\n }\n\n if (isObjectType(type)) {\n return Kind.OBJECT_TYPE_EXTENSION;\n }\n\n if (isInterfaceType(type)) {\n return Kind.INTERFACE_TYPE_EXTENSION;\n }\n\n if (isUnionType(type)) {\n return Kind.UNION_TYPE_EXTENSION;\n }\n\n if (isEnumType(type)) {\n return Kind.ENUM_TYPE_EXTENSION;\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (isInputObjectType(type)) {\n return Kind.INPUT_OBJECT_TYPE_EXTENSION;\n } // istanbul ignore next (Not reachable. All possible types have been considered)\n\n\n false || invariant(0, 'Unexpected type: ' + inspect(type));\n}\n\nfunction extensionKindToTypeName(kind) {\n switch (kind) {\n case Kind.SCALAR_TYPE_EXTENSION:\n return 'scalar';\n\n case Kind.OBJECT_TYPE_EXTENSION:\n return 'object';\n\n case Kind.INTERFACE_TYPE_EXTENSION:\n return 'interface';\n\n case Kind.UNION_TYPE_EXTENSION:\n return 'union';\n\n case Kind.ENUM_TYPE_EXTENSION:\n return 'enum';\n\n case Kind.INPUT_OBJECT_TYPE_EXTENSION:\n return 'input object';\n } // istanbul ignore next (Not reachable. All possible types have been considered)\n\n\n false || invariant(0, 'Unexpected kind: ' + inspect(kind));\n}\n","// Spec Section: \"Executable Definitions\"\nimport { ExecutableDefinitionsRule } from \"./rules/ExecutableDefinitionsRule.mjs\"; // Spec Section: \"Operation Name Uniqueness\"\n\nimport { UniqueOperationNamesRule } from \"./rules/UniqueOperationNamesRule.mjs\"; // Spec Section: \"Lone Anonymous Operation\"\n\nimport { LoneAnonymousOperationRule } from \"./rules/LoneAnonymousOperationRule.mjs\"; // Spec Section: \"Subscriptions with Single Root Field\"\n\nimport { SingleFieldSubscriptionsRule } from \"./rules/SingleFieldSubscriptionsRule.mjs\"; // Spec Section: \"Fragment Spread Type Existence\"\n\nimport { KnownTypeNamesRule } from \"./rules/KnownTypeNamesRule.mjs\"; // Spec Section: \"Fragments on Composite Types\"\n\nimport { FragmentsOnCompositeTypesRule } from \"./rules/FragmentsOnCompositeTypesRule.mjs\"; // Spec Section: \"Variables are Input Types\"\n\nimport { VariablesAreInputTypesRule } from \"./rules/VariablesAreInputTypesRule.mjs\"; // Spec Section: \"Leaf Field Selections\"\n\nimport { ScalarLeafsRule } from \"./rules/ScalarLeafsRule.mjs\"; // Spec Section: \"Field Selections on Objects, Interfaces, and Unions Types\"\n\nimport { FieldsOnCorrectTypeRule } from \"./rules/FieldsOnCorrectTypeRule.mjs\"; // Spec Section: \"Fragment Name Uniqueness\"\n\nimport { UniqueFragmentNamesRule } from \"./rules/UniqueFragmentNamesRule.mjs\"; // Spec Section: \"Fragment spread target defined\"\n\nimport { KnownFragmentNamesRule } from \"./rules/KnownFragmentNamesRule.mjs\"; // Spec Section: \"Fragments must be used\"\n\nimport { NoUnusedFragmentsRule } from \"./rules/NoUnusedFragmentsRule.mjs\"; // Spec Section: \"Fragment spread is possible\"\n\nimport { PossibleFragmentSpreadsRule } from \"./rules/PossibleFragmentSpreadsRule.mjs\"; // Spec Section: \"Fragments must not form cycles\"\n\nimport { NoFragmentCyclesRule } from \"./rules/NoFragmentCyclesRule.mjs\"; // Spec Section: \"Variable Uniqueness\"\n\nimport { UniqueVariableNamesRule } from \"./rules/UniqueVariableNamesRule.mjs\"; // Spec Section: \"All Variable Used Defined\"\n\nimport { NoUndefinedVariablesRule } from \"./rules/NoUndefinedVariablesRule.mjs\"; // Spec Section: \"All Variables Used\"\n\nimport { NoUnusedVariablesRule } from \"./rules/NoUnusedVariablesRule.mjs\"; // Spec Section: \"Directives Are Defined\"\n\nimport { KnownDirectivesRule } from \"./rules/KnownDirectivesRule.mjs\"; // Spec Section: \"Directives Are Unique Per Location\"\n\nimport { UniqueDirectivesPerLocationRule } from \"./rules/UniqueDirectivesPerLocationRule.mjs\"; // Spec Section: \"Argument Names\"\n\nimport { KnownArgumentNamesRule, KnownArgumentNamesOnDirectivesRule } from \"./rules/KnownArgumentNamesRule.mjs\"; // Spec Section: \"Argument Uniqueness\"\n\nimport { UniqueArgumentNamesRule } from \"./rules/UniqueArgumentNamesRule.mjs\"; // Spec Section: \"Value Type Correctness\"\n\nimport { ValuesOfCorrectTypeRule } from \"./rules/ValuesOfCorrectTypeRule.mjs\"; // Spec Section: \"Argument Optionality\"\n\nimport { ProvidedRequiredArgumentsRule, ProvidedRequiredArgumentsOnDirectivesRule } from \"./rules/ProvidedRequiredArgumentsRule.mjs\"; // Spec Section: \"All Variable Usages Are Allowed\"\n\nimport { VariablesInAllowedPositionRule } from \"./rules/VariablesInAllowedPositionRule.mjs\"; // Spec Section: \"Field Selection Merging\"\n\nimport { OverlappingFieldsCanBeMergedRule } from \"./rules/OverlappingFieldsCanBeMergedRule.mjs\"; // Spec Section: \"Input Object Field Uniqueness\"\n\nimport { UniqueInputFieldNamesRule } from \"./rules/UniqueInputFieldNamesRule.mjs\"; // SDL-specific validation rules\n\nimport { LoneSchemaDefinitionRule } from \"./rules/LoneSchemaDefinitionRule.mjs\";\nimport { UniqueOperationTypesRule } from \"./rules/UniqueOperationTypesRule.mjs\";\nimport { UniqueTypeNamesRule } from \"./rules/UniqueTypeNamesRule.mjs\";\nimport { UniqueEnumValueNamesRule } from \"./rules/UniqueEnumValueNamesRule.mjs\";\nimport { UniqueFieldDefinitionNamesRule } from \"./rules/UniqueFieldDefinitionNamesRule.mjs\";\nimport { UniqueDirectiveNamesRule } from \"./rules/UniqueDirectiveNamesRule.mjs\";\nimport { PossibleTypeExtensionsRule } from \"./rules/PossibleTypeExtensionsRule.mjs\";\n/**\n * This set includes all validation rules defined by the GraphQL spec.\n *\n * The order of the rules in this list has been adjusted to lead to the\n * most clear output when encountering multiple validation errors.\n */\n\nexport const specifiedRules = Object.freeze([ExecutableDefinitionsRule, UniqueOperationNamesRule, LoneAnonymousOperationRule, SingleFieldSubscriptionsRule, KnownTypeNamesRule, FragmentsOnCompositeTypesRule, VariablesAreInputTypesRule, ScalarLeafsRule, FieldsOnCorrectTypeRule, UniqueFragmentNamesRule, KnownFragmentNamesRule, NoUnusedFragmentsRule, PossibleFragmentSpreadsRule, NoFragmentCyclesRule, UniqueVariableNamesRule, NoUndefinedVariablesRule, NoUnusedVariablesRule, KnownDirectivesRule, UniqueDirectivesPerLocationRule, KnownArgumentNamesRule, UniqueArgumentNamesRule, ValuesOfCorrectTypeRule, ProvidedRequiredArgumentsRule, VariablesInAllowedPositionRule, OverlappingFieldsCanBeMergedRule, UniqueInputFieldNamesRule]);\n/**\n * @internal\n */\n\nexport const specifiedSDLRules = Object.freeze([LoneSchemaDefinitionRule, UniqueOperationTypesRule, UniqueTypeNamesRule, UniqueEnumValueNamesRule, UniqueFieldDefinitionNamesRule, UniqueDirectiveNamesRule, KnownTypeNamesRule, KnownDirectivesRule, UniqueDirectivesPerLocationRule, PossibleTypeExtensionsRule, KnownArgumentNamesOnDirectivesRule, UniqueArgumentNamesRule, UniqueInputFieldNamesRule, ProvidedRequiredArgumentsOnDirectivesRule]);\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\nimport { isExecutableDefinitionNode } from \"../../language/predicates.mjs\";\n\n/**\n * Executable definitions\n *\n * A GraphQL document is only valid for execution if all definitions are either\n * operation or fragment definitions.\n */\nexport function ExecutableDefinitionsRule(context) {\n return {\n Document(node) {\n for (const definition of node.definitions) {\n if (!isExecutableDefinitionNode(definition)) {\n const defName = definition.kind === Kind.SCHEMA_DEFINITION || definition.kind === Kind.SCHEMA_EXTENSION ? 'schema' : '\"' + definition.name.value + '\"';\n context.reportError(new GraphQLError(`The ${defName} definition is not executable.`, definition));\n }\n }\n\n return false;\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique operation names\n *\n * A GraphQL document is only valid if all defined operations have unique names.\n */\nexport function UniqueOperationNamesRule(context) {\n const knownOperationNames = Object.create(null);\n return {\n OperationDefinition(node) {\n const operationName = node.name;\n\n if (operationName) {\n if (knownOperationNames[operationName.value]) {\n context.reportError(new GraphQLError(`There can be only one operation named \"${operationName.value}\".`, [knownOperationNames[operationName.value], operationName]));\n } else {\n knownOperationNames[operationName.value] = operationName;\n }\n }\n\n return false;\n },\n\n FragmentDefinition: () => false\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { Kind } from \"../../language/kinds.mjs\";\n\n/**\n * Lone anonymous operation\n *\n * A GraphQL document is only valid if when it contains an anonymous operation\n * (the query short-hand) that it contains only that one operation definition.\n */\nexport function LoneAnonymousOperationRule(context) {\n let operationCount = 0;\n return {\n Document(node) {\n operationCount = node.definitions.filter(definition => definition.kind === Kind.OPERATION_DEFINITION).length;\n },\n\n OperationDefinition(node) {\n if (!node.name && operationCount > 1) {\n context.reportError(new GraphQLError('This anonymous operation must be the only defined operation.', node));\n }\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Subscriptions must only include one field.\n *\n * A GraphQL subscription is valid only if it contains a single root field.\n */\nexport function SingleFieldSubscriptionsRule(context) {\n return {\n OperationDefinition(node) {\n if (node.operation === 'subscription') {\n if (node.selectionSet.selections.length !== 1) {\n context.reportError(new GraphQLError(node.name ? `Subscription \"${node.name.value}\" must select only one top level field.` : 'Anonymous Subscription must select only one top level field.', node.selectionSet.selections.slice(1)));\n }\n }\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { print } from \"../../language/printer.mjs\";\nimport { isCompositeType } from \"../../type/definition.mjs\";\nimport { typeFromAST } from \"../../utilities/typeFromAST.mjs\";\n\n/**\n * Fragments on composite type\n *\n * Fragments use a type condition to determine if they apply, since fragments\n * can only be spread into a composite type (object, interface, or union), the\n * type condition must also be a composite type.\n */\nexport function FragmentsOnCompositeTypesRule(context) {\n return {\n InlineFragment(node) {\n const typeCondition = node.typeCondition;\n\n if (typeCondition) {\n const type = typeFromAST(context.getSchema(), typeCondition);\n\n if (type && !isCompositeType(type)) {\n const typeStr = print(typeCondition);\n context.reportError(new GraphQLError(`Fragment cannot condition on non composite type \"${typeStr}\".`, typeCondition));\n }\n }\n },\n\n FragmentDefinition(node) {\n const type = typeFromAST(context.getSchema(), node.typeCondition);\n\n if (type && !isCompositeType(type)) {\n const typeStr = print(node.typeCondition);\n context.reportError(new GraphQLError(`Fragment \"${node.name.value}\" cannot condition on non composite type \"${typeStr}\".`, node.typeCondition));\n }\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { print } from \"../../language/printer.mjs\";\nimport { isInputType } from \"../../type/definition.mjs\";\nimport { typeFromAST } from \"../../utilities/typeFromAST.mjs\";\n\n/**\n * Variables are input types\n *\n * A GraphQL operation is only valid if all the variables it defines are of\n * input types (scalar, enum, or input object).\n */\nexport function VariablesAreInputTypesRule(context) {\n return {\n VariableDefinition(node) {\n const type = typeFromAST(context.getSchema(), node.type);\n\n if (type && !isInputType(type)) {\n const variableName = node.variable.name.value;\n const typeName = print(node.type);\n context.reportError(new GraphQLError(`Variable \"$${variableName}\" cannot be non-input type \"${typeName}\".`, node.type));\n }\n }\n\n };\n}\n","import inspect from \"../../jsutils/inspect.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { getNamedType, isLeafType } from \"../../type/definition.mjs\";\n\n/**\n * Scalar leafs\n *\n * A GraphQL document is valid only if all leaf fields (fields without\n * sub selections) are of scalar or enum types.\n */\nexport function ScalarLeafsRule(context) {\n return {\n Field(node) {\n const type = context.getType();\n const selectionSet = node.selectionSet;\n\n if (type) {\n if (isLeafType(getNamedType(type))) {\n if (selectionSet) {\n const fieldName = node.name.value;\n const typeStr = inspect(type);\n context.reportError(new GraphQLError(`Field \"${fieldName}\" must not have a selection since type \"${typeStr}\" has no subfields.`, selectionSet));\n }\n } else if (!selectionSet) {\n const fieldName = node.name.value;\n const typeStr = inspect(type);\n context.reportError(new GraphQLError(`Field \"${fieldName}\" of type \"${typeStr}\" must have a selection of subfields. Did you mean \"${fieldName} { ... }\"?`, node));\n }\n }\n }\n\n };\n}\n","import didYouMean from \"../../jsutils/didYouMean.mjs\";\nimport suggestionList from \"../../jsutils/suggestionList.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { isObjectType, isInterfaceType, isAbstractType } from \"../../type/definition.mjs\";\n\n/**\n * Fields on correct type\n *\n * A GraphQL document is only valid if all fields selected are defined by the\n * parent type, or are an allowed meta field such as __typename.\n */\nexport function FieldsOnCorrectTypeRule(context) {\n return {\n Field(node) {\n const type = context.getParentType();\n\n if (type) {\n const fieldDef = context.getFieldDef();\n\n if (!fieldDef) {\n // This field doesn't exist, lets look for suggestions.\n const schema = context.getSchema();\n const fieldName = node.name.value; // First determine if there are any suggested types to condition on.\n\n let suggestion = didYouMean('to use an inline fragment on', getSuggestedTypeNames(schema, type, fieldName)); // If there are no suggested types, then perhaps this was a typo?\n\n if (suggestion === '') {\n suggestion = didYouMean(getSuggestedFieldNames(type, fieldName));\n } // Report an error, including helpful suggestions.\n\n\n context.reportError(new GraphQLError(`Cannot query field \"${fieldName}\" on type \"${type.name}\".` + suggestion, node));\n }\n }\n }\n\n };\n}\n/**\n * Go through all of the implementations of type, as well as the interfaces that\n * they implement. If any of those types include the provided field, suggest them,\n * sorted by how often the type is referenced.\n */\n\nfunction getSuggestedTypeNames(schema, type, fieldName) {\n if (!isAbstractType(type)) {\n // Must be an Object type, which does not have possible fields.\n return [];\n }\n\n const suggestedTypes = new Set();\n const usageCount = Object.create(null);\n\n for (const possibleType of schema.getPossibleTypes(type)) {\n if (!possibleType.getFields()[fieldName]) {\n continue;\n } // This object type defines this field.\n\n\n suggestedTypes.add(possibleType);\n usageCount[possibleType.name] = 1;\n\n for (const possibleInterface of possibleType.getInterfaces()) {\n if (!possibleInterface.getFields()[fieldName]) {\n continue;\n } // This interface type defines this field.\n\n\n suggestedTypes.add(possibleInterface);\n usageCount[possibleInterface.name] = (usageCount[possibleInterface.name] ?? 0) + 1;\n }\n }\n\n return Array.from(suggestedTypes).sort((typeA, typeB) => {\n // Suggest both interface and object types based on how common they are.\n const usageCountDiff = usageCount[typeB.name] - usageCount[typeA.name];\n\n if (usageCountDiff !== 0) {\n return usageCountDiff;\n } // Suggest super types first followed by subtypes\n\n\n if (isInterfaceType(typeA) && schema.isSubType(typeA, typeB)) {\n return -1;\n }\n\n if (isInterfaceType(typeB) && schema.isSubType(typeB, typeA)) {\n return 1;\n }\n\n return typeA.name.localeCompare(typeB.name);\n }).map(x => x.name);\n}\n/**\n * For the field name provided, determine if there are any similar field names\n * that may be the result of a typo.\n */\n\n\nfunction getSuggestedFieldNames(type, fieldName) {\n if (isObjectType(type) || isInterfaceType(type)) {\n const possibleFieldNames = Object.keys(type.getFields());\n return suggestionList(fieldName, possibleFieldNames);\n } // Otherwise, must be a Union type, which does not define fields.\n\n\n return [];\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique fragment names\n *\n * A GraphQL document is only valid if all defined fragments have unique names.\n */\nexport function UniqueFragmentNamesRule(context) {\n const knownFragmentNames = Object.create(null);\n return {\n OperationDefinition: () => false,\n\n FragmentDefinition(node) {\n const fragmentName = node.name.value;\n\n if (knownFragmentNames[fragmentName]) {\n context.reportError(new GraphQLError(`There can be only one fragment named \"${fragmentName}\".`, [knownFragmentNames[fragmentName], node.name]));\n } else {\n knownFragmentNames[fragmentName] = node.name;\n }\n\n return false;\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Known fragment names\n *\n * A GraphQL document is only valid if all `...Fragment` fragment spreads refer\n * to fragments defined in the same document.\n */\nexport function KnownFragmentNamesRule(context) {\n return {\n FragmentSpread(node) {\n const fragmentName = node.name.value;\n const fragment = context.getFragment(fragmentName);\n\n if (!fragment) {\n context.reportError(new GraphQLError(`Unknown fragment \"${fragmentName}\".`, node.name));\n }\n }\n\n };\n}\n","import inspect from \"../../jsutils/inspect.mjs\";\nimport { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { isCompositeType } from \"../../type/definition.mjs\";\nimport { typeFromAST } from \"../../utilities/typeFromAST.mjs\";\nimport { doTypesOverlap } from \"../../utilities/typeComparators.mjs\";\n\n/**\n * Possible fragment spread\n *\n * A fragment spread is only valid if the type condition could ever possibly\n * be true: if there is a non-empty intersection of the possible parent types,\n * and possible types which pass the type condition.\n */\nexport function PossibleFragmentSpreadsRule(context) {\n return {\n InlineFragment(node) {\n const fragType = context.getType();\n const parentType = context.getParentType();\n\n if (isCompositeType(fragType) && isCompositeType(parentType) && !doTypesOverlap(context.getSchema(), fragType, parentType)) {\n const parentTypeStr = inspect(parentType);\n const fragTypeStr = inspect(fragType);\n context.reportError(new GraphQLError(`Fragment cannot be spread here as objects of type \"${parentTypeStr}\" can never be of type \"${fragTypeStr}\".`, node));\n }\n },\n\n FragmentSpread(node) {\n const fragName = node.name.value;\n const fragType = getFragmentType(context, fragName);\n const parentType = context.getParentType();\n\n if (fragType && parentType && !doTypesOverlap(context.getSchema(), fragType, parentType)) {\n const parentTypeStr = inspect(parentType);\n const fragTypeStr = inspect(fragType);\n context.reportError(new GraphQLError(`Fragment \"${fragName}\" cannot be spread here as objects of type \"${parentTypeStr}\" can never be of type \"${fragTypeStr}\".`, node));\n }\n }\n\n };\n}\n\nfunction getFragmentType(context, name) {\n const frag = context.getFragment(name);\n\n if (frag) {\n const type = typeFromAST(context.getSchema(), frag.typeCondition);\n\n if (isCompositeType(type)) {\n return type;\n }\n }\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nexport function NoFragmentCyclesRule(context) {\n // Tracks already visited fragments to maintain O(N) and to ensure that cycles\n // are not redundantly reported.\n const visitedFrags = Object.create(null); // Array of AST nodes used to produce meaningful errors\n\n const spreadPath = []; // Position in the spread path\n\n const spreadPathIndexByName = Object.create(null);\n return {\n OperationDefinition: () => false,\n\n FragmentDefinition(node) {\n detectCycleRecursive(node);\n return false;\n }\n\n }; // This does a straight-forward DFS to find cycles.\n // It does not terminate when a cycle was found but continues to explore\n // the graph to find all possible cycles.\n\n function detectCycleRecursive(fragment) {\n if (visitedFrags[fragment.name.value]) {\n return;\n }\n\n const fragmentName = fragment.name.value;\n visitedFrags[fragmentName] = true;\n const spreadNodes = context.getFragmentSpreads(fragment.selectionSet);\n\n if (spreadNodes.length === 0) {\n return;\n }\n\n spreadPathIndexByName[fragmentName] = spreadPath.length;\n\n for (const spreadNode of spreadNodes) {\n const spreadName = spreadNode.name.value;\n const cycleIndex = spreadPathIndexByName[spreadName];\n spreadPath.push(spreadNode);\n\n if (cycleIndex === undefined) {\n const spreadFragment = context.getFragment(spreadName);\n\n if (spreadFragment) {\n detectCycleRecursive(spreadFragment);\n }\n } else {\n const cyclePath = spreadPath.slice(cycleIndex);\n const viaPath = cyclePath.slice(0, -1).map(s => '\"' + s.name.value + '\"').join(', ');\n context.reportError(new GraphQLError(`Cannot spread fragment \"${spreadName}\" within itself` + (viaPath !== '' ? ` via ${viaPath}.` : '.'), cyclePath));\n }\n\n spreadPath.pop();\n }\n\n spreadPathIndexByName[fragmentName] = undefined;\n }\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique variable names\n *\n * A GraphQL operation is only valid if all its variables are uniquely named.\n */\nexport function UniqueVariableNamesRule(context) {\n let knownVariableNames = Object.create(null);\n return {\n OperationDefinition() {\n knownVariableNames = Object.create(null);\n },\n\n VariableDefinition(node) {\n const variableName = node.variable.name.value;\n\n if (knownVariableNames[variableName]) {\n context.reportError(new GraphQLError(`There can be only one variable named \"$${variableName}\".`, [knownVariableNames[variableName], node.variable.name]));\n } else {\n knownVariableNames[variableName] = node.variable.name;\n }\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * No undefined variables\n *\n * A GraphQL operation is only valid if all variables encountered, both directly\n * and via fragment spreads, are defined by that operation.\n */\nexport function NoUndefinedVariablesRule(context) {\n let variableNameDefined = Object.create(null);\n return {\n OperationDefinition: {\n enter() {\n variableNameDefined = Object.create(null);\n },\n\n leave(operation) {\n const usages = context.getRecursiveVariableUsages(operation);\n\n for (const {\n node\n } of usages) {\n const varName = node.name.value;\n\n if (variableNameDefined[varName] !== true) {\n context.reportError(new GraphQLError(operation.name ? `Variable \"$${varName}\" is not defined by operation \"${operation.name.value}\".` : `Variable \"$${varName}\" is not defined.`, [node, operation]));\n }\n }\n }\n\n },\n\n VariableDefinition(node) {\n variableNameDefined[node.variable.name.value] = true;\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * No unused variables\n *\n * A GraphQL operation is only valid if all variables defined by an operation\n * are used, either directly or within a spread fragment.\n */\nexport function NoUnusedVariablesRule(context) {\n let variableDefs = [];\n return {\n OperationDefinition: {\n enter() {\n variableDefs = [];\n },\n\n leave(operation) {\n const variableNameUsed = Object.create(null);\n const usages = context.getRecursiveVariableUsages(operation);\n\n for (const {\n node\n } of usages) {\n variableNameUsed[node.name.value] = true;\n }\n\n for (const variableDef of variableDefs) {\n const variableName = variableDef.variable.name.value;\n\n if (variableNameUsed[variableName] !== true) {\n context.reportError(new GraphQLError(operation.name ? `Variable \"$${variableName}\" is never used in operation \"${operation.name.value}\".` : `Variable \"$${variableName}\" is never used.`, variableDef));\n }\n }\n }\n\n },\n\n VariableDefinition(def) {\n variableDefs.push(def);\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Lone Schema definition\n *\n * A GraphQL document is only valid if it contains only one schema definition.\n */\nexport function LoneSchemaDefinitionRule(context) {\n const oldSchema = context.getSchema();\n const alreadyDefined = oldSchema?.astNode ?? oldSchema?.getQueryType() ?? oldSchema?.getMutationType() ?? oldSchema?.getSubscriptionType();\n let schemaDefinitionsCount = 0;\n return {\n SchemaDefinition(node) {\n if (alreadyDefined) {\n context.reportError(new GraphQLError('Cannot define a new schema within a schema extension.', node));\n return;\n }\n\n if (schemaDefinitionsCount > 0) {\n context.reportError(new GraphQLError('Must provide only one schema definition.', node));\n }\n\n ++schemaDefinitionsCount;\n }\n\n };\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique operation types\n *\n * A GraphQL document is only valid if it has only one type per operation.\n */\nexport function UniqueOperationTypesRule(context) {\n const schema = context.getSchema();\n const definedOperationTypes = Object.create(null);\n const existingOperationTypes = schema ? {\n query: schema.getQueryType(),\n mutation: schema.getMutationType(),\n subscription: schema.getSubscriptionType()\n } : {};\n return {\n SchemaDefinition: checkOperationTypes,\n SchemaExtension: checkOperationTypes\n };\n\n function checkOperationTypes(node) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const operationTypesNodes = node.operationTypes ?? [];\n\n for (const operationType of operationTypesNodes) {\n const operation = operationType.operation;\n const alreadyDefinedOperationType = definedOperationTypes[operation];\n\n if (existingOperationTypes[operation]) {\n context.reportError(new GraphQLError(`Type for ${operation} already defined in the schema. It cannot be redefined.`, operationType));\n } else if (alreadyDefinedOperationType) {\n context.reportError(new GraphQLError(`There can be only one ${operation} type in schema.`, [alreadyDefinedOperationType, operationType]));\n } else {\n definedOperationTypes[operation] = operationType;\n }\n }\n\n return false;\n }\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique type names\n *\n * A GraphQL document is only valid if all defined types have unique names.\n */\nexport function UniqueTypeNamesRule(context) {\n const knownTypeNames = Object.create(null);\n const schema = context.getSchema();\n return {\n ScalarTypeDefinition: checkTypeName,\n ObjectTypeDefinition: checkTypeName,\n InterfaceTypeDefinition: checkTypeName,\n UnionTypeDefinition: checkTypeName,\n EnumTypeDefinition: checkTypeName,\n InputObjectTypeDefinition: checkTypeName\n };\n\n function checkTypeName(node) {\n const typeName = node.name.value;\n\n if (schema?.getType(typeName)) {\n context.reportError(new GraphQLError(`Type \"${typeName}\" already exists in the schema. It cannot also be defined in this type definition.`, node.name));\n return;\n }\n\n if (knownTypeNames[typeName]) {\n context.reportError(new GraphQLError(`There can be only one type named \"${typeName}\".`, [knownTypeNames[typeName], node.name]));\n } else {\n knownTypeNames[typeName] = node.name;\n }\n\n return false;\n }\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\nimport { isEnumType } from \"../../type/definition.mjs\";\n\n/**\n * Unique enum value names\n *\n * A GraphQL enum type is only valid if all its values are uniquely named.\n */\nexport function UniqueEnumValueNamesRule(context) {\n const schema = context.getSchema();\n const existingTypeMap = schema ? schema.getTypeMap() : Object.create(null);\n const knownValueNames = Object.create(null);\n return {\n EnumTypeDefinition: checkValueUniqueness,\n EnumTypeExtension: checkValueUniqueness\n };\n\n function checkValueUniqueness(node) {\n const typeName = node.name.value;\n\n if (!knownValueNames[typeName]) {\n knownValueNames[typeName] = Object.create(null);\n } // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n\n\n const valueNodes = node.values ?? [];\n const valueNames = knownValueNames[typeName];\n\n for (const valueDef of valueNodes) {\n const valueName = valueDef.name.value;\n const existingType = existingTypeMap[typeName];\n\n if (isEnumType(existingType) && existingType.getValue(valueName)) {\n context.reportError(new GraphQLError(`Enum value \"${typeName}.${valueName}\" already exists in the schema. It cannot also be defined in this type extension.`, valueDef.name));\n } else if (valueNames[valueName]) {\n context.reportError(new GraphQLError(`Enum value \"${typeName}.${valueName}\" can only be defined once.`, [valueNames[valueName], valueDef.name]));\n } else {\n valueNames[valueName] = valueDef.name;\n }\n }\n\n return false;\n }\n}\n","import { GraphQLError } from \"../../error/GraphQLError.mjs\";\n\n/**\n * Unique directive names\n *\n * A GraphQL document is only valid if all defined directives have unique names.\n */\nexport function UniqueDirectiveNamesRule(context) {\n const knownDirectiveNames = Object.create(null);\n const schema = context.getSchema();\n return {\n DirectiveDefinition(node) {\n const directiveName = node.name.value;\n\n if (schema?.getDirective(directiveName)) {\n context.reportError(new GraphQLError(`Directive \"@${directiveName}\" already exists in the schema. It cannot be redefined.`, node.name));\n return;\n }\n\n if (knownDirectiveNames[directiveName]) {\n context.reportError(new GraphQLError(`There can be only one directive named \"@${directiveName}\".`, [knownDirectiveNames[directiveName], node.name]));\n } else {\n knownDirectiveNames[directiveName] = node.name;\n }\n\n return false;\n }\n\n };\n}\n","import { Kind } from \"../language/kinds.mjs\";\nimport { visit } from \"../language/visitor.mjs\";\nimport { TypeInfo, visitWithTypeInfo } from \"../utilities/TypeInfo.mjs\";\n\n/**\n * An instance of this class is passed as the \"this\" context to all validators,\n * allowing access to commonly useful contextual information from within a\n * validation rule.\n */\nexport class ASTValidationContext {\n constructor(ast, onError) {\n this._ast = ast;\n this._fragments = undefined;\n this._fragmentSpreads = new Map();\n this._recursivelyReferencedFragments = new Map();\n this._onError = onError;\n }\n\n reportError(error) {\n this._onError(error);\n }\n\n getDocument() {\n return this._ast;\n }\n\n getFragment(name) {\n let fragments = this._fragments;\n\n if (!fragments) {\n this._fragments = fragments = this.getDocument().definitions.reduce((frags, statement) => {\n if (statement.kind === Kind.FRAGMENT_DEFINITION) {\n frags[statement.name.value] = statement;\n }\n\n return frags;\n }, Object.create(null));\n }\n\n return fragments[name];\n }\n\n getFragmentSpreads(node) {\n let spreads = this._fragmentSpreads.get(node);\n\n if (!spreads) {\n spreads = [];\n const setsToVisit = [node];\n\n while (setsToVisit.length !== 0) {\n const set = setsToVisit.pop();\n\n for (const selection of set.selections) {\n if (selection.kind === Kind.FRAGMENT_SPREAD) {\n spreads.push(selection);\n } else if (selection.selectionSet) {\n setsToVisit.push(selection.selectionSet);\n }\n }\n }\n\n this._fragmentSpreads.set(node, spreads);\n }\n\n return spreads;\n }\n\n getRecursivelyReferencedFragments(operation) {\n let fragments = this._recursivelyReferencedFragments.get(operation);\n\n if (!fragments) {\n fragments = [];\n const collectedNames = Object.create(null);\n const nodesToVisit = [operation.selectionSet];\n\n while (nodesToVisit.length !== 0) {\n const node = nodesToVisit.pop();\n\n for (const spread of this.getFragmentSpreads(node)) {\n const fragName = spread.name.value;\n\n if (collectedNames[fragName] !== true) {\n collectedNames[fragName] = true;\n const fragment = this.getFragment(fragName);\n\n if (fragment) {\n fragments.push(fragment);\n nodesToVisit.push(fragment.selectionSet);\n }\n }\n }\n }\n\n this._recursivelyReferencedFragments.set(operation, fragments);\n }\n\n return fragments;\n }\n\n}\nexport class SDLValidationContext extends ASTValidationContext {\n constructor(ast, schema, onError) {\n super(ast, onError);\n this._schema = schema;\n }\n\n getSchema() {\n return this._schema;\n }\n\n}\nexport class ValidationContext extends ASTValidationContext {\n constructor(schema, ast, typeInfo, onError) {\n super(ast, onError);\n this._schema = schema;\n this._typeInfo = typeInfo;\n this._variableUsages = new Map();\n this._recursiveVariableUsages = new Map();\n }\n\n getSchema() {\n return this._schema;\n }\n\n getVariableUsages(node) {\n let usages = this._variableUsages.get(node);\n\n if (!usages) {\n const newUsages = [];\n const typeInfo = new TypeInfo(this._schema);\n visit(node, visitWithTypeInfo(typeInfo, {\n VariableDefinition: () => false,\n\n Variable(variable) {\n newUsages.push({\n node: variable,\n type: typeInfo.getInputType(),\n defaultValue: typeInfo.getDefaultValue()\n });\n }\n\n }));\n usages = newUsages;\n\n this._variableUsages.set(node, usages);\n }\n\n return usages;\n }\n\n getRecursiveVariableUsages(operation) {\n let usages = this._recursiveVariableUsages.get(operation);\n\n if (!usages) {\n usages = this.getVariableUsages(operation);\n\n for (const frag of this.getRecursivelyReferencedFragments(operation)) {\n usages = usages.concat(this.getVariableUsages(frag));\n }\n\n this._recursiveVariableUsages.set(operation, usages);\n }\n\n return usages;\n }\n\n getType() {\n return this._typeInfo.getType();\n }\n\n getParentType() {\n return this._typeInfo.getParentType();\n }\n\n getInputType() {\n return this._typeInfo.getInputType();\n }\n\n getParentInputType() {\n return this._typeInfo.getParentInputType();\n }\n\n getFieldDef() {\n return this._typeInfo.getFieldDef();\n }\n\n getDirective() {\n return this._typeInfo.getDirective();\n }\n\n getArgument() {\n return this._typeInfo.getArgument();\n }\n\n getEnumValue() {\n return this._typeInfo.getEnumValue();\n }\n\n}\n","import devAssert from \"../jsutils/devAssert.mjs\";\nimport { GraphQLError } from \"../error/GraphQLError.mjs\";\nimport { visit, visitInParallel } from \"../language/visitor.mjs\";\nimport { assertValidSchema } from \"../type/validate.mjs\";\nimport { TypeInfo, visitWithTypeInfo } from \"../utilities/TypeInfo.mjs\";\nimport { specifiedRules, specifiedSDLRules } from \"./specifiedRules.mjs\";\nimport { SDLValidationContext, ValidationContext } from \"./ValidationContext.mjs\";\n/**\n * Implements the \"Validation\" section of the spec.\n *\n * Validation runs synchronously, returning an array of encountered errors, or\n * an empty array if no errors were encountered and the document is valid.\n *\n * A list of specific validation rules may be provided. If not provided, the\n * default list of rules defined by the GraphQL specification will be used.\n *\n * Each validation rules is a function which returns a visitor\n * (see the language/visitor API). Visitor methods are expected to return\n * GraphQLErrors, or Arrays of GraphQLErrors when invalid.\n *\n * Optionally a custom TypeInfo instance may be provided. If not provided, one\n * will be created from the provided schema.\n */\n\nexport function validate(schema, documentAST, rules = specifiedRules, typeInfo = new TypeInfo(schema), options = {\n maxErrors: undefined\n}) {\n documentAST || devAssert(0, 'Must provide document.'); // If the schema used for validation is invalid, throw an error.\n\n assertValidSchema(schema);\n const abortObj = Object.freeze({});\n const errors = [];\n const context = new ValidationContext(schema, documentAST, typeInfo, error => {\n if (options.maxErrors != null && errors.length >= options.maxErrors) {\n errors.push(new GraphQLError('Too many validation errors, error limit reached. Validation aborted.'));\n throw abortObj;\n }\n\n errors.push(error);\n }); // This uses a specialized visitor which runs multiple visitors in parallel,\n // while maintaining the visitor skip and break API.\n\n const visitor = visitInParallel(rules.map(rule => rule(context))); // Visit the whole document with each instance of all provided rules.\n\n try {\n visit(documentAST, visitWithTypeInfo(typeInfo, visitor));\n } catch (e) {\n if (e !== abortObj) {\n throw e;\n }\n }\n\n return errors;\n}\n/**\n * @internal\n */\n\nexport function validateSDL(documentAST, schemaToExtend, rules = specifiedSDLRules) {\n const errors = [];\n const context = new SDLValidationContext(documentAST, schemaToExtend, error => {\n errors.push(error);\n });\n const visitors = rules.map(rule => rule(context));\n visit(documentAST, visitInParallel(visitors));\n return errors;\n}\n/**\n * Utility function which asserts a SDL document is valid by throwing an error\n * if it is invalid.\n *\n * @internal\n */\n\nexport function assertValidSDL(documentAST) {\n const errors = validateSDL(documentAST);\n\n if (errors.length !== 0) {\n throw new Error(errors.map(error => error.message).join('\\n\\n'));\n }\n}\n/**\n * Utility function which asserts a SDL document is valid by throwing an error\n * if it is invalid.\n *\n * @internal\n */\n\nexport function assertValidSDLExtension(documentAST, schema) {\n const errors = validateSDL(documentAST, schema);\n\n if (errors.length !== 0) {\n throw new Error(errors.map(error => error.message).join('\\n\\n'));\n }\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport keyMap from \"../jsutils/keyMap.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { isLeafType, isInputObjectType, isListType, isNonNullType } from \"../type/definition.mjs\";\n/**\n * Produces a JavaScript value given a GraphQL Value AST.\n *\n * A GraphQL type must be provided, which will be used to interpret different\n * GraphQL Value literals.\n *\n * Returns `undefined` when the value could not be validly coerced according to\n * the provided type.\n *\n * | GraphQL Value | JSON Value |\n * | -------------------- | ------------- |\n * | Input Object | Object |\n * | List | Array |\n * | Boolean | Boolean |\n * | String | String |\n * | Int / Float | Number |\n * | Enum Value | Mixed |\n * | NullValue | null |\n *\n */\n\nexport function valueFromAST(valueNode, type, variables) {\n if (!valueNode) {\n // When there is no node, then there is also no value.\n // Importantly, this is different from returning the value null.\n return;\n }\n\n if (valueNode.kind === Kind.VARIABLE) {\n const variableName = valueNode.name.value;\n\n if (variables == null || variables[variableName] === undefined) {\n // No valid return value.\n return;\n }\n\n const variableValue = variables[variableName];\n\n if (variableValue === null && isNonNullType(type)) {\n return; // Invalid: intentionally return no value.\n } // Note: This does no further checking that this variable is correct.\n // This assumes that this query has been validated and the variable\n // usage here is of the correct type.\n\n\n return variableValue;\n }\n\n if (isNonNullType(type)) {\n if (valueNode.kind === Kind.NULL) {\n return; // Invalid: intentionally return no value.\n }\n\n return valueFromAST(valueNode, type.ofType, variables);\n }\n\n if (valueNode.kind === Kind.NULL) {\n // This is explicitly returning the value null.\n return null;\n }\n\n if (isListType(type)) {\n const itemType = type.ofType;\n\n if (valueNode.kind === Kind.LIST) {\n const coercedValues = [];\n\n for (const itemNode of valueNode.values) {\n if (isMissingVariable(itemNode, variables)) {\n // If an array contains a missing variable, it is either coerced to\n // null or if the item type is non-null, it considered invalid.\n if (isNonNullType(itemType)) {\n return; // Invalid: intentionally return no value.\n }\n\n coercedValues.push(null);\n } else {\n const itemValue = valueFromAST(itemNode, itemType, variables);\n\n if (itemValue === undefined) {\n return; // Invalid: intentionally return no value.\n }\n\n coercedValues.push(itemValue);\n }\n }\n\n return coercedValues;\n }\n\n const coercedValue = valueFromAST(valueNode, itemType, variables);\n\n if (coercedValue === undefined) {\n return; // Invalid: intentionally return no value.\n }\n\n return [coercedValue];\n }\n\n if (isInputObjectType(type)) {\n if (valueNode.kind !== Kind.OBJECT) {\n return; // Invalid: intentionally return no value.\n }\n\n const coercedObj = Object.create(null);\n const fieldNodes = keyMap(valueNode.fields, field => field.name.value);\n\n for (const field of objectValues(type.getFields())) {\n const fieldNode = fieldNodes[field.name];\n\n if (!fieldNode || isMissingVariable(fieldNode.value, variables)) {\n if (field.defaultValue !== undefined) {\n coercedObj[field.name] = field.defaultValue;\n } else if (isNonNullType(field.type)) {\n return; // Invalid: intentionally return no value.\n }\n\n continue;\n }\n\n const fieldValue = valueFromAST(fieldNode.value, field.type, variables);\n\n if (fieldValue === undefined) {\n return; // Invalid: intentionally return no value.\n }\n\n coercedObj[field.name] = fieldValue;\n }\n\n return coercedObj;\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (isLeafType(type)) {\n // Scalars and Enums fulfill parsing a literal value via parseLiteral().\n // Invalid values represent a failure to parse correctly, in which case\n // no value is returned.\n let result;\n\n try {\n result = type.parseLiteral(valueNode, variables);\n } catch (_error) {\n return; // Invalid: intentionally return no value.\n }\n\n if (result === undefined) {\n return; // Invalid: intentionally return no value.\n }\n\n return result;\n } // istanbul ignore next (Not reachable. All possible input types have been considered)\n\n\n false || invariant(0, 'Unexpected input type: ' + inspect(type));\n} // Returns true if the provided valueNode is a variable which is not defined\n// in the set of variables.\n\nfunction isMissingVariable(valueNode, variables) {\n return valueNode.kind === Kind.VARIABLE && (variables == null || variables[valueNode.name.value] === undefined);\n}\n","import keyMap from \"../jsutils/keyMap.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport printPathArray from \"../jsutils/printPathArray.mjs\";\nimport { GraphQLError } from \"../error/GraphQLError.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { print } from \"../language/printer.mjs\";\nimport { isInputType, isNonNullType } from \"../type/definition.mjs\";\nimport { typeFromAST } from \"../utilities/typeFromAST.mjs\";\nimport { valueFromAST } from \"../utilities/valueFromAST.mjs\";\nimport { coerceInputValue } from \"../utilities/coerceInputValue.mjs\";\n\n/**\n * Prepares an object map of variableValues of the correct type based on the\n * provided variable definitions and arbitrary input. If the input cannot be\n * parsed to match the variable definitions, a GraphQLError will be thrown.\n *\n * Note: The returned value is a plain Object with a prototype, since it is\n * exposed to user code. Care should be taken to not pull values from the\n * Object prototype.\n *\n * @internal\n */\nexport function getVariableValues(schema, varDefNodes, inputs, options) {\n const errors = [];\n const maxErrors = options?.maxErrors;\n\n try {\n const coerced = coerceVariableValues(schema, varDefNodes, inputs, error => {\n if (maxErrors != null && errors.length >= maxErrors) {\n throw new GraphQLError('Too many errors processing variables, error limit reached. Execution aborted.');\n }\n\n errors.push(error);\n });\n\n if (errors.length === 0) {\n return {\n coerced\n };\n }\n } catch (error) {\n errors.push(error);\n }\n\n return {\n errors\n };\n}\n\nfunction coerceVariableValues(schema, varDefNodes, inputs, onError) {\n const coercedValues = {};\n\n for (const varDefNode of varDefNodes) {\n const varName = varDefNode.variable.name.value;\n const varType = typeFromAST(schema, varDefNode.type);\n\n if (!isInputType(varType)) {\n // Must use input types for variables. This should be caught during\n // validation, however is checked again here for safety.\n const varTypeStr = print(varDefNode.type);\n onError(new GraphQLError(`Variable \"$${varName}\" expected value of type \"${varTypeStr}\" which cannot be used as an input type.`, varDefNode.type));\n continue;\n }\n\n if (!hasOwnProperty(inputs, varName)) {\n if (varDefNode.defaultValue) {\n coercedValues[varName] = valueFromAST(varDefNode.defaultValue, varType);\n } else if (isNonNullType(varType)) {\n const varTypeStr = inspect(varType);\n onError(new GraphQLError(`Variable \"$${varName}\" of required type \"${varTypeStr}\" was not provided.`, varDefNode));\n }\n\n continue;\n }\n\n const value = inputs[varName];\n\n if (value === null && isNonNullType(varType)) {\n const varTypeStr = inspect(varType);\n onError(new GraphQLError(`Variable \"$${varName}\" of non-null type \"${varTypeStr}\" must not be null.`, varDefNode));\n continue;\n }\n\n coercedValues[varName] = coerceInputValue(value, varType, (path, invalidValue, error) => {\n let prefix = `Variable \"$${varName}\" got invalid value ` + inspect(invalidValue);\n\n if (path.length > 0) {\n prefix += ` at \"${varName}${printPathArray(path)}\"`;\n }\n\n onError(new GraphQLError(prefix + '; ' + error.message, varDefNode, undefined, undefined, undefined, error.originalError));\n });\n }\n\n return coercedValues;\n}\n/**\n * Prepares an object map of argument values given a list of argument\n * definitions and list of argument AST nodes.\n *\n * Note: The returned value is a plain Object with a prototype, since it is\n * exposed to user code. Care should be taken to not pull values from the\n * Object prototype.\n *\n * @internal\n */\n\n\nexport function getArgumentValues(def, node, variableValues) {\n const coercedValues = {}; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n\n const argumentNodes = node.arguments ?? [];\n const argNodeMap = keyMap(argumentNodes, arg => arg.name.value);\n\n for (const argDef of def.args) {\n const name = argDef.name;\n const argType = argDef.type;\n const argumentNode = argNodeMap[name];\n\n if (!argumentNode) {\n if (argDef.defaultValue !== undefined) {\n coercedValues[name] = argDef.defaultValue;\n } else if (isNonNullType(argType)) {\n throw new GraphQLError(`Argument \"${name}\" of required type \"${inspect(argType)}\" ` + 'was not provided.', node);\n }\n\n continue;\n }\n\n const valueNode = argumentNode.value;\n let isNull = valueNode.kind === Kind.NULL;\n\n if (valueNode.kind === Kind.VARIABLE) {\n const variableName = valueNode.name.value;\n\n if (variableValues == null || !hasOwnProperty(variableValues, variableName)) {\n if (argDef.defaultValue !== undefined) {\n coercedValues[name] = argDef.defaultValue;\n } else if (isNonNullType(argType)) {\n throw new GraphQLError(`Argument \"${name}\" of required type \"${inspect(argType)}\" ` + `was provided the variable \"$${variableName}\" which was not provided a runtime value.`, valueNode);\n }\n\n continue;\n }\n\n isNull = variableValues[variableName] == null;\n }\n\n if (isNull && isNonNullType(argType)) {\n throw new GraphQLError(`Argument \"${name}\" of non-null type \"${inspect(argType)}\" ` + 'must not be null.', valueNode);\n }\n\n const coercedValue = valueFromAST(valueNode, argType, variableValues);\n\n if (coercedValue === undefined) {\n // Note: ValuesOfCorrectTypeRule validation should catch this before\n // execution. This is a runtime check to ensure execution does not\n // continue with an invalid argument value.\n throw new GraphQLError(`Argument \"${name}\" has invalid value ${print(valueNode)}.`, valueNode);\n }\n\n coercedValues[name] = coercedValue;\n }\n\n return coercedValues;\n}\n/**\n * Prepares an object map of argument values given a directive definition\n * and a AST node which may contain directives. Optionally also accepts a map\n * of variable values.\n *\n * If the directive does not exist on the node, returns undefined.\n *\n * Note: The returned value is a plain Object with a prototype, since it is\n * exposed to user code. Care should be taken to not pull values from the\n * Object prototype.\n */\n\nexport function getDirectiveValues(directiveDef, node, variableValues) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const directiveNode = node.directives?.find(directive => directive.name.value === directiveDef.name);\n\n if (directiveNode) {\n return getArgumentValues(directiveDef, directiveNode, variableValues);\n }\n}\n\nfunction hasOwnProperty(obj, prop) {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport devAssert from \"../jsutils/devAssert.mjs\";\nimport keyValMap from \"../jsutils/keyValMap.mjs\";\nimport isObjectLike from \"../jsutils/isObjectLike.mjs\";\nimport { parseValue } from \"../language/parser.mjs\";\nimport { GraphQLSchema } from \"../type/schema.mjs\";\nimport { GraphQLDirective } from \"../type/directives.mjs\";\nimport { specifiedScalarTypes } from \"../type/scalars.mjs\";\nimport { introspectionTypes, TypeKind } from \"../type/introspection.mjs\";\nimport { isInputType, isOutputType, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, assertNullableType, assertObjectType, assertInterfaceType } from \"../type/definition.mjs\";\nimport { valueFromAST } from \"./valueFromAST.mjs\";\n/**\n * Build a GraphQLSchema for use by client tools.\n *\n * Given the result of a client running the introspection query, creates and\n * returns a GraphQLSchema instance which can be then used with all graphql-js\n * tools, but cannot be used to execute a query, as introspection does not\n * represent the \"resolver\", \"parse\" or \"serialize\" functions or any other\n * server-internal mechanisms.\n *\n * This function expects a complete introspection result. Don't forget to check\n * the \"errors\" field of a server response before calling this function.\n */\n\nexport function buildClientSchema(introspection, options) {\n isObjectLike(introspection) && isObjectLike(introspection.__schema) || devAssert(0, `Invalid or incomplete introspection result. Ensure that you are passing \"data\" property of introspection response and no \"errors\" was returned alongside: ${inspect(introspection)}.`); // Get the schema from the introspection result.\n\n const schemaIntrospection = introspection.__schema; // Iterate through all types, getting the type definition for each.\n\n const typeMap = keyValMap(schemaIntrospection.types, typeIntrospection => typeIntrospection.name, typeIntrospection => buildType(typeIntrospection)); // Include standard types only if they are used.\n\n for (const stdType of [...specifiedScalarTypes, ...introspectionTypes]) {\n if (typeMap[stdType.name]) {\n typeMap[stdType.name] = stdType;\n }\n } // Get the root Query, Mutation, and Subscription types.\n\n\n const queryType = schemaIntrospection.queryType ? getObjectType(schemaIntrospection.queryType) : null;\n const mutationType = schemaIntrospection.mutationType ? getObjectType(schemaIntrospection.mutationType) : null;\n const subscriptionType = schemaIntrospection.subscriptionType ? getObjectType(schemaIntrospection.subscriptionType) : null; // Get the directives supported by Introspection, assuming empty-set if\n // directives were not queried for.\n\n const directives = schemaIntrospection.directives ? schemaIntrospection.directives.map(buildDirective) : []; // Then produce and return a Schema with these types.\n\n return new GraphQLSchema({\n description: schemaIntrospection.description,\n query: queryType,\n mutation: mutationType,\n subscription: subscriptionType,\n types: objectValues(typeMap),\n directives,\n assumeValid: options?.assumeValid\n }); // Given a type reference in introspection, return the GraphQLType instance.\n // preferring cached instances before building new instances.\n\n function getType(typeRef) {\n if (typeRef.kind === TypeKind.LIST) {\n const itemRef = typeRef.ofType;\n\n if (!itemRef) {\n throw new Error('Decorated type deeper than introspection query.');\n }\n\n return new GraphQLList(getType(itemRef));\n }\n\n if (typeRef.kind === TypeKind.NON_NULL) {\n const nullableRef = typeRef.ofType;\n\n if (!nullableRef) {\n throw new Error('Decorated type deeper than introspection query.');\n }\n\n const nullableType = getType(nullableRef);\n return new GraphQLNonNull(assertNullableType(nullableType));\n }\n\n return getNamedType(typeRef);\n }\n\n function getNamedType(typeRef) {\n const typeName = typeRef.name;\n\n if (!typeName) {\n throw new Error(`Unknown type reference: ${inspect(typeRef)}.`);\n }\n\n const type = typeMap[typeName];\n\n if (!type) {\n throw new Error(`Invalid or incomplete schema, unknown type: ${typeName}. Ensure that a full introspection query is used in order to build a client schema.`);\n }\n\n return type;\n }\n\n function getObjectType(typeRef) {\n return assertObjectType(getNamedType(typeRef));\n }\n\n function getInterfaceType(typeRef) {\n return assertInterfaceType(getNamedType(typeRef));\n } // Given a type's introspection result, construct the correct\n // GraphQLType instance.\n\n\n function buildType(type) {\n if (type != null && type.name != null && type.kind != null) {\n switch (type.kind) {\n case TypeKind.SCALAR:\n return buildScalarDef(type);\n\n case TypeKind.OBJECT:\n return buildObjectDef(type);\n\n case TypeKind.INTERFACE:\n return buildInterfaceDef(type);\n\n case TypeKind.UNION:\n return buildUnionDef(type);\n\n case TypeKind.ENUM:\n return buildEnumDef(type);\n\n case TypeKind.INPUT_OBJECT:\n return buildInputObjectDef(type);\n }\n }\n\n const typeStr = inspect(type);\n throw new Error(`Invalid or incomplete introspection result. Ensure that a full introspection query is used in order to build a client schema: ${typeStr}.`);\n }\n\n function buildScalarDef(scalarIntrospection) {\n return new GraphQLScalarType({\n name: scalarIntrospection.name,\n description: scalarIntrospection.description,\n specifiedByUrl: scalarIntrospection.specifiedByUrl\n });\n }\n\n function buildImplementationsList(implementingIntrospection) {\n // TODO: Temporary workaround until GraphQL ecosystem will fully support\n // 'interfaces' on interface types.\n if (implementingIntrospection.interfaces === null && implementingIntrospection.kind === TypeKind.INTERFACE) {\n return [];\n }\n\n if (!implementingIntrospection.interfaces) {\n const implementingIntrospectionStr = inspect(implementingIntrospection);\n throw new Error(`Introspection result missing interfaces: ${implementingIntrospectionStr}.`);\n }\n\n return implementingIntrospection.interfaces.map(getInterfaceType);\n }\n\n function buildObjectDef(objectIntrospection) {\n return new GraphQLObjectType({\n name: objectIntrospection.name,\n description: objectIntrospection.description,\n interfaces: () => buildImplementationsList(objectIntrospection),\n fields: () => buildFieldDefMap(objectIntrospection)\n });\n }\n\n function buildInterfaceDef(interfaceIntrospection) {\n return new GraphQLInterfaceType({\n name: interfaceIntrospection.name,\n description: interfaceIntrospection.description,\n interfaces: () => buildImplementationsList(interfaceIntrospection),\n fields: () => buildFieldDefMap(interfaceIntrospection)\n });\n }\n\n function buildUnionDef(unionIntrospection) {\n if (!unionIntrospection.possibleTypes) {\n const unionIntrospectionStr = inspect(unionIntrospection);\n throw new Error(`Introspection result missing possibleTypes: ${unionIntrospectionStr}.`);\n }\n\n return new GraphQLUnionType({\n name: unionIntrospection.name,\n description: unionIntrospection.description,\n types: () => unionIntrospection.possibleTypes.map(getObjectType)\n });\n }\n\n function buildEnumDef(enumIntrospection) {\n if (!enumIntrospection.enumValues) {\n const enumIntrospectionStr = inspect(enumIntrospection);\n throw new Error(`Introspection result missing enumValues: ${enumIntrospectionStr}.`);\n }\n\n return new GraphQLEnumType({\n name: enumIntrospection.name,\n description: enumIntrospection.description,\n values: keyValMap(enumIntrospection.enumValues, valueIntrospection => valueIntrospection.name, valueIntrospection => ({\n description: valueIntrospection.description,\n deprecationReason: valueIntrospection.deprecationReason\n }))\n });\n }\n\n function buildInputObjectDef(inputObjectIntrospection) {\n if (!inputObjectIntrospection.inputFields) {\n const inputObjectIntrospectionStr = inspect(inputObjectIntrospection);\n throw new Error(`Introspection result missing inputFields: ${inputObjectIntrospectionStr}.`);\n }\n\n return new GraphQLInputObjectType({\n name: inputObjectIntrospection.name,\n description: inputObjectIntrospection.description,\n fields: () => buildInputValueDefMap(inputObjectIntrospection.inputFields)\n });\n }\n\n function buildFieldDefMap(typeIntrospection) {\n if (!typeIntrospection.fields) {\n throw new Error(`Introspection result missing fields: ${inspect(typeIntrospection)}.`);\n }\n\n return keyValMap(typeIntrospection.fields, fieldIntrospection => fieldIntrospection.name, buildField);\n }\n\n function buildField(fieldIntrospection) {\n const type = getType(fieldIntrospection.type);\n\n if (!isOutputType(type)) {\n const typeStr = inspect(type);\n throw new Error(`Introspection must provide output type for fields, but received: ${typeStr}.`);\n }\n\n if (!fieldIntrospection.args) {\n const fieldIntrospectionStr = inspect(fieldIntrospection);\n throw new Error(`Introspection result missing field args: ${fieldIntrospectionStr}.`);\n }\n\n return {\n description: fieldIntrospection.description,\n deprecationReason: fieldIntrospection.deprecationReason,\n type,\n args: buildInputValueDefMap(fieldIntrospection.args)\n };\n }\n\n function buildInputValueDefMap(inputValueIntrospections) {\n return keyValMap(inputValueIntrospections, inputValue => inputValue.name, buildInputValue);\n }\n\n function buildInputValue(inputValueIntrospection) {\n const type = getType(inputValueIntrospection.type);\n\n if (!isInputType(type)) {\n const typeStr = inspect(type);\n throw new Error(`Introspection must provide input type for arguments, but received: ${typeStr}.`);\n }\n\n const defaultValue = inputValueIntrospection.defaultValue != null ? valueFromAST(parseValue(inputValueIntrospection.defaultValue), type) : undefined;\n return {\n description: inputValueIntrospection.description,\n type,\n defaultValue,\n deprecationReason: inputValueIntrospection.deprecationReason\n };\n }\n\n function buildDirective(directiveIntrospection) {\n if (!directiveIntrospection.args) {\n const directiveIntrospectionStr = inspect(directiveIntrospection);\n throw new Error(`Introspection result missing directive args: ${directiveIntrospectionStr}.`);\n }\n\n if (!directiveIntrospection.locations) {\n const directiveIntrospectionStr = inspect(directiveIntrospection);\n throw new Error(`Introspection result missing directive locations: ${directiveIntrospectionStr}.`);\n }\n\n return new GraphQLDirective({\n name: directiveIntrospection.name,\n description: directiveIntrospection.description,\n isRepeatable: directiveIntrospection.isRepeatable,\n locations: directiveIntrospection.locations.slice(),\n args: buildInputValueDefMap(directiveIntrospection.args)\n });\n }\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport keyMap from \"../jsutils/keyMap.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport mapValue from \"../jsutils/mapValue.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport devAssert from \"../jsutils/devAssert.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { isTypeDefinitionNode, isTypeExtensionNode } from \"../language/predicates.mjs\";\nimport { assertValidSDLExtension } from \"../validation/validate.mjs\";\nimport { getDirectiveValues } from \"../execution/values.mjs\";\nimport { assertSchema, GraphQLSchema } from \"../type/schema.mjs\";\nimport { specifiedScalarTypes, isSpecifiedScalarType } from \"../type/scalars.mjs\";\nimport { introspectionTypes, isIntrospectionType } from \"../type/introspection.mjs\";\nimport { GraphQLDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective } from \"../type/directives.mjs\";\nimport { isScalarType, isObjectType, isInterfaceType, isUnionType, isListType, isNonNullType, isEnumType, isInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType } from \"../type/definition.mjs\";\nimport { valueFromAST } from \"./valueFromAST.mjs\";\n\n/**\n * Produces a new schema given an existing schema and a document which may\n * contain GraphQL type extensions and definitions. The original schema will\n * remain unaltered.\n *\n * Because a schema represents a graph of references, a schema cannot be\n * extended without effectively making an entire copy. We do not know until it's\n * too late if subgraphs remain unchanged.\n *\n * This algorithm copies the provided schema, applying extensions while\n * producing the copy. The original schema remains unaltered.\n */\nexport function extendSchema(schema, documentAST, options) {\n assertSchema(schema);\n documentAST != null && documentAST.kind === Kind.DOCUMENT || devAssert(0, 'Must provide valid Document AST.');\n\n if (options?.assumeValid !== true && options?.assumeValidSDL !== true) {\n assertValidSDLExtension(documentAST, schema);\n }\n\n const schemaConfig = schema.toConfig();\n const extendedConfig = extendSchemaImpl(schemaConfig, documentAST, options);\n return schemaConfig === extendedConfig ? schema : new GraphQLSchema(extendedConfig);\n}\n/**\n * @internal\n */\n\nexport function extendSchemaImpl(schemaConfig, documentAST, options) {\n // Collect the type definitions and extensions found in the document.\n const typeDefs = [];\n const typeExtensionsMap = Object.create(null); // New directives and types are separate because a directives and types can\n // have the same name. For example, a type named \"skip\".\n\n const directiveDefs = [];\n let schemaDef; // Schema extensions are collected which may add additional operation types.\n\n const schemaExtensions = [];\n\n for (const def of documentAST.definitions) {\n if (def.kind === Kind.SCHEMA_DEFINITION) {\n schemaDef = def;\n } else if (def.kind === Kind.SCHEMA_EXTENSION) {\n schemaExtensions.push(def);\n } else if (isTypeDefinitionNode(def)) {\n typeDefs.push(def);\n } else if (isTypeExtensionNode(def)) {\n const extendedTypeName = def.name.value;\n const existingTypeExtensions = typeExtensionsMap[extendedTypeName];\n typeExtensionsMap[extendedTypeName] = existingTypeExtensions ? existingTypeExtensions.concat([def]) : [def];\n } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {\n directiveDefs.push(def);\n }\n } // If this document contains no new types, extensions, or directives then\n // return the same unmodified GraphQLSchema instance.\n\n\n if (Object.keys(typeExtensionsMap).length === 0 && typeDefs.length === 0 && directiveDefs.length === 0 && schemaExtensions.length === 0 && schemaDef == null) {\n return schemaConfig;\n }\n\n const typeMap = Object.create(null);\n\n for (const existingType of schemaConfig.types) {\n typeMap[existingType.name] = extendNamedType(existingType);\n }\n\n for (const typeNode of typeDefs) {\n const name = typeNode.name.value;\n typeMap[name] = stdTypeMap[name] ?? buildType(typeNode);\n }\n\n const operationTypes = {\n // Get the extended root operation types.\n query: schemaConfig.query && replaceNamedType(schemaConfig.query),\n mutation: schemaConfig.mutation && replaceNamedType(schemaConfig.mutation),\n subscription: schemaConfig.subscription && replaceNamedType(schemaConfig.subscription),\n // Then, incorporate schema definition and all schema extensions.\n ...(schemaDef && getOperationTypes([schemaDef])),\n ...getOperationTypes(schemaExtensions)\n }; // Then produce and return a Schema config with these types.\n\n return {\n description: schemaDef?.description?.value,\n ...operationTypes,\n types: objectValues(typeMap),\n directives: [...schemaConfig.directives.map(replaceDirective), ...directiveDefs.map(buildDirective)],\n extensions: undefined,\n astNode: schemaDef ?? schemaConfig.astNode,\n extensionASTNodes: schemaConfig.extensionASTNodes.concat(schemaExtensions),\n assumeValid: options?.assumeValid ?? false\n }; // Below are functions used for producing this schema that have closed over\n // this scope and have access to the schema, cache, and newly defined types.\n\n function replaceType(type) {\n if (isListType(type)) {\n // $FlowFixMe[incompatible-return]\n return new GraphQLList(replaceType(type.ofType));\n }\n\n if (isNonNullType(type)) {\n // $FlowFixMe[incompatible-return]\n return new GraphQLNonNull(replaceType(type.ofType));\n }\n\n return replaceNamedType(type);\n }\n\n function replaceNamedType(type) {\n // Note: While this could make early assertions to get the correctly\n // typed values, that would throw immediately while type system\n // validation with validateSchema() will produce more actionable results.\n return typeMap[type.name];\n }\n\n function replaceDirective(directive) {\n const config = directive.toConfig();\n return new GraphQLDirective({ ...config,\n args: mapValue(config.args, extendArg)\n });\n }\n\n function extendNamedType(type) {\n if (isIntrospectionType(type) || isSpecifiedScalarType(type)) {\n // Builtin types are not extended.\n return type;\n }\n\n if (isScalarType(type)) {\n return extendScalarType(type);\n }\n\n if (isObjectType(type)) {\n return extendObjectType(type);\n }\n\n if (isInterfaceType(type)) {\n return extendInterfaceType(type);\n }\n\n if (isUnionType(type)) {\n return extendUnionType(type);\n }\n\n if (isEnumType(type)) {\n return extendEnumType(type);\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (isInputObjectType(type)) {\n return extendInputObjectType(type);\n } // istanbul ignore next (Not reachable. All possible types have been considered)\n\n\n false || invariant(0, 'Unexpected type: ' + inspect(type));\n }\n\n function extendInputObjectType(type) {\n const config = type.toConfig();\n const extensions = typeExtensionsMap[config.name] ?? [];\n return new GraphQLInputObjectType({ ...config,\n fields: () => ({ ...mapValue(config.fields, field => ({ ...field,\n type: replaceType(field.type)\n })),\n ...buildInputFieldMap(extensions)\n }),\n extensionASTNodes: config.extensionASTNodes.concat(extensions)\n });\n }\n\n function extendEnumType(type) {\n const config = type.toConfig();\n const extensions = typeExtensionsMap[type.name] ?? [];\n return new GraphQLEnumType({ ...config,\n values: { ...config.values,\n ...buildEnumValueMap(extensions)\n },\n extensionASTNodes: config.extensionASTNodes.concat(extensions)\n });\n }\n\n function extendScalarType(type) {\n const config = type.toConfig();\n const extensions = typeExtensionsMap[config.name] ?? [];\n let specifiedByUrl = config.specifiedByUrl;\n\n for (const extensionNode of extensions) {\n specifiedByUrl = getSpecifiedByUrl(extensionNode) ?? specifiedByUrl;\n }\n\n return new GraphQLScalarType({ ...config,\n specifiedByUrl,\n extensionASTNodes: config.extensionASTNodes.concat(extensions)\n });\n }\n\n function extendObjectType(type) {\n const config = type.toConfig();\n const extensions = typeExtensionsMap[config.name] ?? [];\n return new GraphQLObjectType({ ...config,\n interfaces: () => [...type.getInterfaces().map(replaceNamedType), ...buildInterfaces(extensions)],\n fields: () => ({ ...mapValue(config.fields, extendField),\n ...buildFieldMap(extensions)\n }),\n extensionASTNodes: config.extensionASTNodes.concat(extensions)\n });\n }\n\n function extendInterfaceType(type) {\n const config = type.toConfig();\n const extensions = typeExtensionsMap[config.name] ?? [];\n return new GraphQLInterfaceType({ ...config,\n interfaces: () => [...type.getInterfaces().map(replaceNamedType), ...buildInterfaces(extensions)],\n fields: () => ({ ...mapValue(config.fields, extendField),\n ...buildFieldMap(extensions)\n }),\n extensionASTNodes: config.extensionASTNodes.concat(extensions)\n });\n }\n\n function extendUnionType(type) {\n const config = type.toConfig();\n const extensions = typeExtensionsMap[config.name] ?? [];\n return new GraphQLUnionType({ ...config,\n types: () => [...type.getTypes().map(replaceNamedType), ...buildUnionTypes(extensions)],\n extensionASTNodes: config.extensionASTNodes.concat(extensions)\n });\n }\n\n function extendField(field) {\n return { ...field,\n type: replaceType(field.type),\n // $FlowFixMe[incompatible-call]\n args: mapValue(field.args, extendArg)\n };\n }\n\n function extendArg(arg) {\n return { ...arg,\n type: replaceType(arg.type)\n };\n }\n\n function getOperationTypes(nodes) {\n const opTypes = {};\n\n for (const node of nodes) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const operationTypesNodes = node.operationTypes ?? [];\n\n for (const operationType of operationTypesNodes) {\n opTypes[operationType.operation] = getNamedType(operationType.type);\n }\n } // Note: While this could make early assertions to get the correctly\n // typed values below, that would throw immediately while type system\n // validation with validateSchema() will produce more actionable results.\n\n\n return opTypes;\n }\n\n function getNamedType(node) {\n const name = node.name.value;\n const type = stdTypeMap[name] ?? typeMap[name];\n\n if (type === undefined) {\n throw new Error(`Unknown type: \"${name}\".`);\n }\n\n return type;\n }\n\n function getWrappedType(node) {\n if (node.kind === Kind.LIST_TYPE) {\n return new GraphQLList(getWrappedType(node.type));\n }\n\n if (node.kind === Kind.NON_NULL_TYPE) {\n // $FlowFixMe[incompatible-call]\n return new GraphQLNonNull(getWrappedType(node.type));\n }\n\n return getNamedType(node);\n }\n\n function buildDirective(node) {\n const locations = node.locations.map(({\n value\n }) => value);\n return new GraphQLDirective({\n name: node.name.value,\n description: node.description?.value,\n locations,\n isRepeatable: node.repeatable,\n args: buildArgumentMap(node.arguments),\n astNode: node\n });\n }\n\n function buildFieldMap(nodes) {\n const fieldConfigMap = Object.create(null);\n\n for (const node of nodes) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const nodeFields = node.fields ?? [];\n\n for (const field of nodeFields) {\n fieldConfigMap[field.name.value] = {\n // Note: While this could make assertions to get the correctly typed\n // value, that would throw immediately while type system validation\n // with validateSchema() will produce more actionable results.\n type: getWrappedType(field.type),\n description: field.description?.value,\n args: buildArgumentMap(field.arguments),\n deprecationReason: getDeprecationReason(field),\n astNode: field\n };\n }\n }\n\n return fieldConfigMap;\n }\n\n function buildArgumentMap(args) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const argsNodes = args ?? [];\n const argConfigMap = Object.create(null);\n\n for (const arg of argsNodes) {\n // Note: While this could make assertions to get the correctly typed\n // value, that would throw immediately while type system validation\n // with validateSchema() will produce more actionable results.\n const type = getWrappedType(arg.type);\n argConfigMap[arg.name.value] = {\n type,\n description: arg.description?.value,\n defaultValue: valueFromAST(arg.defaultValue, type),\n deprecationReason: getDeprecationReason(arg),\n astNode: arg\n };\n }\n\n return argConfigMap;\n }\n\n function buildInputFieldMap(nodes) {\n const inputFieldMap = Object.create(null);\n\n for (const node of nodes) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const fieldsNodes = node.fields ?? [];\n\n for (const field of fieldsNodes) {\n // Note: While this could make assertions to get the correctly typed\n // value, that would throw immediately while type system validation\n // with validateSchema() will produce more actionable results.\n const type = getWrappedType(field.type);\n inputFieldMap[field.name.value] = {\n type,\n description: field.description?.value,\n defaultValue: valueFromAST(field.defaultValue, type),\n deprecationReason: getDeprecationReason(field),\n astNode: field\n };\n }\n }\n\n return inputFieldMap;\n }\n\n function buildEnumValueMap(nodes) {\n const enumValueMap = Object.create(null);\n\n for (const node of nodes) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const valuesNodes = node.values ?? [];\n\n for (const value of valuesNodes) {\n enumValueMap[value.name.value] = {\n description: value.description?.value,\n deprecationReason: getDeprecationReason(value),\n astNode: value\n };\n }\n }\n\n return enumValueMap;\n }\n\n function buildInterfaces(nodes) {\n const interfaces = [];\n\n for (const node of nodes) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const interfacesNodes = node.interfaces ?? [];\n\n for (const type of interfacesNodes) {\n // Note: While this could make assertions to get the correctly typed\n // values below, that would throw immediately while type system\n // validation with validateSchema() will produce more actionable\n // results.\n interfaces.push(getNamedType(type));\n }\n }\n\n return interfaces;\n }\n\n function buildUnionTypes(nodes) {\n const types = [];\n\n for (const node of nodes) {\n // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')\n const typeNodes = node.types ?? [];\n\n for (const type of typeNodes) {\n // Note: While this could make assertions to get the correctly typed\n // values below, that would throw immediately while type system\n // validation with validateSchema() will produce more actionable\n // results.\n types.push(getNamedType(type));\n }\n }\n\n return types;\n }\n\n function buildType(astNode) {\n const name = astNode.name.value;\n const extensionNodes = typeExtensionsMap[name] ?? [];\n\n switch (astNode.kind) {\n case Kind.OBJECT_TYPE_DEFINITION:\n {\n const extensionASTNodes = extensionNodes;\n const allNodes = [astNode, ...extensionASTNodes];\n return new GraphQLObjectType({\n name,\n description: astNode.description?.value,\n interfaces: () => buildInterfaces(allNodes),\n fields: () => buildFieldMap(allNodes),\n astNode,\n extensionASTNodes\n });\n }\n\n case Kind.INTERFACE_TYPE_DEFINITION:\n {\n const extensionASTNodes = extensionNodes;\n const allNodes = [astNode, ...extensionASTNodes];\n return new GraphQLInterfaceType({\n name,\n description: astNode.description?.value,\n interfaces: () => buildInterfaces(allNodes),\n fields: () => buildFieldMap(allNodes),\n astNode,\n extensionASTNodes\n });\n }\n\n case Kind.ENUM_TYPE_DEFINITION:\n {\n const extensionASTNodes = extensionNodes;\n const allNodes = [astNode, ...extensionASTNodes];\n return new GraphQLEnumType({\n name,\n description: astNode.description?.value,\n values: buildEnumValueMap(allNodes),\n astNode,\n extensionASTNodes\n });\n }\n\n case Kind.UNION_TYPE_DEFINITION:\n {\n const extensionASTNodes = extensionNodes;\n const allNodes = [astNode, ...extensionASTNodes];\n return new GraphQLUnionType({\n name,\n description: astNode.description?.value,\n types: () => buildUnionTypes(allNodes),\n astNode,\n extensionASTNodes\n });\n }\n\n case Kind.SCALAR_TYPE_DEFINITION:\n {\n const extensionASTNodes = extensionNodes;\n return new GraphQLScalarType({\n name,\n description: astNode.description?.value,\n specifiedByUrl: getSpecifiedByUrl(astNode),\n astNode,\n extensionASTNodes\n });\n }\n\n case Kind.INPUT_OBJECT_TYPE_DEFINITION:\n {\n const extensionASTNodes = extensionNodes;\n const allNodes = [astNode, ...extensionASTNodes];\n return new GraphQLInputObjectType({\n name,\n description: astNode.description?.value,\n fields: () => buildInputFieldMap(allNodes),\n astNode,\n extensionASTNodes\n });\n }\n } // istanbul ignore next (Not reachable. All possible type definition nodes have been considered)\n\n\n false || invariant(0, 'Unexpected type definition node: ' + inspect(astNode));\n }\n}\nconst stdTypeMap = keyMap(specifiedScalarTypes.concat(introspectionTypes), type => type.name);\n/**\n * Given a field or enum value node, returns the string value for the\n * deprecation reason.\n */\n\nfunction getDeprecationReason(node) {\n const deprecated = getDirectiveValues(GraphQLDeprecatedDirective, node);\n return deprecated?.reason;\n}\n/**\n * Given a scalar node, returns the string value for the specifiedByUrl.\n */\n\n\nfunction getSpecifiedByUrl(node) {\n const specifiedBy = getDirectiveValues(GraphQLSpecifiedByDirective, node);\n return specifiedBy?.url;\n}\n","import devAssert from \"../jsutils/devAssert.mjs\";\nimport { Kind } from \"../language/kinds.mjs\";\nimport { parse } from \"../language/parser.mjs\";\nimport { assertValidSDL } from \"../validation/validate.mjs\";\nimport { GraphQLSchema } from \"../type/schema.mjs\";\nimport { specifiedDirectives } from \"../type/directives.mjs\";\nimport { extendSchemaImpl } from \"./extendSchema.mjs\";\n\n/**\n * This takes the ast of a schema document produced by the parse function in\n * src/language/parser.js.\n *\n * If no schema definition is provided, then it will look for types named Query\n * and Mutation.\n *\n * Given that AST it constructs a GraphQLSchema. The resulting schema\n * has no resolve methods, so execution will use default resolvers.\n */\nexport function buildASTSchema(documentAST, options) {\n documentAST != null && documentAST.kind === Kind.DOCUMENT || devAssert(0, 'Must provide valid Document AST.');\n\n if (options?.assumeValid !== true && options?.assumeValidSDL !== true) {\n assertValidSDL(documentAST);\n }\n\n const emptySchemaConfig = {\n description: undefined,\n types: [],\n directives: [],\n extensions: undefined,\n extensionASTNodes: [],\n assumeValid: false\n };\n const config = extendSchemaImpl(emptySchemaConfig, documentAST, options);\n\n if (config.astNode == null) {\n for (const type of config.types) {\n switch (type.name) {\n // Note: While this could make early assertions to get the correctly\n // typed values below, that would throw immediately while type system\n // validation with validateSchema() will produce more actionable results.\n case 'Query':\n config.query = type;\n break;\n\n case 'Mutation':\n config.mutation = type;\n break;\n\n case 'Subscription':\n config.subscription = type;\n break;\n }\n }\n }\n\n const {\n directives\n } = config; // If specified directives were not explicitly declared, add them.\n\n for (const stdDirective of specifiedDirectives) {\n if (directives.every(directive => directive.name !== stdDirective.name)) {\n directives.push(stdDirective);\n }\n }\n\n return new GraphQLSchema(config);\n}\n/**\n * A helper function to build a GraphQLSchema directly from a source\n * document.\n */\n\nexport function buildSchema(source, options) {\n const document = parse(source, {\n noLocation: options?.noLocation,\n experimentalFragmentVariables: options?.experimentalFragmentVariables\n });\n return buildASTSchema(document, {\n assumeValidSDL: options?.assumeValidSDL,\n assumeValid: options?.assumeValid\n });\n}\n","import objectValues from \"../polyfills/objectValues.mjs\";\nimport inspect from \"../jsutils/inspect.mjs\";\nimport invariant from \"../jsutils/invariant.mjs\";\nimport { print } from \"../language/printer.mjs\";\nimport { printBlockString } from \"../language/blockString.mjs\";\nimport { isIntrospectionType } from \"../type/introspection.mjs\";\nimport { GraphQLString, isSpecifiedScalarType } from \"../type/scalars.mjs\";\nimport { DEFAULT_DEPRECATION_REASON, isSpecifiedDirective } from \"../type/directives.mjs\";\nimport { isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType } from \"../type/definition.mjs\";\nimport { astFromValue } from \"./astFromValue.mjs\";\nexport function printSchema(schema) {\n return printFilteredSchema(schema, n => !isSpecifiedDirective(n), isDefinedType);\n}\nexport function printIntrospectionSchema(schema) {\n return printFilteredSchema(schema, isSpecifiedDirective, isIntrospectionType);\n}\n\nfunction isDefinedType(type) {\n return !isSpecifiedScalarType(type) && !isIntrospectionType(type);\n}\n\nfunction printFilteredSchema(schema, directiveFilter, typeFilter) {\n const directives = schema.getDirectives().filter(directiveFilter);\n const types = objectValues(schema.getTypeMap()).filter(typeFilter);\n return [printSchemaDefinition(schema)].concat(directives.map(directive => printDirective(directive)), types.map(type => printType(type))).filter(Boolean).join('\\n\\n') + '\\n';\n}\n\nfunction printSchemaDefinition(schema) {\n if (schema.description == null && isSchemaOfCommonNames(schema)) {\n return;\n }\n\n const operationTypes = [];\n const queryType = schema.getQueryType();\n\n if (queryType) {\n operationTypes.push(` query: ${queryType.name}`);\n }\n\n const mutationType = schema.getMutationType();\n\n if (mutationType) {\n operationTypes.push(` mutation: ${mutationType.name}`);\n }\n\n const subscriptionType = schema.getSubscriptionType();\n\n if (subscriptionType) {\n operationTypes.push(` subscription: ${subscriptionType.name}`);\n }\n\n return printDescription(schema) + `schema {\\n${operationTypes.join('\\n')}\\n}`;\n}\n/**\n * GraphQL schema define root types for each type of operation. These types are\n * the same as any other type and can be named in any manner, however there is\n * a common naming convention:\n *\n * schema {\n * query: Query\n * mutation: Mutation\n * }\n *\n * When using this naming convention, the schema description can be omitted.\n */\n\n\nfunction isSchemaOfCommonNames(schema) {\n const queryType = schema.getQueryType();\n\n if (queryType && queryType.name !== 'Query') {\n return false;\n }\n\n const mutationType = schema.getMutationType();\n\n if (mutationType && mutationType.name !== 'Mutation') {\n return false;\n }\n\n const subscriptionType = schema.getSubscriptionType();\n\n if (subscriptionType && subscriptionType.name !== 'Subscription') {\n return false;\n }\n\n return true;\n}\n\nexport function printType(type) {\n if (isScalarType(type)) {\n return printScalar(type);\n }\n\n if (isObjectType(type)) {\n return printObject(type);\n }\n\n if (isInterfaceType(type)) {\n return printInterface(type);\n }\n\n if (isUnionType(type)) {\n return printUnion(type);\n }\n\n if (isEnumType(type)) {\n return printEnum(type);\n } // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')\n\n\n if (isInputObjectType(type)) {\n return printInputObject(type);\n } // istanbul ignore next (Not reachable. All possible types have been considered)\n\n\n false || invariant(0, 'Unexpected type: ' + inspect(type));\n}\n\nfunction printScalar(type) {\n return printDescription(type) + `scalar ${type.name}` + printSpecifiedByUrl(type);\n}\n\nfunction printImplementedInterfaces(type) {\n const interfaces = type.getInterfaces();\n return interfaces.length ? ' implements ' + interfaces.map(i => i.name).join(' & ') : '';\n}\n\nfunction printObject(type) {\n return printDescription(type) + `type ${type.name}` + printImplementedInterfaces(type) + printFields(type);\n}\n\nfunction printInterface(type) {\n return printDescription(type) + `interface ${type.name}` + printImplementedInterfaces(type) + printFields(type);\n}\n\nfunction printUnion(type) {\n const types = type.getTypes();\n const possibleTypes = types.length ? ' = ' + types.join(' | ') : '';\n return printDescription(type) + 'union ' + type.name + possibleTypes;\n}\n\nfunction printEnum(type) {\n const values = type.getValues().map((value, i) => printDescription(value, ' ', !i) + ' ' + value.name + printDeprecated(value.deprecationReason));\n return printDescription(type) + `enum ${type.name}` + printBlock(values);\n}\n\nfunction printInputObject(type) {\n const fields = objectValues(type.getFields()).map((f, i) => printDescription(f, ' ', !i) + ' ' + printInputValue(f));\n return printDescription(type) + `input ${type.name}` + printBlock(fields);\n}\n\nfunction printFields(type) {\n const fields = objectValues(type.getFields()).map((f, i) => printDescription(f, ' ', !i) + ' ' + f.name + printArgs(f.args, ' ') + ': ' + String(f.type) + printDeprecated(f.deprecationReason));\n return printBlock(fields);\n}\n\nfunction printBlock(items) {\n return items.length !== 0 ? ' {\\n' + items.join('\\n') + '\\n}' : '';\n}\n\nfunction printArgs(args, indentation = '') {\n if (args.length === 0) {\n return '';\n } // If every arg does not have a description, print them on one line.\n\n\n if (args.every(arg => !arg.description)) {\n return '(' + args.map(printInputValue).join(', ') + ')';\n }\n\n return '(\\n' + args.map((arg, i) => printDescription(arg, ' ' + indentation, !i) + ' ' + indentation + printInputValue(arg)).join('\\n') + '\\n' + indentation + ')';\n}\n\nfunction printInputValue(arg) {\n const defaultAST = astFromValue(arg.defaultValue, arg.type);\n let argDecl = arg.name + ': ' + String(arg.type);\n\n if (defaultAST) {\n argDecl += ` = ${print(defaultAST)}`;\n }\n\n return argDecl + printDeprecated(arg.deprecationReason);\n}\n\nfunction printDirective(directive) {\n return printDescription(directive) + 'directive @' + directive.name + printArgs(directive.args) + (directive.isRepeatable ? ' repeatable' : '') + ' on ' + directive.locations.join(' | ');\n}\n\nfunction printDeprecated(reason) {\n if (reason == null) {\n return '';\n }\n\n const reasonAST = astFromValue(reason, GraphQLString);\n\n if (reasonAST && reason !== DEFAULT_DEPRECATION_REASON) {\n return ' @deprecated(reason: ' + print(reasonAST) + ')';\n }\n\n return ' @deprecated';\n}\n\nfunction printSpecifiedByUrl(scalar) {\n if (scalar.specifiedByUrl == null) {\n return '';\n }\n\n const url = scalar.specifiedByUrl;\n const urlAST = astFromValue(url, GraphQLString);\n urlAST || invariant(0, 'Unexpected null value returned from `astFromValue` for specifiedByUrl');\n return ' @specifiedBy(url: ' + print(urlAST) + ')';\n}\n\nfunction printDescription(def, indentation = '', firstInBlock = true) {\n const {\n description\n } = def;\n\n if (description == null) {\n return '';\n }\n\n const preferMultipleLines = description.length > 70;\n const blockString = printBlockString(description, '', preferMultipleLines);\n const prefix = indentation && !firstInBlock ? '\\n' + indentation : indentation;\n return prefix + blockString.replace(/\\n/g, '\\n' + indentation) + '\\n';\n}\n",null,null,null,null,null,"import { GraphQLError } from \"../error/GraphQLError.mjs\";\n\n/**\n * Extracts the root type of the operation from the schema.\n */\nexport function getOperationRootType(schema, operation) {\n if (operation.operation === 'query') {\n const queryType = schema.getQueryType();\n\n if (!queryType) {\n throw new GraphQLError('Schema does not define the required query root type.', operation);\n }\n\n return queryType;\n }\n\n if (operation.operation === 'mutation') {\n const mutationType = schema.getMutationType();\n\n if (!mutationType) {\n throw new GraphQLError('Schema is not configured for mutations.', operation);\n }\n\n return mutationType;\n }\n\n if (operation.operation === 'subscription') {\n const subscriptionType = schema.getSubscriptionType();\n\n if (!subscriptionType) {\n throw new GraphQLError('Schema is not configured for subscriptions.', operation);\n }\n\n return subscriptionType;\n }\n\n throw new GraphQLError('Can only have query, mutation and subscription operations.', operation);\n}\n",null,"/**\n * Provided a collection of ASTs, presumably each from different files,\n * concatenate the ASTs together into batched AST, useful for validating many\n * GraphQL source files which together represent one conceptual application.\n */\nexport function concatAST(documents) {\n let definitions = [];\n\n for (const doc of documents) {\n definitions = definitions.concat(doc.definitions);\n }\n\n return {\n kind: 'Document',\n definitions\n };\n}\n"],"names":["isObjectLike","value","getLocation","source","position","lineRegexp","match","line","column","exec","body","index","length","printLocation","location","printSourceLocation","start","sourceLocation","firstLineColumnOffset","locationOffset","whitespace","lineIndex","lineOffset","lineNum","columnOffset","columnNum","locationStr","name","lines","split","locationLine","subLineIndex","Math","floor","subLineColumnNum","subLines","i","push","slice","printPrefixedLines","map","subLine","existingLines","filter","_","undefined","padLen","max","prefix","leftPad","str","join","len","Array","GraphQLError","Error","constructor","message","nodes","positions","path","originalError","extensions","super","_nodes","isArray","_source","loc","_locations","_positions","reduce","list","node","pos","_extensions","originalExtensions","Object","defineProperties","this","enumerable","writable","locations","stack","defineProperty","configurable","captureStackTrace","toString","error","output","printError","get","Symbol","toStringTag","syntaxError","description","Kind","freeze","NAME","DOCUMENT","OPERATION_DEFINITION","VARIABLE_DEFINITION","SELECTION_SET","FIELD","ARGUMENT","FRAGMENT_SPREAD","INLINE_FRAGMENT","FRAGMENT_DEFINITION","VARIABLE","INT","FLOAT","STRING","BOOLEAN","NULL","ENUM","LIST","OBJECT","OBJECT_FIELD","DIRECTIVE","NAMED_TYPE","LIST_TYPE","NON_NULL_TYPE","SCHEMA_DEFINITION","OPERATION_TYPE_DEFINITION","SCALAR_TYPE_DEFINITION","OBJECT_TYPE_DEFINITION","FIELD_DEFINITION","INPUT_VALUE_DEFINITION","INTERFACE_TYPE_DEFINITION","UNION_TYPE_DEFINITION","ENUM_TYPE_DEFINITION","ENUM_VALUE_DEFINITION","INPUT_OBJECT_TYPE_DEFINITION","DIRECTIVE_DEFINITION","SCHEMA_EXTENSION","SCALAR_TYPE_EXTENSION","OBJECT_TYPE_EXTENSION","INTERFACE_TYPE_EXTENSION","UNION_TYPE_EXTENSION","ENUM_TYPE_EXTENSION","INPUT_OBJECT_TYPE_EXTENSION","Location","startToken","endToken","end","toJSON","for","Token","kind","prev","next","isNode","maybeNode","TokenKind","SOF","EOF","BANG","DOLLAR","AMP","PAREN_L","PAREN_R","SPREAD","COLON","EQUALS","AT","BRACKET_L","BRACKET_R","BRACE_L","PIPE","BRACE_R","BLOCK_STRING","COMMENT","inspect","formatValue","seenValues","JSON","stringify","previouslySeenValues","indexOf","jsonValue","array","min","remaining","items","formatArray","object","keys","tag","prototype","call","replace","getObjectTag","key","formatObject","formatObjectValue","String","devAssert","condition","Boolean","Source","DirectiveLocation","QUERY","MUTATION","SUBSCRIPTION","SCHEMA","SCALAR","ARGUMENT_DEFINITION","INTERFACE","UNION","ENUM_VALUE","INPUT_OBJECT","INPUT_FIELD_DEFINITION","dedentBlockStringValue","rawString","commonIndent","isFirstLine","isEmptyLine","indent","charCodeAt","getBlockStringIndentation","startLine","isBlank","endLine","printBlockString","indentation","preferMultipleLines","isSingleLine","hasLeadingSpace","hasTrailingQuote","hasTrailingSlash","printAsMultipleLines","result","Lexer","startOfFileToken","lastToken","token","lineStart","advance","lookahead","readToken","printCharCode","code","isNaN","fromCharCode","toUpperCase","lexer","bodyLength","col","readComment","readBlockString","readString","readNumber","readName","unexpectedCharacterMessage","firstCode","isFloat","readDigits","isNameStart","chunkStart","charCode","a","b","c","d","char2hex","rawValue","parse","options","Parser","parseDocument","sourceObj","instanceOf","isSource","_lexer","_options","parseName","expectToken","definitions","many","parseDefinition","peek","parseOperationDefinition","parseFragmentDefinition","parseTypeSystemDefinition","parseTypeSystemExtension","peekDescription","unexpected","operation","variableDefinitions","directives","selectionSet","parseSelectionSet","parseOperationType","parseVariableDefinitions","parseDirectives","operationToken","optionalMany","parseVariableDefinition","variable","parseVariable","type","parseTypeReference","defaultValue","expectOptionalToken","parseValueLiteral","selections","parseSelection","parseFragment","parseField","nameOrAlias","alias","arguments","parseArguments","isConst","item","parseConstArgument","parseArgument","hasTypeCondition","expectOptionalKeyword","parseFragmentName","typeCondition","parseNamedType","expectKeyword","experimentalFragmentVariables","parseList","parseObject","parseStringLiteral","block","values","any","fields","parseObjectField","parseDirective","keywordToken","parseSchemaDefinition","parseScalarTypeDefinition","parseObjectTypeDefinition","parseInterfaceTypeDefinition","parseUnionTypeDefinition","parseEnumTypeDefinition","parseInputObjectTypeDefinition","parseDirectiveDefinition","parseDescription","operationTypes","parseOperationTypeDefinition","interfaces","parseImplementsInterfaces","parseFieldsDefinition","delimitedMany","parseFieldDefinition","args","parseArgumentDefs","parseInputValueDef","types","parseUnionMemberTypes","parseEnumValuesDefinition","parseEnumValueDefinition","parseInputFieldsDefinition","parseSchemaExtension","parseScalarTypeExtension","parseObjectTypeExtension","parseInterfaceTypeExtension","parseUnionTypeExtension","parseEnumTypeExtension","parseInputObjectTypeExtension","repeatable","parseDirectiveLocations","parseDirectiveLocation","noLocation","getTokenKindDesc","getTokenDesc","atToken","openKind","parseFn","closeKind","delimiterKind","isPunctuatorTokenKind","QueryDocumentKeys","Name","Document","OperationDefinition","VariableDefinition","Variable","SelectionSet","Field","Argument","FragmentSpread","InlineFragment","FragmentDefinition","IntValue","FloatValue","StringValue","BooleanValue","NullValue","EnumValue","ListValue","ObjectValue","ObjectField","Directive","NamedType","ListType","NonNullType","SchemaDefinition","OperationTypeDefinition","ScalarTypeDefinition","ObjectTypeDefinition","FieldDefinition","InputValueDefinition","InterfaceTypeDefinition","UnionTypeDefinition","EnumTypeDefinition","EnumValueDefinition","InputObjectTypeDefinition","DirectiveDefinition","SchemaExtension","ScalarTypeExtension","ObjectTypeExtension","InterfaceTypeExtension","UnionTypeExtension","EnumTypeExtension","InputObjectTypeExtension","BREAK","visit","root","visitor","visitorKeys","parent","inArray","edits","ancestors","newRoot","isLeaving","isEdited","pop","clone","k","editOffset","ii","editKey","editValue","splice","visitFn","getVisitFn","visitInParallel","visitors","skipping","enter","fn","apply","leave","kindVisitor","kindSpecificVisitor","specificVisitor","specificKindVisitor","objectValues","obj","NAME_RX","objectEntries","entries","keyMap","keyFn","create","mapValue","toObjMap","getPrototypeOf","keyValMap","valFn","didYouMean","firstArg","secondArg","subMessage","suggestionsArg","suggestions","x","selected","lastItem","identityFunc","suggestionList","input","optionsByDistance","lexicalDistance","LexicalDistance","threshold","option","distance","measure","sort","distanceDiff","localeCompare","_input","_inputLowerCase","toLowerCase","_inputArray","stringToArray","_rows","fill","optionLowerCase","tmp","aLength","bLength","rows","j","upRow","currentRow","smallestCell","cost","currentCell","doubleDiagonalCell","strLength","print","ast","printDocASTReducer","op","varDefs","wrap","argsLine","isBlockString","addDescription","hasMultilineItems","cb","maybeArray","separator","maybeString","isMultiline","some","invariant","valueFromASTUntyped","valueNode","variables","parseInt","parseFloat","field","isType","isScalarType","isObjectType","isInterfaceType","isUnionType","isEnumType","isInputObjectType","isListType","isNonNullType","GraphQLScalarType","GraphQLObjectType","GraphQLInterfaceType","GraphQLUnionType","GraphQLEnumType","GraphQLInputObjectType","GraphQLList","GraphQLNonNull","isInputType","isWrappingType","ofType","isOutputType","isLeafType","isCompositeType","isAbstractType","isNullableType","getNullableType","isNamedType","getNamedType","unwrappedType","resolveThunk","thunk","undefineIfEmpty","arr","config","parseValue","specifiedByUrl","serialize","parseLiteral","astNode","extensionASTNodes","toConfig","isTypeOf","_fields","defineFieldMap","bind","_interfaces","defineInterfaces","getFields","getInterfaces","fieldsToFieldsConfig","fieldMap","isPlainObj","fieldConfig","fieldName","resolve","argsConfig","argName","argConfig","deprecationReason","subscribe","argsToArgsConfig","arg","isRequiredArgument","resolveType","_types","defineTypes","getTypes","typeName","valueMap","_values","valueName","valueConfig","_valueLookup","Map","enumValue","_nameLookup","getValues","getValue","outputValue","inputValue","valueStr","didYouMeanEnumValue","_variables","enumType","unknownValueStr","defineInputFieldMap","isRequiredInputField","isEqualType","typeA","typeB","isTypeSubTypeOf","schema","maybeSubType","superType","isSubType","doTypesOverlap","getPossibleTypes","MAX_INT","MIN_INT","GraphQLInt","coercedValue","serializeObject","num","Number","isInteger","GraphQLFloat","isFinite","valueOf","valueOfResult","GraphQLString","GraphQLBoolean","GraphQLID","specifiedScalarTypes","isSpecifiedScalarType","astFromValue","astValue","itemType","iterator","isCollection","valuesNodes","from","itemNode","fieldNodes","fieldValue","serialized","stringNum","integerStringRegExp","test","TypeError","__Schema","__Type","getTypeMap","queryType","getQueryType","mutationType","getMutationType","subscriptionType","getSubscriptionType","__Directive","getDirectives","directive","isRepeatable","__DirectiveLocation","__InputValue","__TypeKind","TypeKind","NON_NULL","__Field","includeDeprecated","possibleTypes","_args","_context","enumValues","__EnumValue","inputFields","isDeprecated","valueAST","SchemaMetaFieldDef","TypeMetaFieldDef","getType","TypeNameMetaFieldDef","parentType","introspectionTypes","isIntrospectionType","isDirective","GraphQLDirective","GraphQLIncludeDirective","if","GraphQLSkipDirective","DEFAULT_DEPRECATION_REASON","GraphQLDeprecatedDirective","reason","GraphQLSpecifiedByDirective","url","specifiedDirectives","assertSchema","GraphQLSchema","isSchema","__validationErrors","assumeValid","_queryType","query","_mutationType","mutation","_subscriptionType","subscription","_directives","allReferencedTypes","Set","delete","collectReferencedTypes","_typeMap","_subTypeMap","_implementationsMap","namedType","iface","implementations","objects","abstractType","getImplementations","interfaceType","getDirective","find","typeSet","has","add","memberType","validateSchema","context","SchemaValidationContext","reportError","getOperationTypeNode","validateRootTypes","validateName","getDeprecatedDirectiveNode","validateDirectives","validateInputObjectCircularRefs","visitedTypes","fieldPath","fieldPathIndexByTypeName","detectCycleRecursive","inputObj","fieldType","cycleIndex","cyclePath","pathStr","fieldObj","createInputObjectCircularRefsValidator","typeMap","validateFields","validateInterfaces","validateUnionMembers","validateEnumValues","validateInputFields","validateTypes","errors","getErrors","_errors","addError","operationNodes","getAllSubNodes","rawOriginalError","locatedError","getAllNodes","ifaceTypeNames","getAllImplementsInterfaceNodes","validateTypeImplementsAncestors","validateTypeImplementsInterface","typeFieldMap","ifaceField","typeField","ifaceArg","typeArg","ifaceInterfaces","transitive","union","memberTypes","includedTypeNames","getUnionMemberTypeNodes","concat","getter","subNodes","typeNode","ifaceNode","unionNode","definitionNode","typeFromAST","innerType","TypeInfo","getFieldDefFn","initialType","_schema","_typeStack","_parentTypeStack","_inputTypeStack","_fieldDefStack","_defaultValueStack","_directive","_argument","_enumValue","_getFieldDef","getFieldDef","getParentType","getInputType","getParentInputType","getDefaultValue","getArgument","getEnumValue","fieldDef","typeConditionAST","outputType","inputType","argDef","argType","fieldOrDirective","listType","objectType","inputFieldType","inputField","fieldNode","visitWithTypeInfo","typeInfo","isExecutableDefinitionNode","isTypeDefinitionNode","isTypeExtensionNode","KnownTypeNamesRule","getSchema","existingTypesMap","definedTypes","def","getDocument","typeNames","_1","_2","isSDL","isTypeSystemDefinitionNode","isTypeSystemExtensionNode","standardTypeNames","isStandardTypeName","suggestedTypes","NoUnusedFragmentsRule","operationDefs","fragmentDefs","fragmentNameUsed","fragment","getRecursivelyReferencedFragments","fragmentDef","fragName","KnownDirectivesRule","locationsMap","definedDirectives","astDefinitions","_key","_parent","_path","candidateLocation","appliedTo","getDirectiveLocationForOperation","getDirectiveLocationForASTPath","UniqueDirectivesPerLocationRule","uniqueDirectiveMap","schemaDirectives","typeDirectivesMap","seenDirectives","directiveName","KnownArgumentNamesOnDirectivesRule","directiveArgs","argsNodes","directiveNode","knownArgs","argNode","UniqueArgumentNamesRule","knownArgNames","isValidValueNode","locationType","typeStr","ProvidedRequiredArgumentsOnDirectivesRule","requiredArgsMap","argNodes","isRequiredArgumentNode","requiredArgs","argNodeMap","argTypeStr","allowedVariableUsage","varType","varDefaultValue","locationDefaultValue","hasLocationDefaultValue","reasonMessage","responseName","subReason","collectConflictsBetweenFieldsAndFragment","conflicts","cachedFieldsAndFragmentNames","comparedFragmentPairs","areMutuallyExclusive","fragmentName","getFragment","fieldMap2","fragmentNames2","getReferencedFieldsAndFragmentNames","collectConflictsBetween","collectConflictsBetweenFragments","fragmentName1","fragmentName2","fragment1","fragment2","fieldMap1","fragmentNames1","parentFieldsAreMutuallyExclusive","fields2","fields1","conflict","findConflict","field1","field2","parentType1","node1","def1","parentType2","node2","def2","name1","name2","arguments1","arguments2","every","argument1","argument2","argument","value1","value2","sameArguments","type1","type2","doTypesConflict","selectionSet1","selectionSet2","allFields","subfieldConflicts","getFieldsAndFragmentNames","findConflictsBetweenSubSelectionSets","cached","nodeAndDefs","fragmentNames","_collectFieldsAndFragmentNames","set","fragmentType","selection","inlineFragmentType","PairSet","_data","first","_pairSetAdd","UniqueInputFieldNamesRule","knownNameStack","knownNames","hasField","defKindToExtKind","specifiedRules","definition","defName","knownOperationNames","operationName","operationCount","variableName","suggestion","usageCount","possibleType","possibleInterface","usageCountDiff","getSuggestedTypeNames","getSuggestedFieldNames","knownFragmentNames","fragType","parentTypeStr","fragTypeStr","frag","getFragmentType","visitedFrags","spreadPath","spreadPathIndexByName","spreadNodes","getFragmentSpreads","spreadNode","spreadName","spreadFragment","viaPath","s","knownVariableNames","variableNameDefined","usages","getRecursiveVariableUsages","varName","variableDefs","variableNameUsed","variableDef","fieldNodeMap","varDefMap","varDef","varTypeStr","collectConflictsWithin","findConflictsWithinSelectionSet","reasonMsg","specifiedSDLRules","oldSchema","alreadyDefined","schemaDefinitionsCount","definedOperationTypes","existingOperationTypes","checkOperationTypes","operationTypesNodes","operationType","alreadyDefinedOperationType","knownTypeNames","checkTypeName","existingTypeMap","knownValueNames","checkValueUniqueness","valueNodes","valueNames","valueDef","existingType","knownFieldNames","checkFieldUniqueness","fieldNames","knownDirectiveNames","checkExtension","defNode","expectedKind","typeToExtKind","kindStr","extensionKindToTypeName","allTypeNames","ASTValidationContext","onError","_ast","_fragments","_fragmentSpreads","_recursivelyReferencedFragments","_onError","fragments","frags","statement","spreads","setsToVisit","collectedNames","nodesToVisit","spread","SDLValidationContext","ValidationContext","_typeInfo","_variableUsages","_recursiveVariableUsages","getVariableUsages","newUsages","validate","documentAST","rules","maxErrors","assertValidSchema","abortObj","rule","e","validateSDL","schemaToExtend","valueFromAST","variableValue","coercedValues","isMissingVariable","itemValue","coercedObj","_error","getDirectiveValues","directiveDef","variableValues","argumentNode","isNull","prop","hasOwnProperty","getArgumentValues","buildClientSchema","introspection","__schema","schemaIntrospection","typeIntrospection","scalarIntrospection","objectIntrospection","buildImplementationsList","buildFieldDefMap","interfaceIntrospection","unionIntrospection","unionIntrospectionStr","getObjectType","buildUnionDef","enumIntrospection","enumIntrospectionStr","valueIntrospection","buildEnumDef","inputObjectIntrospection","inputObjectIntrospectionStr","buildInputValueDefMap","buildInputObjectDef","buildType","stdType","directiveIntrospection","directiveIntrospectionStr","typeRef","itemRef","nullableRef","nullableType","assertNullableType","assertObjectType","getInterfaceType","assertInterfaceType","implementingIntrospection","implementingIntrospectionStr","fieldIntrospection","buildField","fieldIntrospectionStr","inputValueIntrospections","buildInputValue","inputValueIntrospection","parser","extendSchemaImpl","schemaConfig","typeDefs","typeExtensionsMap","directiveDefs","schemaDef","schemaExtensions","extendedTypeName","existingTypeExtensions","extendNamedType","stdTypeMap","replaceNamedType","getOperationTypes","extendArg","buildArgumentMap","replaceType","extensionNode","getSpecifiedByUrl","extendScalarType","buildInterfaces","extendField","buildFieldMap","extendObjectType","extendInterfaceType","buildUnionTypes","extendUnionType","buildEnumValueMap","extendEnumType","buildInputFieldMap","extendInputObjectType","opTypes","getWrappedType","fieldConfigMap","nodeFields","getDeprecationReason","argConfigMap","inputFieldMap","fieldsNodes","enumValueMap","interfacesNodes","typeNodes","extensionNodes","allNodes","buildASTSchema","assumeValidSDL","assertValidSDL","stdDirective","printSchema","directiveFilter","typeFilter","printSchemaDefinition","printDescription","printArgs","printDirective","scalar","urlAST","printSpecifiedByUrl","printScalar","printImplementedInterfaces","printFields","printObject","printInterface","printUnion","printDeprecated","printBlock","printEnum","f","printInputValue","printInputObject","printType","printFilteredSchema","n","isDefinedType","isSchemaOfCommonNames","defaultAST","argDecl","reasonAST","firstInBlock","specifiedRulesToBeRemoved","defaultValidationRules","includes","GraphQLSchemaValidationError","validationErrors","isMetaFieldName","startsWith","isNotNullOrUndefined","valueFromValueNode","filePathForNode","compileToIR","document","fragmentNodeMap","operations","fragmentMap","referencedTypes","compileOperation","fragmentNode","compileFragment","operationDefinition","filePath","rootType","getOperationRootType","compileSelectionSet","fragmentDefinition","selectionSetNode","visitedFragments","selectionNode","unwrappedFieldType","argDefType","compileSelection","introspectionResult","payload","data","documents","doc","concatAST"],"mappings":"mDAIe,SAASA,EAAaC,GACnC,MAAuB,iBAATA,GAA+B,OAAVA,ECG9B,SAASC,EAAYC,EAAQC,GAClC,MAAMC,EAAa,eACnB,IAEIC,EAFAC,EAAO,EACPC,EAASJ,EAAW,EAGxB,MAAQE,EAAQD,EAAWI,KAAKN,EAAOO,QAAUJ,EAAMK,MAAQP,GAC7DG,GAAQ,EACRC,EAASJ,EAAW,GAAKE,EAAMK,MAAQL,EAAM,GAAGM,QAGlD,MAAO,CACLL,KAAAA,EACAC,OAAAA,GChBG,SAASK,EAAcC,GAC5B,OAAOC,EAAoBD,EAASX,OAAQD,EAAYY,EAASX,OAAQW,EAASE,QAM7E,SAASD,EAAoBZ,EAAQc,GAC1C,MAAMC,EAAwBf,EAAOgB,eAAeX,OAAS,EACvDE,EAAOU,EAAWF,GAAyBf,EAAOO,KAClDW,EAAYJ,EAAeV,KAAO,EAClCe,EAAanB,EAAOgB,eAAeZ,KAAO,EAC1CgB,EAAUN,EAAeV,KAAOe,EAChCE,EAAuC,IAAxBP,EAAeV,KAAaW,EAAwB,EACnEO,EAAYR,EAAeT,OAASgB,EACpCE,EAAc,GAAGvB,EAAOwB,QAAQJ,KAAWE,MAC3CG,EAAQlB,EAAKmB,MAAM,gBACnBC,EAAeF,EAAMP,GAE3B,GAAIS,EAAalB,OAAS,IAAK,CAC7B,MAAMmB,EAAeC,KAAKC,MAAMR,EAAY,IACtCS,EAAmBT,EAAY,GAC/BU,EAAW,GAEjB,IAAK,IAAIC,EAAI,EAAGA,EAAIN,EAAalB,OAAQwB,GAAK,GAC5CD,EAASE,KAAKP,EAAaQ,MAAMF,EAAGA,EAAI,KAG1C,OAAOV,EAAca,EAAmB,CAAC,CAAC,GAAGhB,IAAWY,EAAS,OAAQA,EAASG,MAAM,EAAGP,EAAe,GAAGS,KAAIC,GAAW,CAAC,GAAIA,KAAW,CAAC,IAAKrB,EAAWc,EAAmB,GAAK,KAAM,CAAC,GAAIC,EAASJ,EAAe,MAG1N,OAAOL,EAAca,EAAmB,CACxC,CAAC,IAAGhB,EAAU,GAAKK,EAAMP,EAAY,IAAK,CAAC,GAAGE,IAAWO,GAAe,CAAC,GAAIV,EAAWK,EAAY,GAAK,KAAM,CAAC,GAAGF,EAAU,IAAKK,EAAMP,EAAY,MAGtJ,SAASkB,EAAmBX,GAC1B,MAAMc,EAAgBd,EAAMe,QAAO,EAAEC,EAAGrC,UAAmBsC,IAATtC,IAC5CuC,EAASd,KAAKe,OAAOL,EAAcF,KAAI,EAAEQ,KAAYA,EAAOpC,UAClE,OAAO8B,EAAcF,KAAI,EAAEQ,EAAQzC,MAAU0C,OAQtC7B,EAR8C0B,GAOjCI,EAPyCF,GAQjCpC,QAAUsC,GARkC3C,EAAO,MAAQA,EAAO,MAOhG,IAAsB2C,KAPiFC,KAAK,MAG5G,SAAS/B,EAAWgC,GAClB,OAAOC,MAAMD,EAAM,GAAGD,KAAK,KCnCtB,MAAMG,qBAAqBC,MAkDhCC,YAAYC,EAASC,EAAOvD,EAAQwD,EAAWC,EAAMC,EAAeC,GAClEC,MAAMN,GAEN,MAAMO,EAASX,MAAMY,QAAQP,GAA0B,IAAjBA,EAAM9C,OAAe8C,OAAQb,EAAYa,EAAQ,CAACA,QAASb,EAGjG,IAAIqB,EAAU/D,GAET+D,GAAWF,IACdE,EAAUF,EAAO,GAAGG,KAAKhE,QAG3B,IAgBIiE,EAhBAC,EAAaV,GAEZU,GAAcL,IACjBK,EAAaL,EAAOM,QAAO,CAACC,EAAMC,KAC5BA,EAAKL,KACPI,EAAKlC,KAAKmC,EAAKL,IAAInD,OAGduD,IACN,KAGDF,GAAoC,IAAtBA,EAAWzD,SAC3ByD,OAAaxB,GAKXc,GAAaxD,EACfiE,EAAaT,EAAUnB,KAAIiC,GAAOvE,EAAYC,EAAQsE,KAC7CT,IACTI,EAAaJ,EAAOM,QAAO,CAACC,EAAMC,KAC5BA,EAAKL,KACPI,EAAKlC,KAAKnC,EAAYsE,EAAKL,IAAIhE,OAAQqE,EAAKL,IAAInD,QAG3CuD,IACN,KAGL,IAAIG,EAAcZ,EAElB,GAAmB,MAAfY,GAAwC,MAAjBb,EAAuB,CAChD,MAAMc,EAAqBd,EAAcC,WAErC9D,EAAa2E,KACfD,EAAcC,GAIlBC,OAAOC,iBAAiBC,KAAM,CAC5BnD,KAAM,CACJ1B,MAAO,gBAETwD,QAAS,CACPxD,MAAOwD,EAIPsB,YAAY,EACZC,UAAU,GAEZC,UAAW,CAGThF,MAAOmE,QAAcvB,EAIrBkC,WAA0B,MAAdX,GAEdR,KAAM,CAGJ3D,MAAO2D,QAAQf,EAIfkC,WAAoB,MAARnB,GAEdF,MAAO,CACLzD,MAAO+D,QAAUnB,GAEnB1C,OAAQ,CACNF,MAAOiE,QAAWrB,GAEpBc,UAAW,CACT1D,MAAOoE,QAAcxB,GAEvBgB,cAAe,CACb5D,MAAO4D,GAETC,WAAY,CAGV7D,MAAOyE,QAAe7B,EAItBkC,WAA2B,MAAfL,KAIZb,GAAeqB,MACjBN,OAAOO,eAAeL,KAAM,QAAS,CACnC7E,MAAO4D,EAAcqB,MACrBF,UAAU,EACVI,cAAc,IAMd7B,MAAM8B,kBACR9B,MAAM8B,kBAAkBP,KAAMxB,cAE9BsB,OAAOO,eAAeL,KAAM,QAAS,CACnC7E,MAAOsD,QAAQ2B,MACfF,UAAU,EACVI,cAAc,IAKpBE,WACE,OAeG,SAAoBC,GACzB,IAAIC,EAASD,EAAM9B,QAEnB,GAAI8B,EAAM7B,MACR,IAAK,MAAMc,KAAQe,EAAM7B,MACnBc,EAAKL,MACPqB,GAAU,OAAS3E,EAAc2D,EAAKL,WAGrC,GAAIoB,EAAMpF,QAAUoF,EAAMN,UAC/B,IAAK,MAAMnE,KAAYyE,EAAMN,UAC3BO,GAAU,OAASzE,EAAoBwE,EAAMpF,OAAQW,GAIzD,OAAO0E,EA9BEC,CAAWX,MAKpBY,IAAKC,OAAOC,eACV,MAAO,UC7LJ,SAASC,EAAY1F,EAAQC,EAAU0F,GAC5C,OAAO,IAAIxC,aAAa,iBAAiBwC,SAAejD,EAAW1C,EAAQ,CAACC,ICJvE,MAAM2F,EAAOnB,OAAOoB,OAAO,CAEhCC,KAAM,OAENC,SAAU,WACVC,qBAAsB,sBACtBC,oBAAqB,qBACrBC,cAAe,eACfC,MAAO,QACPC,SAAU,WAEVC,gBAAiB,iBACjBC,gBAAiB,iBACjBC,oBAAqB,qBAErBC,SAAU,WACVC,IAAK,WACLC,MAAO,aACPC,OAAQ,cACRC,QAAS,eACTC,KAAM,YACNC,KAAM,YACNC,KAAM,YACNC,OAAQ,cACRC,aAAc,cAEdC,UAAW,YAEXC,WAAY,YACZC,UAAW,WACXC,cAAe,cAEfC,kBAAmB,mBACnBC,0BAA2B,0BAE3BC,uBAAwB,uBACxBC,uBAAwB,uBACxBC,iBAAkB,kBAClBC,uBAAwB,uBACxBC,0BAA2B,0BAC3BC,sBAAuB,sBACvBC,qBAAsB,qBACtBC,sBAAuB,sBACvBC,6BAA8B,4BAE9BC,qBAAsB,sBAEtBC,iBAAkB,kBAElBC,sBAAuB,sBACvBC,sBAAuB,sBACvBC,yBAA0B,yBAC1BC,qBAAsB,qBACtBC,oBAAqB,oBACrBC,4BAA6B,6BCrDxB,MAAMC,SAoBXpF,YAAYqF,EAAYC,EAAU3I,GAChC2E,KAAK9D,MAAQ6H,EAAW7H,MACxB8D,KAAKiE,IAAMD,EAASC,IACpBjE,KAAK+D,WAAaA,EAClB/D,KAAKgE,SAAWA,EAChBhE,KAAK3E,OAASA,EAGhB6I,SACE,MAAO,CACLhI,MAAO8D,KAAK9D,MACZ+H,IAAKjE,KAAKiE,KAMd,CAACpD,OAAOsD,IAAI,iCACV,OAAOnE,KAAKkE,UAST,MAAME,MA8BX1F,YAAY2F,EAAMnI,EAAO+H,EAAKxI,EAAMC,EAAQ4I,EAAMnJ,GAChD6E,KAAKqE,KAAOA,EACZrE,KAAK9D,MAAQA,EACb8D,KAAKiE,IAAMA,EACXjE,KAAKvE,KAAOA,EACZuE,KAAKtE,OAASA,EACdsE,KAAK7E,MAAQA,EACb6E,KAAKsE,KAAOA,EACZtE,KAAKuE,KAAO,KAGdL,SACE,MAAO,CACLG,KAAMrE,KAAKqE,KACXlJ,MAAO6E,KAAK7E,MACZM,KAAMuE,KAAKvE,KACXC,OAAQsE,KAAKtE,QAMjB,CAACmF,OAAOsD,IAAI,iCACV,OAAOnE,KAAKkE,UAQT,SAASM,EAAOC,GACrB,OAAoB,MAAbA,GAA+C,iBAAnBA,EAAUJ,KC7GxC,MAAMK,EAAY5E,OAAOoB,OAAO,CACrCyD,IAAK,QACLC,IAAK,QACLC,KAAM,IACNC,OAAQ,IACRC,IAAK,IACLC,QAAS,IACTC,QAAS,IACTC,OAAQ,MACRC,MAAO,IACPC,OAAQ,IACRC,GAAI,IACJC,UAAW,IACXC,UAAW,IACXC,QAAS,IACTC,KAAM,IACNC,QAAS,IACTvE,KAAM,OACNW,IAAK,MACLC,MAAO,QACPC,OAAQ,SACR2D,aAAc,cACdC,QAAS,YCnBI,SAASC,EAAQ1K,GAC9B,OAAO2K,EAAY3K,EAAO,IAG5B,SAAS2K,EAAY3K,EAAO4K,GAC1B,cAAe5K,GACb,IAAK,SACH,OAAO6K,KAAKC,UAAU9K,GAExB,IAAK,WACH,OAAOA,EAAM0B,KAAO,aAAa1B,EAAM0B,QAAU,aAEnD,IAAK,SACH,OAAc,OAAV1B,EACK,OAUf,SAA2BA,EAAO+K,GAChC,IAA6C,IAAzCA,EAAqBC,QAAQhL,GAC/B,MAAO,aAGT,MAAM4K,EAAa,IAAIG,EAAsB/K,GAE7C,GAA4B,mBAAjBA,EAAM+I,OAAuB,CACtC,MAAMkC,EAAYjL,EAAM+I,OAAO/I,GAE/B,GAAIiL,IAAcjL,EAChB,MAA4B,iBAAdiL,EAAyBA,EAAYN,EAAYM,EAAWL,QAEvE,GAAIxH,MAAMY,QAAQhE,GACvB,OAwBJ,SAAqBkL,EAAON,GAC1B,GAAqB,IAAjBM,EAAMvK,OACR,MAAO,KAGT,GAAIiK,EAAWjK,OAxEW,EAyExB,MAAO,UAGT,MAAMwC,EAAMpB,KAAKoJ,IA7EM,GA6EgBD,EAAMvK,QACvCyK,EAAYF,EAAMvK,OAASwC,EAC3BkI,EAAQ,GAEd,IAAK,IAAIlJ,EAAI,EAAGA,EAAIgB,IAAOhB,EACzBkJ,EAAMjJ,KAAKuI,EAAYO,EAAM/I,GAAIyI,IAGjB,IAAdQ,EACFC,EAAMjJ,KAAK,mBACFgJ,EAAY,GACrBC,EAAMjJ,KAAK,OAAOgJ,gBAGpB,MAAO,IAAMC,EAAMnI,KAAK,MAAQ,IA/CvBoI,CAAYtL,EAAO4K,GAG5B,OAGF,SAAsBW,EAAQX,GAC5B,MAAMY,EAAO7G,OAAO6G,KAAKD,GAEzB,GAAoB,IAAhBC,EAAK7K,OACP,MAAO,KAGT,GAAIiK,EAAWjK,OAxDW,EAyDxB,MAAO,IAoCX,SAAsB4K,GACpB,MAAME,EAAM9G,OAAO+G,UAAUrG,SAASsG,KAAKJ,GAAQK,QAAQ,aAAc,IAAIA,QAAQ,KAAM,IAE3F,GAAY,WAARH,GAAkD,mBAAvBF,EAAOhI,YAA4B,CAChE,MAAM7B,EAAO6J,EAAOhI,YAAY7B,KAEhC,GAAoB,iBAATA,GAA8B,KAATA,EAC9B,OAAOA,EAIX,OAAO+J,EA/CQI,CAAaN,GAAU,IAOtC,MAAO,KAJYC,EAAKjJ,KAAIuJ,GAEnBA,EAAM,KADCnB,EAAYY,EAAOO,GAAMlB,KAGhB1H,KAAK,MAAQ,KAlB/B6I,CAAa/L,EAAO4K,GAxBhBoB,CAAkBhM,EAAO4K,GAElC,QACE,OAAOqB,OAAOjM,IC3BL,SAASkM,EAAUC,EAAW3I,GAG3C,IAFyB4I,QAAQD,GAG/B,MAAM,IAAI7I,MAAME,SCIpB,SAAoBxD,EAAOuD,GACzB,OAAOvD,aAAiBuD,GCEnB,MAAM8I,OACX9I,YAAY9C,EAAMiB,EAAO,kBAAmBR,EAAiB,CAC3DZ,KAAM,EACNC,OAAQ,IAEQ,iBAATE,GAAqByL,EAAU,EAAG,oCAAoCxB,EAAQjK,OACrFoE,KAAKpE,KAAOA,EACZoE,KAAKnD,KAAOA,EACZmD,KAAK3D,eAAiBA,EACtB2D,KAAK3D,eAAeZ,KAAO,GAAK4L,EAAU,EAAG,6DAC7CrH,KAAK3D,eAAeX,OAAS,GAAK2L,EAAU,EAAG,+DAIjDzG,IAAKC,OAAOC,eACV,MAAO,UCvBJ,MAAM2G,EAAoB3H,OAAOoB,OAAO,CAE7CwG,MAAO,QACPC,SAAU,WACVC,aAAc,eACdpG,MAAO,QACPI,oBAAqB,sBACrBF,gBAAiB,kBACjBC,gBAAiB,kBACjBL,oBAAqB,sBAErBuG,OAAQ,SACRC,OAAQ,SACRzF,OAAQ,SACRU,iBAAkB,mBAClBgF,oBAAqB,sBACrBC,UAAW,YACXC,MAAO,QACP9F,KAAM,OACN+F,WAAY,aACZC,aAAc,eACdC,uBAAwB,2BChBnB,SAASC,EAAuBC,GAErC,MAAMxL,EAAQwL,EAAUvL,MAAM,gBAExBwL,EAuCD,SAAmCpN,GACxC,IAAIqN,GAAc,EACdC,GAAc,EACdC,EAAS,EACTH,EAAe,KAEnB,IAAK,IAAIjL,EAAI,EAAGA,EAAInC,EAAMW,SAAUwB,EAClC,OAAQnC,EAAMwN,WAAWrL,IACvB,KAAK,GAE6B,KAA5BnC,EAAMwN,WAAWrL,EAAI,MACrBA,EAKN,KAAK,GAEHkL,GAAc,EACdC,GAAc,EACdC,EAAS,EACT,MAEF,KAAK,EAEL,KAAK,KAEDA,EACF,MAEF,QACMD,IAAgBD,IAAiC,OAAjBD,GAAyBG,EAASH,KACpEA,EAAeG,GAGjBD,GAAc,EAIpB,OAAOF,GAAgB,EA9EFK,CAA0BN,GAE/C,GAAqB,IAAjBC,EACF,IAAK,IAAIjL,EAAI,EAAGA,EAAIR,EAAMhB,OAAQwB,IAChCR,EAAMQ,GAAKR,EAAMQ,GAAGE,MAAM+K,GAK9B,IAAIM,EAAY,EAEhB,KAAOA,EAAY/L,EAAMhB,QAAUgN,EAAQhM,EAAM+L,OAC7CA,EAGJ,IAAIE,EAAUjM,EAAMhB,OAEpB,KAAOiN,EAAUF,GAAaC,EAAQhM,EAAMiM,EAAU,OAClDA,EAIJ,OAAOjM,EAAMU,MAAMqL,EAAWE,GAAS1K,KAAK,MAG9C,SAASyK,EAAQ1K,GACf,IAAK,IAAId,EAAI,EAAGA,EAAIc,EAAItC,SAAUwB,EAChC,GAAe,MAAXc,EAAId,IAAyB,OAAXc,EAAId,GACxB,OAAO,EAIX,OAAO,EAwDF,SAAS0L,EAAiB7N,EAAO8N,EAAc,GAAIC,GAAsB,GAC9E,MAAMC,GAAwC,IAAzBhO,EAAMgL,QAAQ,MAC7BiD,EAA+B,MAAbjO,EAAM,IAA2B,OAAbA,EAAM,GAC5CkO,EAA+C,MAA5BlO,EAAMA,EAAMW,OAAS,GACxCwN,EAA+C,OAA5BnO,EAAMA,EAAMW,OAAS,GACxCyN,GAAwBJ,GAAgBE,GAAoBC,GAAoBJ,EACtF,IAAIM,EAAS,GAYb,OAVID,GAA0BJ,GAAgBC,IAC5CI,GAAU,KAAOP,GAGnBO,GAAUP,EAAc9N,EAAM4L,QAAQ,MAAO,KAAOkC,GAAe9N,EAE/DoO,IACFC,GAAU,MAGL,MAAQA,EAAOzC,QAAQ,OAAQ,SAAW,MCzG5C,MAAM0C,MAgBX/K,YAAYrD,GACV,MAAMqO,EAAmB,IAAItF,MAAMM,EAAUC,IAAK,EAAG,EAAG,EAAG,EAAG,MAC9D3E,KAAK3E,OAASA,EACd2E,KAAK2J,UAAYD,EACjB1J,KAAK4J,MAAQF,EACb1J,KAAKvE,KAAO,EACZuE,KAAK6J,UAAY,EAOnBC,UACE9J,KAAK2J,UAAY3J,KAAK4J,MAEtB,OADc5J,KAAK4J,MAAQ5J,KAAK+J,YASlCA,YACE,IAAIH,EAAQ5J,KAAK4J,MAEjB,GAAIA,EAAMvF,OAASK,EAAUE,IAC3B,GAEEgF,EAAQA,EAAMrF,OAASqF,EAAMrF,KAAOyF,EAAUhK,KAAM4J,UAC7CA,EAAMvF,OAASK,EAAUkB,SAGpC,OAAOgE,GAYX,SAASK,EAAcC,GACrB,OACEC,MAAMD,GAAQxF,EAAUE,IACxBsF,EAAO,IAASlE,KAAKC,UAAUmB,OAAOgD,aAAaF,IACnD,QAAQ,KAAOA,EAAK1J,SAAS,IAAI6J,eAAe7M,OAAO,MAY3D,SAASwM,EAAUM,EAAOhG,GACxB,MAAMjJ,EAASiP,EAAMjP,OACfO,EAAOP,EAAOO,KACd2O,EAAa3O,EAAKE,OACxB,IAAI6D,EAAM2E,EAAKL,IAEf,KAAOtE,EAAM4K,GAAY,CACvB,MAAML,EAAOtO,EAAK+M,WAAWhJ,GACvBlE,EAAO6O,EAAM7O,KACb+O,EAAM,EAAI7K,EAAM2K,EAAMT,UAE5B,OAAQK,GACN,KAAK,MAEL,KAAK,EAEL,KAAK,GAEL,KAAK,KAEDvK,EACF,SAEF,KAAK,KAEDA,IACA2K,EAAM7O,KACR6O,EAAMT,UAAYlK,EAClB,SAEF,KAAK,GAE8B,KAA7B/D,EAAK+M,WAAWhJ,EAAM,GACxBA,GAAO,IAELA,IAGF2K,EAAM7O,KACR6O,EAAMT,UAAYlK,EAClB,SAEF,KAAK,GAEH,OAAO,IAAIyE,MAAMM,EAAUG,KAAMlF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE5D,KAAK,GAEH,OAAOmG,EAAYpP,EAAQsE,EAAKlE,EAAM+O,EAAKlG,GAE7C,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUI,OAAQnF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE9D,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUK,IAAKpF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE3D,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUM,QAASrF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE/D,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUO,QAAStF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE/D,KAAK,GAEH,GAAiC,KAA7B1I,EAAK+M,WAAWhJ,EAAM,IAA0C,KAA7B/D,EAAK+M,WAAWhJ,EAAM,GAC3D,OAAO,IAAIyE,MAAMM,EAAUQ,OAAQvF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAG9D,MAEF,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUS,MAAOxF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE7D,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUU,OAAQzF,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE9D,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUW,GAAI1F,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE1D,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUY,UAAW3F,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAEjE,KAAK,GAEH,OAAO,IAAIF,MAAMM,EAAUa,UAAW5F,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAEjE,KAAK,IAEH,OAAO,IAAIF,MAAMM,EAAUc,QAAS7F,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE/D,KAAK,IAEH,OAAO,IAAIF,MAAMM,EAAUe,KAAM9F,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE5D,KAAK,IAEH,OAAO,IAAIF,MAAMM,EAAUgB,QAAS/F,EAAKA,EAAM,EAAGlE,EAAM+O,EAAKlG,GAE/D,KAAK,GAEH,OAAiC,KAA7B1I,EAAK+M,WAAWhJ,EAAM,IAA0C,KAA7B/D,EAAK+M,WAAWhJ,EAAM,GACpD+K,EAAgBrP,EAAQsE,EAAKlE,EAAM+O,EAAKlG,EAAMgG,GAGhDK,EAAWtP,EAAQsE,EAAKlE,EAAM+O,EAAKlG,GAE5C,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEH,OAAOsG,EAAWvP,EAAQsE,EAAKuK,EAAMzO,EAAM+O,EAAKlG,GAElD,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,GAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEL,KAAK,IAEH,OAAOuG,EAASxP,EAAQsE,EAAKlE,EAAM+O,EAAKlG,GAG5C,MAAMvD,EAAY1F,EAAQsE,EAAKmL,EAA2BZ,IAG5D,MAAMzO,EAAO6O,EAAM7O,KACb+O,EAAM,EAAI7K,EAAM2K,EAAMT,UAC5B,OAAO,IAAIzF,MAAMM,EAAUE,IAAK2F,EAAYA,EAAY9O,EAAM+O,EAAKlG,GAOrE,SAASwG,EAA2BZ,GAClC,OAAIA,EAAO,IAAmB,IAATA,GAA4B,KAATA,GAA4B,KAATA,EAClD,wCAAwCD,EAAcC,MAGlD,KAATA,EAEK,kFAGF,yCAAyCD,EAAcC,MAShE,SAASO,EAAYpP,EAAQa,EAAOT,EAAM+O,EAAKlG,GAC7C,MAAM1I,EAAOP,EAAOO,KACpB,IAAIsO,EACA5O,EAAWY,EAEf,GACEgO,EAAOtO,EAAK+M,aAAarN,UACjB6O,MAAMD,KAChBA,EAAO,IAAmB,IAATA,IAEjB,OAAO,IAAI9F,MAAMM,EAAUkB,QAAS1J,EAAOZ,EAAUG,EAAM+O,EAAKlG,EAAM1I,EAAK4B,MAAMtB,EAAQ,EAAGZ,IAW9F,SAASsP,EAAWvP,EAAQa,EAAO6O,EAAWtP,EAAM+O,EAAKlG,GACvD,MAAM1I,EAAOP,EAAOO,KACpB,IAAIsO,EAAOa,EACPzP,EAAWY,EACX8O,GAAU,EAOd,GALa,KAATd,IAEFA,EAAOtO,EAAK+M,aAAarN,IAGd,KAAT4O,GAIF,GAFAA,EAAOtO,EAAK+M,aAAarN,GAErB4O,GAAQ,IAAMA,GAAQ,GACxB,MAAMnJ,EAAY1F,EAAQC,EAAU,6CAA6C2O,EAAcC,YAGjG5O,EAAW2P,EAAW5P,EAAQC,EAAU4O,GACxCA,EAAOtO,EAAK+M,WAAWrN,GA0BzB,GAvBa,KAAT4O,IAEFc,GAAU,EACVd,EAAOtO,EAAK+M,aAAarN,GACzBA,EAAW2P,EAAW5P,EAAQC,EAAU4O,GACxCA,EAAOtO,EAAK+M,WAAWrN,IAGZ,KAAT4O,GAAwB,MAATA,IAEjBc,GAAU,EACVd,EAAOtO,EAAK+M,aAAarN,GAEZ,KAAT4O,GAAwB,KAATA,IAEjBA,EAAOtO,EAAK+M,aAAarN,IAG3BA,EAAW2P,EAAW5P,EAAQC,EAAU4O,GACxCA,EAAOtO,EAAK+M,WAAWrN,IAIZ,KAAT4O,GAsON,SAAqBA,GACnB,OAAgB,KAATA,GAAeA,GAAQ,IAAMA,GAAQ,IAAMA,GAAQ,IAAMA,GAAQ,IAvOrDgB,CAAYhB,GAC7B,MAAMnJ,EAAY1F,EAAQC,EAAU,2CAA2C2O,EAAcC,OAG/F,OAAO,IAAI9F,MAAM4G,EAAUtG,EAAU3C,MAAQ2C,EAAU5C,IAAK5F,EAAOZ,EAAUG,EAAM+O,EAAKlG,EAAM1I,EAAK4B,MAAMtB,EAAOZ,IAOlH,SAAS2P,EAAW5P,EAAQa,EAAO6O,GACjC,MAAMnP,EAAOP,EAAOO,KACpB,IAAIN,EAAWY,EACXgO,EAAOa,EAEX,GAAIb,GAAQ,IAAMA,GAAQ,GAAI,CAE5B,GACEA,EAAOtO,EAAK+M,aAAarN,SAClB4O,GAAQ,IAAMA,GAAQ,IAG/B,OAAO5O,EAGT,MAAMyF,EAAY1F,EAAQC,EAAU,2CAA2C2O,EAAcC,OAS/F,SAASS,EAAWtP,EAAQa,EAAOT,EAAM+O,EAAKlG,GAC5C,MAAM1I,EAAOP,EAAOO,KACpB,IAAIN,EAAWY,EAAQ,EACnBiP,EAAa7P,EACb4O,EAAO,EACP/O,EAAQ,GAEZ,KAAOG,EAAWM,EAAKE,SAAWqO,MAAMD,EAAOtO,EAAK+M,WAAWrN,KACtD,KAAT4O,GAA4B,KAATA,GAAiB,CAElC,GAAa,KAATA,EAEF,OADA/O,GAASS,EAAK4B,MAAM2N,EAAY7P,GACzB,IAAI8I,MAAMM,EAAU1C,OAAQ9F,EAAOZ,EAAW,EAAGG,EAAM+O,EAAKlG,EAAMnJ,GAI3E,GAAI+O,EAAO,IAAmB,IAATA,EACnB,MAAMnJ,EAAY1F,EAAQC,EAAU,oCAAoC2O,EAAcC,OAKxF,KAFE5O,EAEW,KAAT4O,EAAa,CAKf,OAHA/O,GAASS,EAAK4B,MAAM2N,EAAY7P,EAAW,GAC3C4O,EAAOtO,EAAK+M,WAAWrN,GAEf4O,GACN,KAAK,GACH/O,GAAS,IACT,MAEF,KAAK,GACHA,GAAS,IACT,MAEF,KAAK,GACHA,GAAS,KACT,MAEF,KAAK,GACHA,GAAS,KACT,MAEF,KAAK,IACHA,GAAS,KACT,MAEF,KAAK,IACHA,GAAS,KACT,MAEF,KAAK,IACHA,GAAS,KACT,MAEF,KAAK,IACHA,GAAS,KACT,MAEF,KAAK,IACH,CAEE,MAAMiQ,GAwFGC,EAxFoBzP,EAAK+M,WAAWrN,EAAW,GAwF5CgQ,EAxFgD1P,EAAK+M,WAAWrN,EAAW,GAwFxEiQ,EAxF4E3P,EAAK+M,WAAWrN,EAAW,GAwFpGkQ,EAxFwG5P,EAAK+M,WAAWrN,EAAW,GAyFxJmQ,EAASJ,IAAM,GAAKI,EAASH,IAAM,EAAIG,EAASF,IAAM,EAAIE,EAASD,IAvFhE,GAAIJ,EAAW,EAAG,CAEhB,MAAMrK,EAAY1F,EAAQC,EAAU,yCADZM,EAAK4B,MAAMlC,EAAW,EAAGA,EAAW,OAI9DH,GAASiM,OAAOgD,aAAagB,GAC7B9P,GAAY,EACZ,MAGJ,QACE,MAAMyF,EAAY1F,EAAQC,EAAU,wCAAwC8L,OAAOgD,aAAaF,SAGlG5O,EACF6P,EAAa7P,GAuEnB,IAAqB+P,EAAGC,EAAGC,EAAGC,EAnE5B,MAAMzK,EAAY1F,EAAQC,EAAU,wBAStC,SAASoP,EAAgBrP,EAAQa,EAAOT,EAAM+O,EAAKlG,EAAMgG,GACvD,MAAM1O,EAAOP,EAAOO,KACpB,IAAIN,EAAWY,EAAQ,EACnBiP,EAAa7P,EACb4O,EAAO,EACPwB,EAAW,GAEf,KAAOpQ,EAAWM,EAAKE,SAAWqO,MAAMD,EAAOtO,EAAK+M,WAAWrN,KAAY,CAEzE,GAAa,KAAT4O,GAAiD,KAAlCtO,EAAK+M,WAAWrN,EAAW,IAA+C,KAAlCM,EAAK+M,WAAWrN,EAAW,GAEpF,OADAoQ,GAAY9P,EAAK4B,MAAM2N,EAAY7P,GAC5B,IAAI8I,MAAMM,EAAUiB,aAAczJ,EAAOZ,EAAW,EAAGG,EAAM+O,EAAKlG,EAAM+D,EAAuBqD,IAIxG,GAAIxB,EAAO,IAAmB,IAATA,GAA4B,KAATA,GAA4B,KAATA,EACzD,MAAMnJ,EAAY1F,EAAQC,EAAU,oCAAoC2O,EAAcC,OAG3E,KAATA,KAEA5O,IACAgP,EAAM7O,KACR6O,EAAMT,UAAYvO,GACA,KAAT4O,GAE6B,KAAlCtO,EAAK+M,WAAWrN,EAAW,GAC7BA,GAAY,IAEVA,IAGFgP,EAAM7O,KACR6O,EAAMT,UAAYvO,GAEX,KAAT4O,GAAiD,KAAlCtO,EAAK+M,WAAWrN,EAAW,IAA+C,KAAlCM,EAAK+M,WAAWrN,EAAW,IAA+C,KAAlCM,EAAK+M,WAAWrN,EAAW,IACxHoQ,GAAY9P,EAAK4B,MAAM2N,EAAY7P,GAAY,MAC/CA,GAAY,EACZ6P,EAAa7P,KAEXA,EAIN,MAAMyF,EAAY1F,EAAQC,EAAU,wBA2BtC,SAASmQ,EAASJ,GAChB,OAAOA,GAAK,IAAMA,GAAK,GAAKA,EAAI,GAC9BA,GAAK,IAAMA,GAAK,GAAKA,EAAI,GACzBA,GAAK,IAAMA,GAAK,IAAMA,EAAI,IACzB,EASL,SAASR,EAASxP,EAAQa,EAAOT,EAAM+O,EAAKlG,GAC1C,MAAM1I,EAAOP,EAAOO,KACd2O,EAAa3O,EAAKE,OACxB,IAAIR,EAAWY,EAAQ,EACnBgO,EAAO,EAEX,KAAO5O,IAAaiP,IAAeJ,MAAMD,EAAOtO,EAAK+M,WAAWrN,MAAwB,KAAT4O,GAC/EA,GAAQ,IAAMA,GAAQ,IACtBA,GAAQ,IAAMA,GAAQ,IACtBA,GAAQ,IAAMA,GAAQ,QAElB5O,EAGJ,OAAO,IAAI8I,MAAMM,EAAUvD,KAAMjF,EAAOZ,EAAUG,EAAM+O,EAAKlG,EAAM1I,EAAK4B,MAAMtB,EAAOZ,ICvoBhF,SAASqQ,EAAMtQ,EAAQuQ,GAE5B,OADe,IAAIC,OAAOxQ,EAAQuQ,GACpBE,gBAkDT,MAAMD,OACXnN,YAAYrD,EAAQuQ,GAClB,MAAMG,EJhCH,SAAkB1Q,GACvB,OAAO2Q,EAAW3Q,EAAQmM,QI+BNyE,CAAS5Q,GAAUA,EAAS,IAAImM,OAAOnM,GACzD2E,KAAKkM,OAAS,IAAIzC,MAAMsC,GACxB/L,KAAKmM,SAAWP,EAOlBQ,YACE,MAAMxC,EAAQ5J,KAAKqM,YAAY3H,EAAUvD,MACzC,MAAO,CACLkD,KAAMpD,EAAKE,KACXhG,MAAOyO,EAAMzO,MACbkE,IAAKW,KAAKX,IAAIuK,IASlBkC,gBACE,MAAM5P,EAAQ8D,KAAKkM,OAAOtC,MAC1B,MAAO,CACLvF,KAAMpD,EAAKG,SACXkL,YAAatM,KAAKuM,KAAK7H,EAAUC,IAAK3E,KAAKwM,gBAAiB9H,EAAUE,KACtEvF,IAAKW,KAAKX,IAAInD,IAelBsQ,kBACE,GAAIxM,KAAKyM,KAAK/H,EAAUvD,MACtB,OAAQnB,KAAKkM,OAAOtC,MAAMzO,OACxB,IAAK,QACL,IAAK,WACL,IAAK,eACH,OAAO6E,KAAK0M,2BAEd,IAAK,WACH,OAAO1M,KAAK2M,0BAEd,IAAK,SACL,IAAK,SACL,IAAK,OACL,IAAK,YACL,IAAK,QACL,IAAK,OACL,IAAK,QACL,IAAK,YACH,OAAO3M,KAAK4M,4BAEd,IAAK,SACH,OAAO5M,KAAK6M,+BAEX,CAAA,GAAI7M,KAAKyM,KAAK/H,EAAUc,SAC7B,OAAOxF,KAAK0M,2BACP,GAAI1M,KAAK8M,kBACd,OAAO9M,KAAK4M,4BAGd,MAAM5M,KAAK+M,aAUbL,2BACE,MAAMxQ,EAAQ8D,KAAKkM,OAAOtC,MAE1B,GAAI5J,KAAKyM,KAAK/H,EAAUc,SACtB,MAAO,CACLnB,KAAMpD,EAAKI,qBACX2L,UAAW,QACXnQ,UAAMkB,EACNkP,oBAAqB,GACrBC,WAAY,GACZC,aAAcnN,KAAKoN,oBACnB/N,IAAKW,KAAKX,IAAInD,IAIlB,MAAM8Q,EAAYhN,KAAKqN,qBACvB,IAAIxQ,EAMJ,OAJImD,KAAKyM,KAAK/H,EAAUvD,QACtBtE,EAAOmD,KAAKoM,aAGP,CACL/H,KAAMpD,EAAKI,qBACX2L,UAAAA,EACAnQ,KAAAA,EACAoQ,oBAAqBjN,KAAKsN,2BAC1BJ,WAAYlN,KAAKuN,iBAAgB,GACjCJ,aAAcnN,KAAKoN,oBACnB/N,IAAKW,KAAKX,IAAInD,IAQlBmR,qBACE,MAAMG,EAAiBxN,KAAKqM,YAAY3H,EAAUvD,MAElD,OAAQqM,EAAerS,OACrB,IAAK,QACH,MAAO,QAET,IAAK,WACH,MAAO,WAET,IAAK,eACH,MAAO,eAGX,MAAM6E,KAAK+M,WAAWS,GAOxBF,2BACE,OAAOtN,KAAKyN,aAAa/I,EAAUM,QAAShF,KAAK0N,wBAAyBhJ,EAAUO,SAOtFyI,0BACE,MAAMxR,EAAQ8D,KAAKkM,OAAOtC,MAC1B,MAAO,CACLvF,KAAMpD,EAAKK,oBACXqM,SAAU3N,KAAK4N,gBACfC,MAAO7N,KAAKqM,YAAY3H,EAAUS,OAAQnF,KAAK8N,sBAC/CC,aAAc/N,KAAKgO,oBAAoBtJ,EAAUU,QAAUpF,KAAKiO,mBAAkB,QAAQlQ,EAC1FmP,WAAYlN,KAAKuN,iBAAgB,GACjClO,IAAKW,KAAKX,IAAInD,IAQlB0R,gBACE,MAAM1R,EAAQ8D,KAAKkM,OAAOtC,MAE1B,OADA5J,KAAKqM,YAAY3H,EAAUI,QACpB,CACLT,KAAMpD,EAAKY,SACXhF,KAAMmD,KAAKoM,YACX/M,IAAKW,KAAKX,IAAInD,IAQlBkR,oBACE,MAAMlR,EAAQ8D,KAAKkM,OAAOtC,MAC1B,MAAO,CACLvF,KAAMpD,EAAKM,cACX2M,WAAYlO,KAAKuM,KAAK7H,EAAUc,QAASxF,KAAKmO,eAAgBzJ,EAAUgB,SACxErG,IAAKW,KAAKX,IAAInD,IAWlBiS,iBACE,OAAOnO,KAAKyM,KAAK/H,EAAUQ,QAAUlF,KAAKoO,gBAAkBpO,KAAKqO,aASnEA,aACE,MAAMnS,EAAQ8D,KAAKkM,OAAOtC,MACpB0E,EAActO,KAAKoM,YACzB,IAAImC,EACA1R,EASJ,OAPImD,KAAKgO,oBAAoBtJ,EAAUS,QACrCoJ,EAAQD,EACRzR,EAAOmD,KAAKoM,aAEZvP,EAAOyR,EAGF,CACLjK,KAAMpD,EAAKO,MACX+M,MAAAA,EACA1R,KAAAA,EACA2R,UAAWxO,KAAKyO,gBAAe,GAC/BvB,WAAYlN,KAAKuN,iBAAgB,GACjCJ,aAAcnN,KAAKyM,KAAK/H,EAAUc,SAAWxF,KAAKoN,yBAAsBrP,EACxEsB,IAAKW,KAAKX,IAAInD,IAQlBuS,eAAeC,GACb,MAAMC,EAAOD,EAAU1O,KAAK4O,mBAAqB5O,KAAK6O,cACtD,OAAO7O,KAAKyN,aAAa/I,EAAUM,QAAS2J,EAAMjK,EAAUO,SAO9D4J,gBACE,MAAM3S,EAAQ8D,KAAKkM,OAAOtC,MACpB/M,EAAOmD,KAAKoM,YAElB,OADApM,KAAKqM,YAAY3H,EAAUS,OACpB,CACLd,KAAMpD,EAAKQ,SACX5E,KAAAA,EACA1B,MAAO6E,KAAKiO,mBAAkB,GAC9B5O,IAAKW,KAAKX,IAAInD,IAIlB0S,qBACE,MAAM1S,EAAQ8D,KAAKkM,OAAOtC,MAC1B,MAAO,CACLvF,KAAMpD,EAAKQ,SACX5E,KAAMmD,KAAKoM,YACXjR,OAAQ6E,KAAKqM,YAAY3H,EAAUS,OAAQnF,KAAKiO,mBAAkB,IAClE5O,IAAKW,KAAKX,IAAInD,IAalBkS,gBACE,MAAMlS,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKqM,YAAY3H,EAAUQ,QAC3B,MAAM4J,EAAmB9O,KAAK+O,sBAAsB,MAEpD,OAAKD,GAAoB9O,KAAKyM,KAAK/H,EAAUvD,MACpC,CACLkD,KAAMpD,EAAKS,gBACX7E,KAAMmD,KAAKgP,oBACX9B,WAAYlN,KAAKuN,iBAAgB,GACjClO,IAAKW,KAAKX,IAAInD,IAIX,CACLmI,KAAMpD,EAAKU,gBACXsN,cAAeH,EAAmB9O,KAAKkP,sBAAmBnR,EAC1DmP,WAAYlN,KAAKuN,iBAAgB,GACjCJ,aAAcnN,KAAKoN,oBACnB/N,IAAKW,KAAKX,IAAInD,IAWlByQ,0BACE,MAAMzQ,EAAQ8D,KAAKkM,OAAOtC,MAK1B,OAJA5J,KAAKmP,cAAc,aAIkC,IAAjDnP,KAAKmM,UAAUiD,8BACV,CACL/K,KAAMpD,EAAKW,oBACX/E,KAAMmD,KAAKgP,oBACX/B,oBAAqBjN,KAAKsN,2BAC1B2B,eAAgBjP,KAAKmP,cAAc,MAAOnP,KAAKkP,kBAC/ChC,WAAYlN,KAAKuN,iBAAgB,GACjCJ,aAAcnN,KAAKoN,oBACnB/N,IAAKW,KAAKX,IAAInD,IAIX,CACLmI,KAAMpD,EAAKW,oBACX/E,KAAMmD,KAAKgP,oBACXC,eAAgBjP,KAAKmP,cAAc,MAAOnP,KAAKkP,kBAC/ChC,WAAYlN,KAAKuN,iBAAgB,GACjCJ,aAAcnN,KAAKoN,oBACnB/N,IAAKW,KAAKX,IAAInD,IAQlB8S,oBACE,GAAgC,OAA5BhP,KAAKkM,OAAOtC,MAAMzO,MACpB,MAAM6E,KAAK+M,aAGb,OAAO/M,KAAKoM,YAuBd6B,kBAAkBS,GAChB,MAAM9E,EAAQ5J,KAAKkM,OAAOtC,MAE1B,OAAQA,EAAMvF,MACZ,KAAKK,EAAUY,UACb,OAAOtF,KAAKqP,UAAUX,GAExB,KAAKhK,EAAUc,QACb,OAAOxF,KAAKsP,YAAYZ,GAE1B,KAAKhK,EAAU5C,IAGb,OAFA9B,KAAKkM,OAAOpC,UAEL,CACLzF,KAAMpD,EAAKa,IACX3G,MAAOyO,EAAMzO,MACbkE,IAAKW,KAAKX,IAAIuK,IAGlB,KAAKlF,EAAU3C,MAGb,OAFA/B,KAAKkM,OAAOpC,UAEL,CACLzF,KAAMpD,EAAKc,MACX5G,MAAOyO,EAAMzO,MACbkE,IAAKW,KAAKX,IAAIuK,IAGlB,KAAKlF,EAAU1C,OACf,KAAK0C,EAAUiB,aACb,OAAO3F,KAAKuP,qBAEd,KAAK7K,EAAUvD,KAGb,OAFAnB,KAAKkM,OAAOpC,UAEJF,EAAMzO,OACZ,IAAK,OACH,MAAO,CACLkJ,KAAMpD,EAAKgB,QACX9G,OAAO,EACPkE,IAAKW,KAAKX,IAAIuK,IAGlB,IAAK,QACH,MAAO,CACLvF,KAAMpD,EAAKgB,QACX9G,OAAO,EACPkE,IAAKW,KAAKX,IAAIuK,IAGlB,IAAK,OACH,MAAO,CACLvF,KAAMpD,EAAKiB,KACX7C,IAAKW,KAAKX,IAAIuK,IAGlB,QACE,MAAO,CACLvF,KAAMpD,EAAKkB,KACXhH,MAAOyO,EAAMzO,MACbkE,IAAKW,KAAKX,IAAIuK,IAItB,KAAKlF,EAAUI,OACb,IAAK4J,EACH,OAAO1O,KAAK4N,gBAMlB,MAAM5N,KAAK+M,aAGbwC,qBACE,MAAM3F,EAAQ5J,KAAKkM,OAAOtC,MAI1B,OAFA5J,KAAKkM,OAAOpC,UAEL,CACLzF,KAAMpD,EAAKe,OACX7G,MAAOyO,EAAMzO,MACbqU,MAAO5F,EAAMvF,OAASK,EAAUiB,aAChCtG,IAAKW,KAAKX,IAAIuK,IAUlByF,UAAUX,GACR,MAAMxS,EAAQ8D,KAAKkM,OAAOtC,MAI1B,MAAO,CACLvF,KAAMpD,EAAKmB,KACXqN,OAAQzP,KAAK0P,IAAIhL,EAAUY,WAJhB,IAAMtF,KAAKiO,kBAAkBS,IAIIhK,EAAUa,WACtDlG,IAAKW,KAAKX,IAAInD,IAUlBoT,YAAYZ,GACV,MAAMxS,EAAQ8D,KAAKkM,OAAOtC,MAI1B,MAAO,CACLvF,KAAMpD,EAAKoB,OACXsN,OAAQ3P,KAAK0P,IAAIhL,EAAUc,SAJhB,IAAMxF,KAAK4P,iBAAiBlB,IAIGhK,EAAUgB,SACpDrG,IAAKW,KAAKX,IAAInD,IAQlB0T,iBAAiBlB,GACf,MAAMxS,EAAQ8D,KAAKkM,OAAOtC,MACpB/M,EAAOmD,KAAKoM,YAElB,OADApM,KAAKqM,YAAY3H,EAAUS,OACpB,CACLd,KAAMpD,EAAKqB,aACXzF,KAAAA,EACA1B,MAAO6E,KAAKiO,kBAAkBS,GAC9BrP,IAAKW,KAAKX,IAAInD,IASlBqR,gBAAgBmB,GACd,MAAMxB,EAAa,GAEnB,KAAOlN,KAAKyM,KAAK/H,EAAUW,KACzB6H,EAAW3P,KAAKyC,KAAK6P,eAAenB,IAGtC,OAAOxB,EAOT2C,eAAenB,GACb,MAAMxS,EAAQ8D,KAAKkM,OAAOtC,MAE1B,OADA5J,KAAKqM,YAAY3H,EAAUW,IACpB,CACLhB,KAAMpD,EAAKsB,UACX1F,KAAMmD,KAAKoM,YACXoC,UAAWxO,KAAKyO,eAAeC,GAC/BrP,IAAKW,KAAKX,IAAInD,IAYlB4R,qBACE,MAAM5R,EAAQ8D,KAAKkM,OAAOtC,MAC1B,IAAIiE,EAcJ,OAZI7N,KAAKgO,oBAAoBtJ,EAAUY,YACrCuI,EAAO7N,KAAK8N,qBACZ9N,KAAKqM,YAAY3H,EAAUa,WAC3BsI,EAAO,CACLxJ,KAAMpD,EAAKwB,UACXoL,KAAAA,EACAxO,IAAKW,KAAKX,IAAInD,KAGhB2R,EAAO7N,KAAKkP,iBAGVlP,KAAKgO,oBAAoBtJ,EAAUG,MAC9B,CACLR,KAAMpD,EAAKyB,cACXmL,KAAAA,EACAxO,IAAKW,KAAKX,IAAInD,IAIX2R,EAOTqB,iBACE,MAAMhT,EAAQ8D,KAAKkM,OAAOtC,MAC1B,MAAO,CACLvF,KAAMpD,EAAKuB,WACX3F,KAAMmD,KAAKoM,YACX/M,IAAKW,KAAKX,IAAInD,IAoBlB0Q,4BAEE,MAAMkD,EAAe9P,KAAK8M,kBAAoB9M,KAAKkM,OAAOnC,YAAc/J,KAAKkM,OAAOtC,MAEpF,GAAIkG,EAAazL,OAASK,EAAUvD,KAClC,OAAQ2O,EAAa3U,OACnB,IAAK,SACH,OAAO6E,KAAK+P,wBAEd,IAAK,SACH,OAAO/P,KAAKgQ,4BAEd,IAAK,OACH,OAAOhQ,KAAKiQ,4BAEd,IAAK,YACH,OAAOjQ,KAAKkQ,+BAEd,IAAK,QACH,OAAOlQ,KAAKmQ,2BAEd,IAAK,OACH,OAAOnQ,KAAKoQ,0BAEd,IAAK,QACH,OAAOpQ,KAAKqQ,iCAEd,IAAK,YACH,OAAOrQ,KAAKsQ,2BAIlB,MAAMtQ,KAAK+M,WAAW+C,GAGxBhD,kBACE,OAAO9M,KAAKyM,KAAK/H,EAAU1C,SAAWhC,KAAKyM,KAAK/H,EAAUiB,cAO5D4K,mBACE,GAAIvQ,KAAK8M,kBACP,OAAO9M,KAAKuP,qBAQhBQ,wBACE,MAAM7T,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,UACnB,MAAMjC,EAAalN,KAAKuN,iBAAgB,GAClCiD,EAAiBxQ,KAAKuM,KAAK7H,EAAUc,QAASxF,KAAKyQ,6BAA8B/L,EAAUgB,SACjG,MAAO,CACLrB,KAAMpD,EAAK0B,kBACX3B,YAAAA,EACAkM,WAAAA,EACAsD,eAAAA,EACAnR,IAAKW,KAAKX,IAAInD,IAQlBuU,+BACE,MAAMvU,EAAQ8D,KAAKkM,OAAOtC,MACpBoD,EAAYhN,KAAKqN,qBACvBrN,KAAKqM,YAAY3H,EAAUS,OAC3B,MAAM0I,EAAO7N,KAAKkP,iBAClB,MAAO,CACL7K,KAAMpD,EAAK2B,0BACXoK,UAAAA,EACAa,KAAAA,EACAxO,IAAKW,KAAKX,IAAInD,IAQlB8T,4BACE,MAAM9T,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,UACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GACxC,MAAO,CACLlJ,KAAMpD,EAAK4B,uBACX7B,YAAAA,EACAnE,KAAAA,EACAqQ,WAAAA,EACA7N,IAAKW,KAAKX,IAAInD,IAUlB+T,4BACE,MAAM/T,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,QACnB,MAAMtS,EAAOmD,KAAKoM,YACZsE,EAAa1Q,KAAK2Q,4BAClBzD,EAAalN,KAAKuN,iBAAgB,GAClCoC,EAAS3P,KAAK4Q,wBACpB,MAAO,CACLvM,KAAMpD,EAAK6B,uBACX9B,YAAAA,EACAnE,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,EACAtQ,IAAKW,KAAKX,IAAInD,IAUlByU,4BACE,OAAO3Q,KAAK+O,sBAAsB,cAAgB/O,KAAK6Q,cAAcnM,EAAUK,IAAK/E,KAAKkP,gBAAkB,GAO7G0B,wBACE,OAAO5Q,KAAKyN,aAAa/I,EAAUc,QAASxF,KAAK8Q,qBAAsBpM,EAAUgB,SAQnFoL,uBACE,MAAM5U,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACnB1T,EAAOmD,KAAKoM,YACZ2E,EAAO/Q,KAAKgR,oBAClBhR,KAAKqM,YAAY3H,EAAUS,OAC3B,MAAM0I,EAAO7N,KAAK8N,qBACZZ,EAAalN,KAAKuN,iBAAgB,GACxC,MAAO,CACLlJ,KAAMpD,EAAK8B,iBACX/B,YAAAA,EACAnE,KAAAA,EACA2R,UAAWuC,EACXlD,KAAAA,EACAX,WAAAA,EACA7N,IAAKW,KAAKX,IAAInD,IAQlB8U,oBACE,OAAOhR,KAAKyN,aAAa/I,EAAUM,QAAShF,KAAKiR,mBAAoBvM,EAAUO,SAQjFgM,qBACE,MAAM/U,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACnB1T,EAAOmD,KAAKoM,YAClBpM,KAAKqM,YAAY3H,EAAUS,OAC3B,MAAM0I,EAAO7N,KAAK8N,qBAClB,IAAIC,EAEA/N,KAAKgO,oBAAoBtJ,EAAUU,UACrC2I,EAAe/N,KAAKiO,mBAAkB,IAGxC,MAAMf,EAAalN,KAAKuN,iBAAgB,GACxC,MAAO,CACLlJ,KAAMpD,EAAK+B,uBACXhC,YAAAA,EACAnE,KAAAA,EACAgR,KAAAA,EACAE,aAAAA,EACAb,WAAAA,EACA7N,IAAKW,KAAKX,IAAInD,IASlBgU,+BACE,MAAMhU,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,aACnB,MAAMtS,EAAOmD,KAAKoM,YACZsE,EAAa1Q,KAAK2Q,4BAClBzD,EAAalN,KAAKuN,iBAAgB,GAClCoC,EAAS3P,KAAK4Q,wBACpB,MAAO,CACLvM,KAAMpD,EAAKgC,0BACXjC,YAAAA,EACAnE,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,EACAtQ,IAAKW,KAAKX,IAAInD,IASlBiU,2BACE,MAAMjU,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,SACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAClC2D,EAAQlR,KAAKmR,wBACnB,MAAO,CACL9M,KAAMpD,EAAKiC,sBACXlC,YAAAA,EACAnE,KAAAA,EACAqQ,WAAAA,EACAgE,MAAAA,EACA7R,IAAKW,KAAKX,IAAInD,IAUlBiV,wBACE,OAAOnR,KAAKgO,oBAAoBtJ,EAAUU,QAAUpF,KAAK6Q,cAAcnM,EAAUe,KAAMzF,KAAKkP,gBAAkB,GAQhHkB,0BACE,MAAMlU,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,QACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAClCkC,EAASzP,KAAKoR,4BACpB,MAAO,CACL/M,KAAMpD,EAAKkC,qBACXnC,YAAAA,EACAnE,KAAAA,EACAqQ,WAAAA,EACAuC,OAAAA,EACApQ,IAAKW,KAAKX,IAAInD,IAQlBkV,4BACE,OAAOpR,KAAKyN,aAAa/I,EAAUc,QAASxF,KAAKqR,yBAA0B3M,EAAUgB,SASvF2L,2BACE,MAAMnV,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACnB1T,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GACxC,MAAO,CACLlJ,KAAMpD,EAAKmC,sBACXpC,YAAAA,EACAnE,KAAAA,EACAqQ,WAAAA,EACA7N,IAAKW,KAAKX,IAAInD,IASlBmU,iCACE,MAAMnU,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,SACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAClCoC,EAAS3P,KAAKsR,6BACpB,MAAO,CACLjN,KAAMpD,EAAKoC,6BACXrC,YAAAA,EACAnE,KAAAA,EACAqQ,WAAAA,EACAyC,OAAAA,EACAtQ,IAAKW,KAAKX,IAAInD,IAQlBoV,6BACE,OAAOtR,KAAKyN,aAAa/I,EAAUc,QAASxF,KAAKiR,mBAAoBvM,EAAUgB,SAiBjFmH,2BACE,MAAMiD,EAAe9P,KAAKkM,OAAOnC,YAEjC,GAAI+F,EAAazL,OAASK,EAAUvD,KAClC,OAAQ2O,EAAa3U,OACnB,IAAK,SACH,OAAO6E,KAAKuR,uBAEd,IAAK,SACH,OAAOvR,KAAKwR,2BAEd,IAAK,OACH,OAAOxR,KAAKyR,2BAEd,IAAK,YACH,OAAOzR,KAAK0R,8BAEd,IAAK,QACH,OAAO1R,KAAK2R,0BAEd,IAAK,OACH,OAAO3R,KAAK4R,yBAEd,IAAK,QACH,OAAO5R,KAAK6R,gCAIlB,MAAM7R,KAAK+M,WAAW+C,GASxByB,uBACE,MAAMrV,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,UACnB,MAAMjC,EAAalN,KAAKuN,iBAAgB,GAClCiD,EAAiBxQ,KAAKyN,aAAa/I,EAAUc,QAASxF,KAAKyQ,6BAA8B/L,EAAUgB,SAEzG,GAA0B,IAAtBwH,EAAWpR,QAA0C,IAA1B0U,EAAe1U,OAC5C,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAKsC,iBACX2J,WAAAA,EACAsD,eAAAA,EACAnR,IAAKW,KAAKX,IAAInD,IASlBsV,2BACE,MAAMtV,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,UACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAExC,GAA0B,IAAtBL,EAAWpR,OACb,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAKuC,sBACX3G,KAAAA,EACAqQ,WAAAA,EACA7N,IAAKW,KAAKX,IAAInD,IAWlBuV,2BACE,MAAMvV,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,QACnB,MAAMtS,EAAOmD,KAAKoM,YACZsE,EAAa1Q,KAAK2Q,4BAClBzD,EAAalN,KAAKuN,iBAAgB,GAClCoC,EAAS3P,KAAK4Q,wBAEpB,GAA0B,IAAtBF,EAAW5U,QAAsC,IAAtBoR,EAAWpR,QAAkC,IAAlB6T,EAAO7T,OAC/D,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAKwC,sBACX5G,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,EACAtQ,IAAKW,KAAKX,IAAInD,IAWlBwV,8BACE,MAAMxV,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,aACnB,MAAMtS,EAAOmD,KAAKoM,YACZsE,EAAa1Q,KAAK2Q,4BAClBzD,EAAalN,KAAKuN,iBAAgB,GAClCoC,EAAS3P,KAAK4Q,wBAEpB,GAA0B,IAAtBF,EAAW5U,QAAsC,IAAtBoR,EAAWpR,QAAkC,IAAlB6T,EAAO7T,OAC/D,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAKyC,yBACX7G,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,EACAtQ,IAAKW,KAAKX,IAAInD,IAUlByV,0BACE,MAAMzV,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,SACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAClC2D,EAAQlR,KAAKmR,wBAEnB,GAA0B,IAAtBjE,EAAWpR,QAAiC,IAAjBoV,EAAMpV,OACnC,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAK0C,qBACX9G,KAAAA,EACAqQ,WAAAA,EACAgE,MAAAA,EACA7R,IAAKW,KAAKX,IAAInD,IAUlB0V,yBACE,MAAM1V,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,QACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAClCkC,EAASzP,KAAKoR,4BAEpB,GAA0B,IAAtBlE,EAAWpR,QAAkC,IAAlB2T,EAAO3T,OACpC,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAK2C,oBACX/G,KAAAA,EACAqQ,WAAAA,EACAuC,OAAAA,EACApQ,IAAKW,KAAKX,IAAInD,IAUlB2V,gCACE,MAAM3V,EAAQ8D,KAAKkM,OAAOtC,MAC1B5J,KAAKmP,cAAc,UACnBnP,KAAKmP,cAAc,SACnB,MAAMtS,EAAOmD,KAAKoM,YACZc,EAAalN,KAAKuN,iBAAgB,GAClCoC,EAAS3P,KAAKsR,6BAEpB,GAA0B,IAAtBpE,EAAWpR,QAAkC,IAAlB6T,EAAO7T,OACpC,MAAMkE,KAAK+M,aAGb,MAAO,CACL1I,KAAMpD,EAAK4C,4BACXhH,KAAAA,EACAqQ,WAAAA,EACAyC,OAAAA,EACAtQ,IAAKW,KAAKX,IAAInD,IASlBoU,2BACE,MAAMpU,EAAQ8D,KAAKkM,OAAOtC,MACpB5I,EAAchB,KAAKuQ,mBACzBvQ,KAAKmP,cAAc,aACnBnP,KAAKqM,YAAY3H,EAAUW,IAC3B,MAAMxI,EAAOmD,KAAKoM,YACZ2E,EAAO/Q,KAAKgR,oBACZc,EAAa9R,KAAK+O,sBAAsB,cAC9C/O,KAAKmP,cAAc,MACnB,MAAMhP,EAAYH,KAAK+R,0BACvB,MAAO,CACL1N,KAAMpD,EAAKqC,qBACXtC,YAAAA,EACAnE,KAAAA,EACA2R,UAAWuC,EACXe,WAAAA,EACA3R,UAAAA,EACAd,IAAKW,KAAKX,IAAInD,IAUlB6V,0BACE,OAAO/R,KAAK6Q,cAAcnM,EAAUe,KAAMzF,KAAKgS,wBA+BjDA,yBACE,MAAM9V,EAAQ8D,KAAKkM,OAAOtC,MACpB/M,EAAOmD,KAAKoM,YAElB,QAAsCrO,IAAlC0J,EAAkB5K,EAAK1B,OACzB,OAAO0B,EAGT,MAAMmD,KAAK+M,WAAW7Q,GAQxBmD,IAAI0E,GACF,IAAkC,IAA9B/D,KAAKmM,UAAU8F,WACjB,OAAO,IAAInO,SAASC,EAAY/D,KAAKkM,OAAOvC,UAAW3J,KAAKkM,OAAO7Q,QAQvEoR,KAAKpI,GACH,OAAOrE,KAAKkM,OAAOtC,MAAMvF,OAASA,EAQpCgI,YAAYhI,GACV,MAAMuF,EAAQ5J,KAAKkM,OAAOtC,MAE1B,GAAIA,EAAMvF,OAASA,EAGjB,OAFArE,KAAKkM,OAAOpC,UAELF,EAGT,MAAM7I,EAAYf,KAAKkM,OAAO7Q,OAAQuO,EAAM1N,MAAO,YAAYgW,EAAiB7N,aAAgB8N,EAAavI,OAQ/GoE,oBAAoB3J,GAClB,MAAMuF,EAAQ5J,KAAKkM,OAAOtC,MAE1B,GAAIA,EAAMvF,OAASA,EAGjB,OAFArE,KAAKkM,OAAOpC,UAELF,EAWXuF,cAAchU,GACZ,MAAMyO,EAAQ5J,KAAKkM,OAAOtC,MAE1B,GAAIA,EAAMvF,OAASK,EAAUvD,MAAQyI,EAAMzO,QAAUA,EAGnD,MAAM4F,EAAYf,KAAKkM,OAAO7Q,OAAQuO,EAAM1N,MAAO,aAAaf,aAAiBgX,EAAavI,OAF9F5J,KAAKkM,OAAOpC,UAWhBiF,sBAAsB5T,GACpB,MAAMyO,EAAQ5J,KAAKkM,OAAOtC,MAE1B,OAAIA,EAAMvF,OAASK,EAAUvD,MAAQyI,EAAMzO,QAAUA,IACnD6E,KAAKkM,OAAOpC,WAEL,GAUXiD,WAAWqF,GACT,MAAMxI,EAAQwI,GAAWpS,KAAKkM,OAAOtC,MACrC,OAAO7I,EAAYf,KAAKkM,OAAO7Q,OAAQuO,EAAM1N,MAAO,cAAciW,EAAavI,OASjF8F,IAAI2C,EAAUC,EAASC,GACrBvS,KAAKqM,YAAYgG,GACjB,MAAMzT,EAAQ,GAEd,MAAQoB,KAAKgO,oBAAoBuE,IAC/B3T,EAAMrB,KAAK+U,EAAQxL,KAAK9G,OAG1B,OAAOpB,EAUT6O,aAAa4E,EAAUC,EAASC,GAC9B,GAAIvS,KAAKgO,oBAAoBqE,GAAW,CACtC,MAAMzT,EAAQ,GAEd,GACEA,EAAMrB,KAAK+U,EAAQxL,KAAK9G,cAChBA,KAAKgO,oBAAoBuE,IAEnC,OAAO3T,EAGT,MAAO,GAST2N,KAAK8F,EAAUC,EAASC,GACtBvS,KAAKqM,YAAYgG,GACjB,MAAMzT,EAAQ,GAEd,GACEA,EAAMrB,KAAK+U,EAAQxL,KAAK9G,cAChBA,KAAKgO,oBAAoBuE,IAEnC,OAAO3T,EASTiS,cAAc2B,EAAeF,GAC3BtS,KAAKgO,oBAAoBwE,GACzB,MAAM5T,EAAQ,GAEd,GACEA,EAAMrB,KAAK+U,EAAQxL,KAAK9G,aACjBA,KAAKgO,oBAAoBwE,IAElC,OAAO5T,GAQX,SAASuT,EAAavI,GACpB,MAAMzO,EAAQyO,EAAMzO,MACpB,OAAO+W,EAAiBtI,EAAMvF,OAAkB,MAATlJ,EAAgB,KAAKA,KAAW,IAOzE,SAAS+W,EAAiB7N,GACxB,ODt5CK,SAA+BA,GACpC,OAAOA,IAASK,EAAUG,MAAQR,IAASK,EAAUI,QAAUT,IAASK,EAAUK,KAAOV,IAASK,EAAUM,SAAWX,IAASK,EAAUO,SAAWZ,IAASK,EAAUQ,QAAUb,IAASK,EAAUS,OAASd,IAASK,EAAUU,QAAUf,IAASK,EAAUW,IAAMhB,IAASK,EAAUY,WAAajB,IAASK,EAAUa,WAAalB,IAASK,EAAUc,SAAWnB,IAASK,EAAUe,MAAQpB,IAASK,EAAUgB,QCq5CzY+M,CAAsBpO,GAAQ,IAAIA,KAAUA,ECt9C9C,MAAMqO,EAAoB,CAC/BC,KAAM,GACNC,SAAU,CAAC,eACXC,oBAAqB,CAAC,OAAQ,sBAAuB,aAAc,gBACnEC,mBAAoB,CAAC,WAAY,OAAQ,eAAgB,cACzDC,SAAU,CAAC,QACXC,aAAc,CAAC,cACfC,MAAO,CAAC,QAAS,OAAQ,YAAa,aAAc,gBACpDC,SAAU,CAAC,OAAQ,SACnBC,eAAgB,CAAC,OAAQ,cACzBC,eAAgB,CAAC,gBAAiB,aAAc,gBAChDC,mBAAoB,CAAC,OAErB,sBAAuB,gBAAiB,aAAc,gBACtDC,SAAU,GACVC,WAAY,GACZC,YAAa,GACbC,aAAc,GACdC,UAAW,GACXC,UAAW,GACXC,UAAW,CAAC,UACZC,YAAa,CAAC,UACdC,YAAa,CAAC,OAAQ,SACtBC,UAAW,CAAC,OAAQ,aACpBC,UAAW,CAAC,QACZC,SAAU,CAAC,QACXC,YAAa,CAAC,QACdC,iBAAkB,CAAC,cAAe,aAAc,kBAChDC,wBAAyB,CAAC,QAC1BC,qBAAsB,CAAC,cAAe,OAAQ,cAC9CC,qBAAsB,CAAC,cAAe,OAAQ,aAAc,aAAc,UAC1EC,gBAAiB,CAAC,cAAe,OAAQ,YAAa,OAAQ,cAC9DC,qBAAsB,CAAC,cAAe,OAAQ,OAAQ,eAAgB,cACtEC,wBAAyB,CAAC,cAAe,OAAQ,aAAc,aAAc,UAC7EC,oBAAqB,CAAC,cAAe,OAAQ,aAAc,SAC3DC,mBAAoB,CAAC,cAAe,OAAQ,aAAc,UAC1DC,oBAAqB,CAAC,cAAe,OAAQ,cAC7CC,0BAA2B,CAAC,cAAe,OAAQ,aAAc,UACjEC,oBAAqB,CAAC,cAAe,OAAQ,YAAa,aAC1DC,gBAAiB,CAAC,aAAc,kBAChCC,oBAAqB,CAAC,OAAQ,cAC9BC,oBAAqB,CAAC,OAAQ,aAAc,aAAc,UAC1DC,uBAAwB,CAAC,OAAQ,aAAc,aAAc,UAC7DC,mBAAoB,CAAC,OAAQ,aAAc,SAC3CC,kBAAmB,CAAC,OAAQ,aAAc,UAC1CC,yBAA0B,CAAC,OAAQ,aAAc,WAEtCC,EAAQxV,OAAOoB,OAAO,IAwF5B,SAASqU,EAAMC,EAAMC,EAASC,EAAchD,GAEjD,IAAItS,EAKAV,EACAuH,EACA0O,EANAC,EAAUrX,MAAMY,QAAQqW,GACxB7O,EAAO,CAAC6O,GACR3Z,GAAS,EACTga,EAAQ,GAIZ,MAAM/W,EAAO,GACPgX,EAAY,GAClB,IAAIC,EAAUP,EAGd,EAAG,CACD3Z,IACA,MAAMma,EAAYna,IAAU8K,EAAK7K,OAC3Bma,EAAWD,GAA8B,IAAjBH,EAAM/Z,OAEpC,GAAIka,EAAW,CAKb,GAJA/O,EAA2B,IAArB6O,EAAUha,YAAeiC,EAAYe,EAAKA,EAAKhD,OAAS,GAC9D4D,EAAOiW,EACPA,EAASG,EAAUI,MAEfD,EAAU,CACZ,GAAIL,EACFlW,EAAOA,EAAKlC,YACP,CACL,MAAM2Y,EAAQ,GAEd,IAAK,MAAMC,KAAKtW,OAAO6G,KAAKjH,GAC1ByW,EAAMC,GAAK1W,EAAK0W,GAGlB1W,EAAOyW,EAGT,IAAIE,EAAa,EAEjB,IAAK,IAAIC,EAAK,EAAGA,EAAKT,EAAM/Z,OAAQwa,IAAM,CACxC,IAAIC,EAAUV,EAAMS,GAAI,GACxB,MAAME,EAAYX,EAAMS,GAAI,GAExBV,IACFW,GAAWF,GAGTT,GAAyB,OAAdY,GACb9W,EAAK+W,OAAOF,EAAS,GACrBF,KAEA3W,EAAK6W,GAAWC,GAKtB3a,EAAQuE,EAAMvE,MACd8K,EAAOvG,EAAMuG,KACbkP,EAAQzV,EAAMyV,MACdD,EAAUxV,EAAMwV,QAChBxV,EAAQA,EAAMkE,SACT,CAIL,GAHA2C,EAAM0O,EAASC,EAAU/Z,EAAQ8K,EAAK9K,QAASkC,EAC/C2B,EAAOiW,EAASA,EAAO1O,GAAO8O,EAE1BrW,MAAAA,EACF,SAGEiW,GACF7W,EAAKvB,KAAK0J,GAId,IAAIuC,EAEJ,IAAKjL,MAAMY,QAAQO,GAAO,CACxB,IAAK8E,EAAO9E,GACV,MAAM,IAAIjB,MAAM,qBAAqBoH,EAAQnG,OAG/C,MAAMgX,EAAUC,EAAWlB,EAAS/V,EAAK2E,KAAM2R,GAE/C,GAAIU,EAAS,CAGX,GAFAlN,EAASkN,EAAQ5P,KAAK2O,EAAS/V,EAAMuH,EAAK0O,EAAQ7W,EAAMgX,GAEpDtM,IAAW8L,EACb,MAGF,IAAe,IAAX9L,GACF,IAAKwM,EAAW,CACdlX,EAAKoX,MACL,eAEG,QAAenY,IAAXyL,IACTqM,EAAMtY,KAAK,CAAC0J,EAAKuC,KAEZwM,GAAW,CACd,IAAIxR,EAAOgF,GAEJ,CACL1K,EAAKoX,MACL,SAHAxW,EAAO8J,SAUFzL,IAAXyL,GAAwByM,GAC1BJ,EAAMtY,KAAK,CAAC0J,EAAKvH,IAGfsW,EACFlX,EAAKoX,OAEL9V,EAAQ,CACNwV,QAAAA,EACA/Z,MAAAA,EACA8K,KAAAA,EACAkP,MAAAA,EACAvR,KAAMlE,GAERwV,EAAUrX,MAAMY,QAAQO,GACxBiH,EAAOiP,EAAUlW,EAAOgW,EAAYhW,EAAK2E,OAAS,GAClDxI,GAAS,EACTga,EAAQ,GAEJF,GACFG,EAAUvY,KAAKoY,GAGjBA,EAASjW,cAEM3B,IAAVqC,GAMT,OAJqB,IAAjByV,EAAM/Z,SACRia,EAAUF,EAAMA,EAAM/Z,OAAS,GAAG,IAG7Bia,EASF,SAASa,EAAgBC,GAC9B,MAAMC,EAAW,IAAIvY,MAAMsY,EAAS/a,QACpC,MAAO,CACLib,MAAMrX,GACJ,IAAK,IAAIpC,EAAI,EAAGA,EAAIuZ,EAAS/a,OAAQwB,IACnC,GAAmB,MAAfwZ,EAASxZ,GAAY,CACvB,MAAM0Z,EAAKL,EAAWE,EAASvZ,GAAIoC,EAAK2E,MAExC,GAEA,GAAI2S,EAAI,CACN,MAAMxN,EAASwN,EAAGC,MAAMJ,EAASvZ,GAAIkR,WAErC,IAAe,IAAXhF,EACFsN,EAASxZ,GAAKoC,OACT,GAAI8J,IAAW8L,EACpBwB,EAASxZ,GAAKgY,OACT,QAAevX,IAAXyL,EACT,OAAOA,KAOjB0N,MAAMxX,GACJ,IAAK,IAAIpC,EAAI,EAAGA,EAAIuZ,EAAS/a,OAAQwB,IACnC,GAAmB,MAAfwZ,EAASxZ,GAAY,CACvB,MAAM0Z,EAAKL,EAAWE,EAASvZ,GAAIoC,EAAK2E,MAExC,GAEA,GAAI2S,EAAI,CACN,MAAMxN,EAASwN,EAAGC,MAAMJ,EAASvZ,GAAIkR,WAErC,GAAIhF,IAAW8L,EACbwB,EAASxZ,GAAKgY,OACT,QAAevX,IAAXyL,IAAmC,IAAXA,EACjC,OAAOA,QAGFsN,EAASxZ,KAAOoC,IACzBoX,EAASxZ,GAAK,QAYjB,SAASqZ,EAAWlB,EAASpR,EAAM2R,GACxC,MAAMmB,EAAc1B,EAAQpR,GAE5B,GAAI8S,EAAa,CACf,IAAKnB,GAAoC,mBAAhBmB,EAEvB,OAAOA,EAGT,MAAMC,EAAsBpB,EAAYmB,EAAYD,MAAQC,EAAYJ,MAExE,GAAmC,mBAAxBK,EAET,OAAOA,MAEJ,CACL,MAAMC,EAAkBrB,EAAYP,EAAQyB,MAAQzB,EAAQsB,MAE5D,GAAIM,EAAiB,CACnB,GAA+B,mBAApBA,EAET,OAAOA,EAGT,MAAMC,EAAsBD,EAAgBhT,GAE5C,GAAmC,mBAAxBiT,EAET,OAAOA,ICrXf,MAAMC,EAAezX,OAAO2P,SAAW+H,GAAO1X,OAAO6G,KAAK6Q,GAAK9Z,KAAIuJ,GAAOuQ,EAAIvQ,MCA9E,MAAMwQ,EAAU,2BCAhB,MAAMC,EAAgB5X,OAAO6X,UAAYH,GAAO1X,OAAO6G,KAAK6Q,GAAK9Z,KAAIuJ,GAAO,CAACA,EAAKuQ,EAAIvQ,OCqBvE,SAAS2Q,EAAOnY,EAAMoY,GACnC,OAAOpY,EAAKD,QAAO,CAAC9B,EAAKiR,KACvBjR,EAAIma,EAAMlJ,IAASA,EACZjR,IACNoC,OAAOgY,OAAO,OCrBJ,SAASC,EAASra,EAAKsZ,GACpC,MAAMxN,EAAS1J,OAAOgY,OAAO,MAE7B,IAAK,MAAO7Q,EAAK9L,KAAUuc,EAAcha,GACvC8L,EAAOvC,GAAO+P,EAAG7b,EAAO8L,GAG1B,OAAOuC,ECZM,SAASwO,EAASR,GAE/B,GAAmC,OAA/B1X,OAAOmY,eAAeT,GACxB,OAAOA,EAGT,MAAM9Z,EAAMoC,OAAOgY,OAAO,MAE1B,IAAK,MAAO7Q,EAAK9L,KAAUuc,EAAcF,GACvC9Z,EAAIuJ,GAAO9L,EAGb,OAAOuC,ECIM,SAASwa,EAAUzY,EAAMoY,EAAOM,GAC7C,OAAO1Y,EAAKD,QAAO,CAAC9B,EAAKiR,KACvBjR,EAAIma,EAAMlJ,IAASwJ,EAAMxJ,GAClBjR,IACNoC,OAAOgY,OAAO,OCfJ,SAASM,EAAWC,EAAUC,GAC3C,MAAOC,EAAYC,GAAsC,iBAAbH,EAAwB,CAACA,EAAUC,GAAa,MAACva,EAAWsa,GACxG,IAAI1Z,EAAU,iBAEV4Z,IACF5Z,GAAW4Z,EAAa,KAG1B,MAAME,EAAcD,EAAe9a,KAAIgb,GAAK,IAAIA,OAEhD,OAAQD,EAAY3c,QAClB,KAAK,EACH,MAAO,GAET,KAAK,EACH,OAAO6C,EAAU8Z,EAAY,GAAK,IAEpC,KAAK,EACH,OAAO9Z,EAAU8Z,EAAY,GAAK,OAASA,EAAY,GAAK,IAGhE,MAAME,EAAWF,EAAYjb,MAAM,EA3Bb,GA4BhBob,EAAWD,EAASzC,MAC1B,OAAOvX,EAAUga,EAASta,KAAK,MAAQ,QAAUua,EAAW,IC1B/C,SAASC,EAAaH,GACnC,OAAOA,ECAM,SAASI,EAAeC,EAAOnN,GAC5C,MAAMoN,EAAoBlZ,OAAOgY,OAAO,MAClCmB,EAAkB,IAAIC,gBAAgBH,GACtCI,EAAYjc,KAAKC,MAAqB,GAAf4b,EAAMjd,QAAgB,EAEnD,IAAK,MAAMsd,KAAUxN,EAAS,CAC5B,MAAMyN,EAAWJ,EAAgBK,QAAQF,EAAQD,QAEhCpb,IAAbsb,IACFL,EAAkBI,GAAUC,GAIhC,OAAOvZ,OAAO6G,KAAKqS,GAAmBO,MAAK,CAAClO,EAAGC,KAC7C,MAAMkO,EAAeR,EAAkB3N,GAAK2N,EAAkB1N,GAC9D,OAAwB,IAAjBkO,EAAqBA,EAAenO,EAAEoO,cAAcnO,MAkB/D,MAAM4N,gBACJxa,YAAYqa,GACV/Y,KAAK0Z,OAASX,EACd/Y,KAAK2Z,gBAAkBZ,EAAMa,cAC7B5Z,KAAK6Z,YAAcC,EAAc9Z,KAAK2Z,iBACtC3Z,KAAK+Z,MAAQ,CAAC,IAAIxb,MAAMwa,EAAMjd,OAAS,GAAGke,KAAK,GAAI,IAAIzb,MAAMwa,EAAMjd,OAAS,GAAGke,KAAK,GAAI,IAAIzb,MAAMwa,EAAMjd,OAAS,GAAGke,KAAK,IAG3HV,QAAQF,EAAQD,GACd,GAAInZ,KAAK0Z,SAAWN,EAClB,OAAO,EAGT,MAAMa,EAAkBb,EAAOQ,cAE/B,GAAI5Z,KAAK2Z,kBAAoBM,EAC3B,OAAO,EAGT,IAAI5O,EAAIyO,EAAcG,GAClB3O,EAAItL,KAAK6Z,YAEb,GAAIxO,EAAEvP,OAASwP,EAAExP,OAAQ,CACvB,MAAMoe,EAAM7O,EACZA,EAAIC,EACJA,EAAI4O,EAGN,MAAMC,EAAU9O,EAAEvP,OACZse,EAAU9O,EAAExP,OAElB,GAAIqe,EAAUC,EAAUjB,EACtB,OAGF,MAAMkB,EAAOra,KAAK+Z,MAElB,IAAK,IAAIO,EAAI,EAAGA,GAAKF,EAASE,IAC5BD,EAAK,GAAGC,GAAKA,EAGf,IAAK,IAAIhd,EAAI,EAAGA,GAAK6c,EAAS7c,IAAK,CACjC,MAAMid,EAAQF,GAAM/c,EAAI,GAAK,GACvBkd,EAAaH,EAAK/c,EAAI,GAC5B,IAAImd,EAAeD,EAAW,GAAKld,EAEnC,IAAK,IAAIgd,EAAI,EAAGA,GAAKF,EAASE,IAAK,CACjC,MAAMI,EAAOrP,EAAE/N,EAAI,KAAOgO,EAAEgP,EAAI,GAAK,EAAI,EACzC,IAAIK,EAAczd,KAAKoJ,IAAIiU,EAAMD,GAAK,EACtCE,EAAWF,EAAI,GAAK,EACpBC,EAAMD,EAAI,GAAKI,GAGf,GAAIpd,EAAI,GAAKgd,EAAI,GAAKjP,EAAE/N,EAAI,KAAOgO,EAAEgP,EAAI,IAAMjP,EAAE/N,EAAI,KAAOgO,EAAEgP,EAAI,GAAI,CAEpE,MAAMM,EAAqBP,GAAM/c,EAAI,GAAK,GAAGgd,EAAI,GACjDK,EAAczd,KAAKoJ,IAAIqU,EAAaC,EAAqB,GAGvDD,EAAcF,IAChBA,EAAeE,GAGjBH,EAAWF,GAAKK,EAIlB,GAAIF,EAAetB,EACjB,OAIJ,MAAME,EAAWgB,EAAKF,EAAU,GAAGC,GACnC,OAAOf,GAAYF,EAAYE,OAAWtb,GAK9C,SAAS+b,EAAc1b,GACrB,MAAMyc,EAAYzc,EAAItC,OAChBuK,EAAQ,IAAI9H,MAAMsc,GAExB,IAAK,IAAIvd,EAAI,EAAGA,EAAIud,IAAavd,EAC/B+I,EAAM/I,GAAKc,EAAIuK,WAAWrL,GAG5B,OAAO+I,ECpHF,SAASyU,EAAMC,GACpB,OAAOxF,EAAMwF,EAAK,CAChB7D,MAAO8D,IAGX,MAEMA,EAAqB,CACzBrI,KAAMjT,GAAQA,EAAKvE,MACnB4X,SAAUrT,GAAQ,IAAMA,EAAK7C,KAE7B+V,SAAUlT,GAAQrB,EAAKqB,EAAK4M,YAAa,QAAU,KAEnDuG,oBAAoBnT,GAClB,MAAMub,EAAKvb,EAAKsN,UACVnQ,EAAO6C,EAAK7C,KACZqe,EAAUC,EAAK,IAAK9c,EAAKqB,EAAKuN,oBAAqB,MAAO,KAC1DC,EAAa7O,EAAKqB,EAAKwN,WAAY,KACnCC,EAAezN,EAAKyN,aAG1B,OAAQtQ,GAASqQ,GAAegO,GAAkB,UAAPD,EAAgC5c,EAAK,CAAC4c,EAAI5c,EAAK,CAACxB,EAAMqe,IAAWhO,EAAYC,GAAe,KAA3EA,GAG9D2F,mBAAoB,EAClBnF,SAAAA,EACAE,KAAAA,EACAE,aAAAA,EACAb,WAAAA,KACIS,EAAW,KAAOE,EAAOsN,EAAK,MAAOpN,GAAgBoN,EAAK,IAAK9c,EAAK6O,EAAY,MACtF8F,aAAc,EACZ9E,WAAAA,KACIsB,EAAMtB,GACZ+E,MAAO,EACL1E,MAAAA,EACA1R,KAAAA,EACA2R,UAAWuC,EACX7D,WAAAA,EACAC,aAAAA,MAEA,MAAMjP,EAASid,EAAK,GAAI5M,EAAO,MAAQ1R,EACvC,IAAIue,EAAWld,EAASid,EAAK,IAAK9c,EAAK0S,EAAM,MAAO,KAMpD,OAJIqK,EAAStf,OAtCO,KAuClBsf,EAAWld,EAASid,EAAK,MAAOzS,GAAOrK,EAAK0S,EAAM,OAAQ,QAGrD1S,EAAK,CAAC+c,EAAU/c,EAAK6O,EAAY,KAAMC,GAAe,MAE/D+F,SAAU,EACRrW,KAAAA,EACA1B,MAAAA,KACI0B,EAAO,KAAO1B,EAEpBgY,eAAgB,EACdtW,KAAAA,EACAqQ,WAAAA,KACI,MAAQrQ,EAAOse,EAAK,IAAK9c,EAAK6O,EAAY,MAChDkG,eAAgB,EACdnE,cAAAA,EACA/B,WAAAA,EACAC,aAAAA,KACI9O,EAAK,CAAC,MAAO8c,EAAK,MAAOlM,GAAgB5Q,EAAK6O,EAAY,KAAMC,GAAe,KACrFkG,mBAAoB,EAClBxW,KAAAA,EACAoS,cAAAA,EACAhC,oBAAAA,EACAC,WAAAA,EACAC,aAAAA,KAGF,YAAYtQ,IAAOse,EAAK,IAAK9c,EAAK4O,EAAqB,MAAO,WAAgBgC,KAAiBkM,EAAK,GAAI9c,EAAK6O,EAAY,KAAM,OAASC,EAExImG,SAAU,EACRnY,MAAAA,KACIA,EACNoY,WAAY,EACVpY,MAAAA,KACIA,EACNqY,YAAa,EACXrY,MAAAA,EACAqU,MAAO6L,GACNpU,IAAQoU,EAAgBrS,EAAiB7N,EAAe,gBAAR8L,EAAwB,GAAK,MAAQjB,KAAKC,UAAU9K,GACvGsY,aAAc,EACZtY,MAAAA,KACIA,EAAQ,OAAS,QACvBuY,UAAW,IAAM,OACjBC,UAAW,EACTxY,MAAAA,KACIA,EACNyY,UAAW,EACTnE,OAAAA,KACI,IAAMpR,EAAKoR,EAAQ,MAAQ,IACjCoE,YAAa,EACXlE,OAAAA,KACI,IAAMtR,EAAKsR,EAAQ,MAAQ,IACjCmE,YAAa,EACXjX,KAAAA,EACA1B,MAAAA,KACI0B,EAAO,KAAO1B,EAEpB4Y,UAAW,EACTlX,KAAAA,EACA2R,UAAWuC,KACP,IAAMlU,EAAOse,EAAK,IAAK9c,EAAK0S,EAAM,MAAO,KAE/CiD,UAAW,EACTnX,KAAAA,KACIA,EACNoX,SAAU,EACRpG,KAAAA,KACI,IAAMA,EAAO,IACnBqG,YAAa,EACXrG,KAAAA,KACIA,EAAO,IAEbsG,iBAAkBmH,GAAe,EAC/BpO,WAAAA,EACAsD,eAAAA,KACInS,EAAK,CAAC,SAAUA,EAAK6O,EAAY,KAAMsC,EAAMgB,IAAkB,OACrE4D,wBAAyB,EACvBpH,UAAAA,EACAa,KAAAA,KACIb,EAAY,KAAOa,EACzBwG,qBAAsBiH,GAAe,EACnCze,KAAAA,EACAqQ,WAAAA,KACI7O,EAAK,CAAC,SAAUxB,EAAMwB,EAAK6O,EAAY,MAAO,OACpDoH,qBAAsBgH,GAAe,EACnCze,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,KACItR,EAAK,CAAC,OAAQxB,EAAMse,EAAK,cAAe9c,EAAKqS,EAAY,QAASrS,EAAK6O,EAAY,KAAMsC,EAAMG,IAAU,OAC/G4E,gBAAiB+G,GAAe,EAC9Bze,KAAAA,EACA2R,UAAWuC,EACXlD,KAAAA,EACAX,WAAAA,KACIrQ,GAAQ0e,GAAkBxK,GAAQoK,EAAK,MAAOzS,GAAOrK,EAAK0S,EAAM,OAAQ,OAASoK,EAAK,IAAK9c,EAAK0S,EAAM,MAAO,MAAQ,KAAOlD,EAAOsN,EAAK,IAAK9c,EAAK6O,EAAY,QACpKsH,qBAAsB8G,GAAe,EACnCze,KAAAA,EACAgR,KAAAA,EACAE,aAAAA,EACAb,WAAAA,KACI7O,EAAK,CAACxB,EAAO,KAAOgR,EAAMsN,EAAK,KAAMpN,GAAe1P,EAAK6O,EAAY,MAAO,OAClFuH,wBAAyB6G,GAAe,EACtCze,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,KACItR,EAAK,CAAC,YAAaxB,EAAMse,EAAK,cAAe9c,EAAKqS,EAAY,QAASrS,EAAK6O,EAAY,KAAMsC,EAAMG,IAAU,OACpH+E,oBAAqB4G,GAAe,EAClCze,KAAAA,EACAqQ,WAAAA,EACAgE,MAAAA,KACI7S,EAAK,CAAC,QAASxB,EAAMwB,EAAK6O,EAAY,KAAMgE,GAA0B,IAAjBA,EAAMpV,OAAe,KAAOuC,EAAK6S,EAAO,OAAS,IAAK,OACjHyD,mBAAoB2G,GAAe,EACjCze,KAAAA,EACAqQ,WAAAA,EACAuC,OAAAA,KACIpR,EAAK,CAAC,OAAQxB,EAAMwB,EAAK6O,EAAY,KAAMsC,EAAMC,IAAU,OACjEmF,oBAAqB0G,GAAe,EAClCze,KAAAA,EACAqQ,WAAAA,KACI7O,EAAK,CAACxB,EAAMwB,EAAK6O,EAAY,MAAO,OAC1C2H,0BAA2ByG,GAAe,EACxCze,KAAAA,EACAqQ,WAAAA,EACAyC,OAAAA,KACItR,EAAK,CAAC,QAASxB,EAAMwB,EAAK6O,EAAY,KAAMsC,EAAMG,IAAU,OAClEmF,oBAAqBwG,GAAe,EAClCze,KAAAA,EACA2R,UAAWuC,EACXe,WAAAA,EACA3R,UAAAA,KACI,cAAgBtD,GAAQ0e,GAAkBxK,GAAQoK,EAAK,MAAOzS,GAAOrK,EAAK0S,EAAM,OAAQ,OAASoK,EAAK,IAAK9c,EAAK0S,EAAM,MAAO,OAASe,EAAa,cAAgB,IAAM,OAASzT,EAAK8B,EAAW,SACxM4U,gBAAiB,EACf7H,WAAAA,EACAsD,eAAAA,KACInS,EAAK,CAAC,gBAAiBA,EAAK6O,EAAY,KAAMsC,EAAMgB,IAAkB,KAC5EwE,oBAAqB,EACnBnY,KAAAA,EACAqQ,WAAAA,KACI7O,EAAK,CAAC,gBAAiBxB,EAAMwB,EAAK6O,EAAY,MAAO,KAC3D+H,oBAAqB,EACnBpY,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,KACItR,EAAK,CAAC,cAAexB,EAAMse,EAAK,cAAe9c,EAAKqS,EAAY,QAASrS,EAAK6O,EAAY,KAAMsC,EAAMG,IAAU,KACtHuF,uBAAwB,EACtBrY,KAAAA,EACA6T,WAAAA,EACAxD,WAAAA,EACAyC,OAAAA,KACItR,EAAK,CAAC,mBAAoBxB,EAAMse,EAAK,cAAe9c,EAAKqS,EAAY,QAASrS,EAAK6O,EAAY,KAAMsC,EAAMG,IAAU,KAC3HwF,mBAAoB,EAClBtY,KAAAA,EACAqQ,WAAAA,EACAgE,MAAAA,KACI7S,EAAK,CAAC,eAAgBxB,EAAMwB,EAAK6O,EAAY,KAAMgE,GAA0B,IAAjBA,EAAMpV,OAAe,KAAOuC,EAAK6S,EAAO,OAAS,IAAK,KACxHkE,kBAAmB,EACjBvY,KAAAA,EACAqQ,WAAAA,EACAuC,OAAAA,KACIpR,EAAK,CAAC,cAAexB,EAAMwB,EAAK6O,EAAY,KAAMsC,EAAMC,IAAU,KACxE4F,yBAA0B,EACxBxY,KAAAA,EACAqQ,WAAAA,EACAyC,OAAAA,KACItR,EAAK,CAAC,eAAgBxB,EAAMwB,EAAK6O,EAAY,KAAMsC,EAAMG,IAAU,MAG3E,SAAS2L,EAAeE,GACtB,OAAO9b,GAAQrB,EAAK,CAACqB,EAAKsB,YAAawa,EAAG9b,IAAQ,MAQpD,SAASrB,EAAKod,EAAYC,EAAY,IACpC,OAAOD,GAAY5d,QAAO6a,GAAKA,IAAGra,KAAKqd,IAAc,GAQvD,SAASlM,EAAMnJ,GACb,OAAO8U,EAAK,MAAOzS,GAAOrK,EAAKgI,EAAO,OAAQ,OAOhD,SAAS8U,EAAKjf,EAAOyf,EAAa1X,EAAM,IACtC,OAAsB,MAAf0X,GAAuC,KAAhBA,EAAqBzf,EAAQyf,EAAc1X,EAAM,GAGjF,SAASyE,GAAOtK,GACd,OAAO+c,EAAK,KAAM/c,EAAI2I,QAAQ,MAAO,SAGvC,SAAS6U,GAAYxd,GACnB,OAA8B,IAAvBA,EAAI+H,QAAQ,MAGrB,SAASoV,GAAkBE,GACzB,OAAqB,MAAdA,GAAsBA,EAAWI,KAAKD,ICpQhC,SAASE,GAAUxU,EAAW3I,GAG3C,IAFyB4I,QAAQD,GAG/B,MAAM,IAAI7I,MAAiB,MAAXE,EAAkBA,EAAU,mCCiBzC,SAASod,GAAoBC,EAAWC,GAC7C,OAAQD,EAAU3X,MAChB,KAAKpD,EAAKiB,KACR,OAAO,KAET,KAAKjB,EAAKa,IACR,OAAOoa,SAASF,EAAU7gB,MAAO,IAEnC,KAAK8F,EAAKc,MACR,OAAOoa,WAAWH,EAAU7gB,OAE9B,KAAK8F,EAAKe,OACV,KAAKf,EAAKkB,KACV,KAAKlB,EAAKgB,QACR,OAAO+Z,EAAU7gB,MAEnB,KAAK8F,EAAKmB,KACR,OAAO4Z,EAAUvM,OAAO/R,KAAIgC,GAAQqc,GAAoBrc,EAAMuc,KAEhE,KAAKhb,EAAKoB,OACR,OAAO6V,EAAU8D,EAAUrM,QAAQyM,GAASA,EAAMvf,KAAK1B,QAAOihB,GAASL,GAAoBK,EAAMjhB,MAAO8gB,KAE1G,KAAKhb,EAAKY,SACR,OAAOoa,IAAYD,EAAUnf,KAAK1B,OAI7B2gB,GAAU,EAAG,0BAA4BjW,EAAQmW,IChCrD,SAASK,GAAOxO,GACrB,OAAOyO,GAAazO,IAAS0O,GAAa1O,IAAS2O,GAAgB3O,IAAS4O,GAAY5O,IAAS6O,GAAW7O,IAAS8O,GAAkB9O,IAAS+O,GAAW/O,IAASgP,GAAchP,GAc7K,SAASyO,GAAazO,GAC3B,OAAO7B,EAAW6B,EAAMiP,mBAUnB,SAASP,GAAa1O,GAC3B,OAAO7B,EAAW6B,EAAMkP,mBAUnB,SAASP,GAAgB3O,GAC9B,OAAO7B,EAAW6B,EAAMmP,sBAUnB,SAASP,GAAY5O,GAC1B,OAAO7B,EAAW6B,EAAMoP,kBAUnB,SAASP,GAAW7O,GACzB,OAAO7B,EAAW6B,EAAMqP,iBAUnB,SAASP,GAAkB9O,GAChC,OAAO7B,EAAW6B,EAAMsP,wBAUnB,SAASP,GAAW/O,GACzB,OAAO7B,EAAW6B,EAAMuP,aAUnB,SAASP,GAAchP,GAC5B,OAAO7B,EAAW6B,EAAMwP,gBAanB,SAASC,GAAYzP,GAC1B,OAAOyO,GAAazO,IAAS6O,GAAW7O,IAAS8O,GAAkB9O,IAAS0P,GAAe1P,IAASyP,GAAYzP,EAAK2P,QAahH,SAASC,GAAa5P,GAC3B,OAAOyO,GAAazO,IAAS0O,GAAa1O,IAAS2O,GAAgB3O,IAAS4O,GAAY5O,IAAS6O,GAAW7O,IAAS0P,GAAe1P,IAAS4P,GAAa5P,EAAK2P,QAa1J,SAASE,GAAW7P,GACzB,OAAOyO,GAAazO,IAAS6O,GAAW7O,GAanC,SAAS8P,GAAgB9P,GAC9B,OAAO0O,GAAa1O,IAAS2O,GAAgB3O,IAAS4O,GAAY5O,GAa7D,SAAS+P,GAAe/P,GAC7B,OAAO2O,GAAgB3O,IAAS4O,GAAY5O,GA4BvC,MAAMuP,YACX1e,YAAY8e,GACVnB,GAAOmB,IAAWnW,EAAU,EAAG,YAAYxB,EAAQ2X,4BACnDxd,KAAKwd,OAASA,EAGhBhd,WACE,MAAO,IAAM4G,OAAOpH,KAAKwd,QAAU,IAGrCtZ,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,eAyBJ,MAAMuc,eACX3e,YAAY8e,GACVK,GAAeL,IAAWnW,EAAU,EAAG,YAAYxB,EAAQ2X,qCAC3Dxd,KAAKwd,OAASA,EAGhBhd,WACE,OAAO4G,OAAOpH,KAAKwd,QAAU,IAG/BtZ,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,kBAQJ,SAASyc,GAAe1P,GAC7B,OAAO+O,GAAW/O,IAASgP,GAAchP,GAapC,SAASgQ,GAAehQ,GAC7B,OAAOwO,GAAOxO,KAAUgP,GAAchP,GAWjC,SAASiQ,GAAgBjQ,GAE9B,GAAIA,EACF,OAAOgP,GAAchP,GAAQA,EAAK2P,OAAS3P,EAOxC,SAASkQ,GAAYlQ,GAC1B,OAAOyO,GAAazO,IAAS0O,GAAa1O,IAAS2O,GAAgB3O,IAAS4O,GAAY5O,IAAS6O,GAAW7O,IAAS8O,GAAkB9O,GAWlI,SAASmQ,GAAanQ,GAE3B,GAAIA,EAAM,CACR,IAAIoQ,EAAgBpQ,EAEpB,KAAO0P,GAAeU,IACpBA,EAAgBA,EAAcT,OAGhC,OAAOS,GAQX,SAASC,GAAaC,GAEpB,MAAwB,mBAAVA,EAAuBA,IAAUA,EAGjD,SAASC,GAAgBC,GACvB,OAAOA,GAAOA,EAAIviB,OAAS,EAAIuiB,OAAMtgB,EA4BhC,MAAM+e,kBACXpe,YAAY4f,GACV,MAAMC,EAAaD,EAAOC,YAAc1F,EACxC7Y,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKwe,eAAiBF,EAAOE,eAC7Bxe,KAAKye,UAAYH,EAAOG,WAAa5F,EACrC7Y,KAAKue,WAAaA,EAElBve,KAAK0e,aAAeJ,EAAOI,gBAAkBhf,EAAMuc,IAAcsC,EAAWxC,GAAoBrc,EAAMuc,KAEtGjc,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBR,GAAgBE,EAAOM,mBACzB,iBAAhBN,EAAOzhB,MAAqBwK,EAAU,EAAG,sBACvB,MAAzBiX,EAAOE,gBAA2D,iBAA1BF,EAAOE,gBAA+BnX,EAAU,EAAG,GAAGrH,KAAKnD,4DAAiEgJ,EAAQyY,EAAOE,oBAC/J,MAApBF,EAAOG,WAAiD,mBAArBH,EAAOG,WAA4BpX,EAAU,EAAG,GAAGrH,KAAKnD,oKAEvFyhB,EAAOI,eACoB,mBAAtBJ,EAAOC,YAA4D,mBAAxBD,EAAOI,cAA+BrX,EAAU,EAAG,GAAGrH,KAAKnD,sEAIjHgiB,WACE,MAAO,CACLhiB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClBwd,eAAgBxe,KAAKwe,eACrBC,UAAWze,KAAKye,UAChBF,WAAYve,KAAKue,WACjBG,aAAc1e,KAAK0e,aACnB1f,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,IAIjDpe,WACE,OAAOR,KAAKnD,KAGdqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,qBA0CJ,MAAMic,kBACXre,YAAY4f,GACVte,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAK8e,SAAWR,EAAOQ,SACvB9e,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBR,GAAgBE,EAAOM,mBAChD5e,KAAK+e,QAAUC,GAAeC,UAAKlhB,EAAWugB,GAC9Cte,KAAKkf,YAAcC,GAAiBF,UAAKlhB,EAAWugB,GAC7B,iBAAhBA,EAAOzhB,MAAqBwK,EAAU,EAAG,sBAC7B,MAAnBiX,EAAOQ,UAA+C,mBAApBR,EAAOQ,UAA2BzX,EAAU,EAAG,GAAGrH,KAAKnD,wDAA6DgJ,EAAQyY,EAAOQ,cAGvKM,YAKE,MAJ4B,mBAAjBpf,KAAK+e,UACd/e,KAAK+e,QAAU/e,KAAK+e,WAGf/e,KAAK+e,QAGdM,gBAKE,MAJgC,mBAArBrf,KAAKkf,cACdlf,KAAKkf,YAAclf,KAAKkf,eAGnBlf,KAAKkf,YAGdL,WACE,MAAO,CACLhiB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClB0P,WAAY1Q,KAAKqf,gBACjB1P,OAAQ2P,GAAqBtf,KAAKof,aAClCN,SAAU9e,KAAK8e,SACf9f,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,IAIjDpe,WACE,OAAOR,KAAKnD,KAGdqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,qBAKX,SAASqe,GAAiBb,GACxB,MAAM5N,EAAawN,GAAaI,EAAO5N,aAAe,GAEtD,OADAnS,MAAMY,QAAQuR,IAAerJ,EAAU,EAAG,GAAGiX,EAAOzhB,0EAC7C6T,EAGT,SAASsO,GAAeV,GACtB,MAAMiB,EAAWrB,GAAaI,EAAO3O,QAErC,OADA6P,GAAWD,IAAalY,EAAU,EAAG,GAAGiX,EAAOzhB,sGACxCkb,EAASwH,GAAU,CAACE,EAAaC,KACtCF,GAAWC,IAAgBpY,EAAU,EAAG,GAAGiX,EAAOzhB,QAAQ6iB,qCACnC,MAAvBD,EAAYE,SAAkD,mBAAxBF,EAAYE,SAA0BtY,EAAU,EAAG,GAAGiX,EAAOzhB,QAAQ6iB,6DAA0E7Z,EAAQ4Z,EAAYE,aACzM,MAAMC,EAAaH,EAAY1O,MAAQ,GACvCyO,GAAWI,IAAevY,EAAU,EAAG,GAAGiX,EAAOzhB,QAAQ6iB,yDACzD,MAAM3O,EAAO2G,EAAckI,GAAYliB,KAAI,EAAEmiB,EAASC,OACpDjjB,KAAMgjB,EACN7e,YAAa8e,EAAU9e,YACvB6M,KAAMiS,EAAUjS,KAChBE,aAAc+R,EAAU/R,aACxBgS,kBAAmBD,EAAUC,kBAC7B/gB,WAAY8gB,EAAU9gB,YAAcgZ,EAAS8H,EAAU9gB,YACvD2f,QAASmB,EAAUnB,YAErB,MAAO,CACL9hB,KAAM6iB,EACN1e,YAAaye,EAAYze,YACzB6M,KAAM4R,EAAY5R,KAClBkD,KAAAA,EACA4O,QAASF,EAAYE,QACrBK,UAAWP,EAAYO,UACvBD,kBAAmBN,EAAYM,kBAC/B/gB,WAAYygB,EAAYzgB,YAAcgZ,EAASyH,EAAYzgB,YAC3D2f,QAASc,EAAYd,YAK3B,SAASa,GAAWhI,GAClB,OAAOtc,EAAasc,KAASjZ,MAAMY,QAAQqY,GAG7C,SAAS8H,GAAqB3P,GAC5B,OAAOoI,EAASpI,GAAQyM,KACtBpb,YAAaob,EAAMpb,YACnB6M,KAAMuO,EAAMvO,KACZkD,KAAMkP,GAAiB7D,EAAMrL,MAC7B4O,QAASvD,EAAMuD,QACfK,UAAW5D,EAAM4D,UACjBD,kBAAmB3D,EAAM2D,kBACzB/gB,WAAYod,EAAMpd,WAClB2f,QAASvC,EAAMuC,YAQZ,SAASsB,GAAiBlP,GAC/B,OAAOmH,EAAUnH,GAAMmP,GAAOA,EAAIrjB,OAAMqjB,KACtClf,YAAakf,EAAIlf,YACjB6M,KAAMqS,EAAIrS,KACVE,aAAcmS,EAAInS,aAClBgS,kBAAmBG,EAAIH,kBACvB/gB,WAAYkhB,EAAIlhB,WAChB2f,QAASuB,EAAIvB,YAGV,SAASwB,GAAmBD,GACjC,OAAOrD,GAAcqD,EAAIrS,YAA8B9P,IAArBmiB,EAAInS,aAqBjC,MAAMiP,qBACXte,YAAY4f,GACVte,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKogB,YAAc9B,EAAO8B,YAC1BpgB,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBR,GAAgBE,EAAOM,mBAChD5e,KAAK+e,QAAUC,GAAeC,UAAKlhB,EAAWugB,GAC9Cte,KAAKkf,YAAcC,GAAiBF,UAAKlhB,EAAWugB,GAC7B,iBAAhBA,EAAOzhB,MAAqBwK,EAAU,EAAG,sBAC1B,MAAtBiX,EAAO8B,aAAqD,mBAAvB9B,EAAO8B,aAA8B/Y,EAAU,EAAG,GAAGrH,KAAKnD,2DAAgEgJ,EAAQyY,EAAO8B,iBAGhLhB,YAKE,MAJ4B,mBAAjBpf,KAAK+e,UACd/e,KAAK+e,QAAU/e,KAAK+e,WAGf/e,KAAK+e,QAGdM,gBAKE,MAJgC,mBAArBrf,KAAKkf,cACdlf,KAAKkf,YAAclf,KAAKkf,eAGnBlf,KAAKkf,YAGdL,WACE,MAAO,CACLhiB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClB0P,WAAY1Q,KAAKqf,gBACjB1P,OAAQ2P,GAAqBtf,KAAKof,aAClCgB,YAAapgB,KAAKogB,YAClBphB,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,IAIjDpe,WACE,OAAOR,KAAKnD,KAGdqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,wBA4BJ,MAAMmc,iBACXve,YAAY4f,GACVte,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKogB,YAAc9B,EAAO8B,YAC1BpgB,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBR,GAAgBE,EAAOM,mBAChD5e,KAAKqgB,OAASC,GAAYrB,UAAKlhB,EAAWugB,GACnB,iBAAhBA,EAAOzhB,MAAqBwK,EAAU,EAAG,sBAC1B,MAAtBiX,EAAO8B,aAAqD,mBAAvB9B,EAAO8B,aAA8B/Y,EAAU,EAAG,GAAGrH,KAAKnD,2DAAgEgJ,EAAQyY,EAAO8B,iBAGhLG,WAKE,MAJ2B,mBAAhBvgB,KAAKqgB,SACdrgB,KAAKqgB,OAASrgB,KAAKqgB,UAGdrgB,KAAKqgB,OAGdxB,WACE,MAAO,CACLhiB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClBkQ,MAAOlR,KAAKugB,WACZH,YAAapgB,KAAKogB,YAClBphB,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,IAIjDpe,WACE,OAAOR,KAAKnD,KAGdqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,oBAKX,SAASwf,GAAYhC,GACnB,MAAMpN,EAAQgN,GAAaI,EAAOpN,OAElC,OADA3S,MAAMY,QAAQ+R,IAAU7J,EAAU,EAAG,mFAAmFiX,EAAOzhB,SACxHqU,EAwBF,MAAMgM,gBAGXxe,YAAY4f,GAyGd,IAA0BkC,EAAUC,EAxGhCzgB,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBR,GAAgBE,EAAOM,mBAChD5e,KAAK0gB,SAmGiBF,EAnGUxgB,KAAKnD,KAoGvC2iB,GADkCiB,EAnGWnC,EAAO7O,SAoG5BpI,EAAU,EAAG,GAAGmZ,wDACjC9I,EAAc+I,GAAU/iB,KAAI,EAAEijB,EAAWC,MAC9CpB,GAAWoB,IAAgBvZ,EAAU,EAAG,GAAGmZ,KAAYG,wFAAqG9a,EAAQ+a,OAC7J,CACL/jB,KAAM8jB,EACN3f,YAAa4f,EAAY5f,YACzB7F,WAA6B4C,IAAtB6iB,EAAYzlB,MAAsBylB,EAAYzlB,MAAQwlB,EAC7DZ,kBAAmBa,EAAYb,kBAC/B/gB,WAAY4hB,EAAY5hB,YAAcgZ,EAAS4I,EAAY5hB,YAC3D2f,QAASiC,EAAYjC,aA5GvB3e,KAAK6gB,aAAe,IAAIC,IAAI9gB,KAAK0gB,QAAQhjB,KAAIqjB,GAAa,CAACA,EAAU5lB,MAAO4lB,MAC5E/gB,KAAKghB,YAAcpJ,EAAO5X,KAAK0gB,SAASvlB,GAASA,EAAM0B,OAChC,iBAAhByhB,EAAOzhB,MAAqBwK,EAAU,EAAG,sBAGlD4Z,YACE,OAAOjhB,KAAK0gB,QAGdQ,SAASrkB,GACP,OAAOmD,KAAKghB,YAAYnkB,GAG1B4hB,UAAU0C,GACR,MAAMJ,EAAY/gB,KAAK6gB,aAAajgB,IAAIugB,GAExC,QAAkBpjB,IAAdgjB,EACF,MAAM,IAAIviB,aAAa,SAASwB,KAAKnD,iCAAiCgJ,EAAQsb,MAGhF,OAAOJ,EAAUlkB,KAGnB0hB,WAAW6C,GAGT,GAA0B,iBAAfA,EAAyB,CAClC,MAAMC,EAAWxb,EAAQub,GACzB,MAAM,IAAI5iB,aAAa,SAASwB,KAAKnD,4CAA4CwkB,KAAcC,GAAoBthB,KAAMqhB,IAG3H,MAAMN,EAAY/gB,KAAKkhB,SAASE,GAEhC,GAAiB,MAAbL,EACF,MAAM,IAAIviB,aAAa,UAAU4iB,yBAAkCphB,KAAKnD,cAAgBykB,GAAoBthB,KAAMohB,IAGpH,OAAOL,EAAU5lB,MAGnBujB,aAAa1C,EAAWuF,GAItB,GAAIvF,EAAU3X,OAASpD,EAAKkB,KAAM,CAChC,MAAMkf,EAAWvG,EAAMkB,GACvB,MAAM,IAAIxd,aAAa,SAASwB,KAAKnD,0CAA0CwkB,KAAcC,GAAoBthB,KAAMqhB,GAAWrF,GAGpI,MAAM+E,EAAY/gB,KAAKkhB,SAASlF,EAAU7gB,OAE1C,GAAiB,MAAb4lB,EAAmB,CACrB,MAAMM,EAAWvG,EAAMkB,GACvB,MAAM,IAAIxd,aAAa,UAAU6iB,yBAAgCrhB,KAAKnD,cAAgBykB,GAAoBthB,KAAMqhB,GAAWrF,GAG7H,OAAO+E,EAAU5lB,MAGnB0jB,WACE,MAAMpP,EAASyI,EAAUlY,KAAKihB,aAAa9lB,GAASA,EAAM0B,OAAM1B,KAC9D6F,YAAa7F,EAAM6F,YACnB7F,MAAOA,EAAMA,MACb4kB,kBAAmB5kB,EAAM4kB,kBACzB/gB,WAAY7D,EAAM6D,WAClB2f,QAASxjB,EAAMwjB,YAEjB,MAAO,CACL9hB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClByO,OAAAA,EACAzQ,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,IAIjDpe,WACE,OAAOR,KAAKnD,KAGdqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,mBAKX,SAASwgB,GAAoBE,EAAUC,GAGrC,OAAOrJ,EAAW,iBADMU,EAAe2I,EADtBD,EAASP,YAAYvjB,KAAIvC,GAASA,EAAM0B,SAwCpD,MAAMsgB,uBACXze,YAAY4f,GACVte,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBR,GAAgBE,EAAOM,mBAChD5e,KAAK+e,QAAU2C,GAAoBzC,UAAKlhB,EAAWugB,GAC5B,iBAAhBA,EAAOzhB,MAAqBwK,EAAU,EAAG,sBAGlD+X,YAKE,MAJ4B,mBAAjBpf,KAAK+e,UACd/e,KAAK+e,QAAU/e,KAAK+e,WAGf/e,KAAK+e,QAGdF,WACE,MAAMlP,EAASoI,EAAS/X,KAAKof,aAAahD,KACxCpb,YAAaob,EAAMpb,YACnB6M,KAAMuO,EAAMvO,KACZE,aAAcqO,EAAMrO,aACpB/O,WAAYod,EAAMpd,WAClB2f,QAASvC,EAAMuC,YAEjB,MAAO,CACL9hB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClB2O,OAAAA,EACA3Q,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,IAIjDpe,WACE,OAAOR,KAAKnD,KAGdqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,0BAKX,SAAS4gB,GAAoBpD,GAC3B,MAAMiB,EAAWrB,GAAaI,EAAO3O,QAErC,OADA6P,GAAWD,IAAalY,EAAU,EAAG,GAAGiX,EAAOzhB,sGACxCkb,EAASwH,GAAU,CAACE,EAAaC,OACpC,YAAaD,IAAgBpY,EAAU,EAAG,GAAGiX,EAAOzhB,QAAQ6iB,4EACvD,CACL7iB,KAAM6iB,EACN1e,YAAaye,EAAYze,YACzB6M,KAAM4R,EAAY5R,KAClBE,aAAc0R,EAAY1R,aAC1BgS,kBAAmBN,EAAYM,kBAC/B/gB,WAAYygB,EAAYzgB,YAAcgZ,EAASyH,EAAYzgB,YAC3D2f,QAASc,EAAYd,YAKpB,SAASgD,GAAqBvF,GACnC,OAAOS,GAAcT,EAAMvO,YAAgC9P,IAAvBqe,EAAMrO,aC58BrC,SAAS6T,GAAYC,EAAOC,GAEjC,OAAID,IAAUC,IAKVjF,GAAcgF,IAAUhF,GAAciF,OAKtClF,GAAWiF,KAAUjF,GAAWkF,MAJ3BF,GAAYC,EAAMrE,OAAQsE,EAAMtE,QAgBpC,SAASuE,GAAgBC,EAAQC,EAAcC,GAEpD,OAAID,IAAiBC,IAKjBrF,GAAcqF,KACZrF,GAAcoF,IACTF,GAAgBC,EAAQC,EAAazE,OAAQ0E,EAAU1E,QAM9DX,GAAcoF,GAETF,GAAgBC,EAAQC,EAAazE,OAAQ0E,GAIlDtF,GAAWsF,KACTtF,GAAWqF,IACNF,GAAgBC,EAAQC,EAAazE,OAAQ0E,EAAU1E,SAM9DZ,GAAWqF,KAORrE,GAAesE,KAAe1F,GAAgByF,IAAiB1F,GAAa0F,KAAkBD,EAAOG,UAAUD,EAAWD,KAY5H,SAASG,GAAeJ,EAAQH,EAAOC,GAE5C,OAAID,IAAUC,IAIVlE,GAAeiE,GACbjE,GAAekE,GAGVE,EAAOK,iBAAiBR,GAAOhG,MAAKhO,GAAQmU,EAAOG,UAAUL,EAAOjU,KAItEmU,EAAOG,UAAUN,EAAOC,KAG7BlE,GAAekE,IAEVE,EAAOG,UAAUL,EAAOD,ICrFnC,MAAMS,GAAU,WACVC,IAAW,WAsCV,MAAMC,GAAa,IAAI1F,kBAAkB,CAC9CjgB,KAAM,MACNmE,YAAa,sIACbyd,UAvCF,SAAsB0C,GACpB,MAAMsB,EAAeC,GAAgBvB,GAErC,GAA4B,kBAAjBsB,EACT,OAAOA,EAAe,EAAI,EAG5B,IAAIE,EAAMF,EAMV,GAJ4B,iBAAjBA,GAA8C,KAAjBA,IACtCE,EAAMC,OAAOH,IAGI,iBAARE,IAAqBC,OAAOC,UAAUF,GAC/C,MAAM,IAAInkB,aAAa,2CAA2CqH,EAAQ4c,MAG5E,GAAIE,EAAML,IAAWK,EAAMJ,GACzB,MAAM,IAAI/jB,aAAa,yDAA2DqH,EAAQ4c,IAG5F,OAAOE,GAmBPpE,WAhBF,SAAmB6C,GACjB,GAA0B,iBAAfA,IAA4BwB,OAAOC,UAAUzB,GACtD,MAAM,IAAI5iB,aAAa,2CAA2CqH,EAAQub,MAG5E,GAAIA,EAAakB,IAAWlB,EAAamB,GACvC,MAAM,IAAI/jB,aAAa,yDAAyD4iB,KAGlF,OAAOA,GASP1C,aAAa1C,GACX,GAAIA,EAAU3X,OAASpD,EAAKa,IAC1B,MAAM,IAAItD,aAAa,2CAA2Csc,EAAMkB,KAAcA,GAGxF,MAAM2G,EAAMzG,SAASF,EAAU7gB,MAAO,IAEtC,GAAIwnB,EAAML,IAAWK,EAAMJ,GACzB,MAAM,IAAI/jB,aAAa,yDAAyDwd,EAAU7gB,QAAS6gB,GAGrG,OAAO2G,KAiCJ,MAAMG,GAAe,IAAIhG,kBAAkB,CAChDjgB,KAAM,QACNmE,YAAa,8JACbyd,UA/BF,SAAwB0C,GACtB,MAAMsB,EAAeC,GAAgBvB,GAErC,GAA4B,kBAAjBsB,EACT,OAAOA,EAAe,EAAI,EAG5B,IAAIE,EAAMF,EAMV,GAJ4B,iBAAjBA,GAA8C,KAAjBA,IACtCE,EAAMC,OAAOH,IAGI,iBAARE,IAAqBC,OAAOG,SAASJ,GAC9C,MAAM,IAAInkB,aAAa,6CAA6CqH,EAAQ4c,MAG9E,OAAOE,GAePpE,WAZF,SAAqB6C,GACnB,GAA0B,iBAAfA,IAA4BwB,OAAOG,SAAS3B,GACrD,MAAM,IAAI5iB,aAAa,6CAA6CqH,EAAQub,MAG9E,OAAOA,GASP1C,aAAa1C,GACX,GAAIA,EAAU3X,OAASpD,EAAKc,OAASia,EAAU3X,OAASpD,EAAKa,IAC3D,MAAM,IAAItD,aAAa,6CAA6Csc,EAAMkB,KAAcA,GAG1F,OAAOG,WAAWH,EAAU7gB,UAOhC,SAASunB,GAAgBvB,GACvB,GAAIjmB,EAAaimB,GAAc,CAC7B,GAAmC,mBAAxBA,EAAY6B,QAAwB,CAC7C,MAAMC,EAAgB9B,EAAY6B,UAElC,IAAK9nB,EAAa+nB,GAChB,OAAOA,EAIX,GAAkC,mBAAvB9B,EAAYjd,OAErB,OAAOid,EAAYjd,SAIvB,OAAOid,EA8BF,MAAM+B,GAAgB,IAAIpG,kBAAkB,CACjDjgB,KAAM,SACNmE,YAAa,wLACbyd,UA9BF,SAAyB0C,GACvB,MAAMsB,EAAeC,GAAgBvB,GAGrC,GAA4B,iBAAjBsB,EACT,OAAOA,EAGT,GAA4B,kBAAjBA,EACT,OAAOA,EAAe,OAAS,QAGjC,GAA4B,iBAAjBA,GAA6BG,OAAOG,SAASN,GACtD,OAAOA,EAAajiB,WAGtB,MAAM,IAAIhC,aAAa,kCAAkCqH,EAAQsb,OAejE5C,WAZF,SAAsB6C,GACpB,GAA0B,iBAAfA,EACT,MAAM,IAAI5iB,aAAa,+CAA+CqH,EAAQub,MAGhF,OAAOA,GASP1C,aAAa1C,GACX,GAAIA,EAAU3X,OAASpD,EAAKe,OAC1B,MAAM,IAAIxD,aAAa,+CAA+Csc,EAAMkB,KAAcA,GAG5F,OAAOA,EAAU7gB,SA2Bd,MAAMgoB,GAAiB,IAAIrG,kBAAkB,CAClDjgB,KAAM,UACNmE,YAAa,0DACbyd,UAzBF,SAA0B0C,GACxB,MAAMsB,EAAeC,GAAgBvB,GAErC,GAA4B,kBAAjBsB,EACT,OAAOA,EAGT,GAAIG,OAAOG,SAASN,GAClB,OAAwB,IAAjBA,EAGT,MAAM,IAAIjkB,aAAa,iDAAiDqH,EAAQ4c,OAehFlE,WAZF,SAAuB6C,GACrB,GAA0B,kBAAfA,EACT,MAAM,IAAI5iB,aAAa,iDAAiDqH,EAAQub,MAGlF,OAAOA,GASP1C,aAAa1C,GACX,GAAIA,EAAU3X,OAASpD,EAAKgB,QAC1B,MAAM,IAAIzD,aAAa,iDAAiDsc,EAAMkB,KAAcA,GAG9F,OAAOA,EAAU7gB,SA+Bd,MAAMioB,GAAY,IAAItG,kBAAkB,CAC7CjgB,KAAM,KACNmE,YAAa,+UACbyd,UA7BF,SAAqB0C,GACnB,MAAMsB,EAAeC,GAAgBvB,GAErC,GAA4B,iBAAjBsB,EACT,OAAOA,EAGT,GAAIG,OAAOC,UAAUJ,GACnB,OAAOrb,OAAOqb,GAGhB,MAAM,IAAIjkB,aAAa,8BAA8BqH,EAAQsb,OAmB7D5C,WAhBF,SAAkB6C,GAChB,GAA0B,iBAAfA,EACT,OAAOA,EAGT,GAA0B,iBAAfA,GAA2BwB,OAAOC,UAAUzB,GACrD,OAAOA,EAAW5gB,WAGpB,MAAM,IAAIhC,aAAa,8BAA8BqH,EAAQub,OAS7D1C,aAAa1C,GACX,GAAIA,EAAU3X,OAASpD,EAAKe,QAAUga,EAAU3X,OAASpD,EAAKa,IAC5D,MAAM,IAAItD,aAAa,2DAA6Dsc,EAAMkB,GAAYA,GAGxG,OAAOA,EAAU7gB,SAIRkoB,GAAuBvjB,OAAOoB,OAAO,CAACgiB,GAAeV,GAAYM,GAAcK,GAAgBC,KACrG,SAASE,GAAsBzV,GACpC,OAAOwV,GAAqBxH,MAAK,EAC/Bhf,KAAAA,KACIgR,EAAKhR,OAASA,ICzOf,SAAS0mB,GAAapoB,EAAO0S,GAClC,GAAIgP,GAAchP,GAAO,CACvB,MAAM2V,EAAWD,GAAapoB,EAAO0S,EAAK2P,QAE1C,OAAIgG,GAAUnf,OAASpD,EAAKiB,KACnB,KAGFshB,EAIT,GAAc,OAAVroB,EACF,MAAO,CACLkJ,KAAMpD,EAAKiB,MAKf,QAAcnE,IAAV5C,EACF,OAAO,KAKT,GAAIyhB,GAAW/O,GAAO,CACpB,MAAM4V,EAAW5V,EAAK2P,OAEtB,GCpCW,SAAsBhG,GACnC,GAAW,MAAPA,GAA8B,iBAARA,EACxB,OAAO,EAIT,MAAM1b,EAAS0b,EAAI1b,OAEnB,MAAsB,iBAAXA,GAAuBA,GAAU,GAAKA,EAAS,GAAM,GAKzB,mBAAzB0b,EAAI3W,OAAO6iB,UDuBnBC,CAAaxoB,GAAQ,CACvB,MAAMyoB,EAAc,GAGpB,IAAK,MAAMjV,KAAQpQ,MAAMslB,KAAK1oB,GAAQ,CACpC,MAAM2oB,EAAWP,GAAa5U,EAAM8U,GAEpB,MAAZK,GACFF,EAAYrmB,KAAKumB,GAIrB,MAAO,CACLzf,KAAMpD,EAAKmB,KACXqN,OAAQmU,GAIZ,OAAOL,GAAapoB,EAAOsoB,GAK7B,GAAI9G,GAAkB9O,GAAO,CAC3B,IAAK3S,EAAaC,GAChB,OAAO,KAGT,MAAM4oB,EAAa,GAEnB,IAAK,MAAM3H,KAAS7E,EAAa1J,EAAKuR,aAAc,CAClD,MAAM4E,EAAaT,GAAapoB,EAAMihB,EAAMvf,MAAOuf,EAAMvO,MAErDmW,GACFD,EAAWxmB,KAAK,CACd8G,KAAMpD,EAAKqB,aACXzF,KAAM,CACJwH,KAAMpD,EAAKE,KACXhG,MAAOihB,EAAMvf,MAEf1B,MAAO6oB,IAKb,MAAO,CACL3f,KAAMpD,EAAKoB,OACXsN,OAAQoU,GAKZ,GAAIrG,GAAW7P,GAAO,CAGpB,MAAMoW,EAAapW,EAAK4Q,UAAUtjB,GAElC,GAAkB,MAAd8oB,EACF,OAAO,KAIT,GAA0B,kBAAfA,EACT,MAAO,CACL5f,KAAMpD,EAAKgB,QACX9G,MAAO8oB,GAKX,GAA0B,iBAAfA,GAA2BrB,OAAOG,SAASkB,GAAa,CACjE,MAAMC,EAAY9c,OAAO6c,GACzB,OAAOE,GAAoBC,KAAKF,GAAa,CAC3C7f,KAAMpD,EAAKa,IACX3G,MAAO+oB,GACL,CACF7f,KAAMpD,EAAKc,MACX5G,MAAO+oB,GAIX,GAA0B,iBAAfD,EAET,OAAIvH,GAAW7O,GACN,CACLxJ,KAAMpD,EAAKkB,KACXhH,MAAO8oB,GAKPpW,IAASuV,IAAae,GAAoBC,KAAKH,GAC1C,CACL5f,KAAMpD,EAAKa,IACX3G,MAAO8oB,GAIJ,CACL5f,KAAMpD,EAAKe,OACX7G,MAAO8oB,GAIX,MAAM,IAAII,UAAU,gCAAgCxe,EAAQoe,OAIrDnI,GAAU,EAAG,0BAA4BjW,EAAQgI,IAQ5D,MAAMsW,GAAsB,wBEtKfG,GAAW,IAAIvH,kBAAkB,CAC5ClgB,KAAM,WACNmE,YAAa,4MACb2O,OAAQ,MACN3O,YAAa,CACX6M,KAAMqV,GACNvD,QAASqC,GAAUA,EAAOhhB,aAE5BkQ,MAAO,CACLlQ,YAAa,gDACb6M,KAAM,IAAIwP,eAAe,IAAID,YAAY,IAAIC,eAAekH,MAE5D5E,QAAQqC,GACCzK,EAAayK,EAAOwC,eAI/BC,UAAW,CACTzjB,YAAa,oDACb6M,KAAM,IAAIwP,eAAekH,IACzB5E,QAASqC,GAAUA,EAAO0C,gBAE5BC,aAAc,CACZ3jB,YAAa,yFACb6M,KAAM0W,GACN5E,QAASqC,GAAUA,EAAO4C,mBAE5BC,iBAAkB,CAChB7jB,YAAa,gGACb6M,KAAM0W,GACN5E,QAASqC,GAAUA,EAAO8C,uBAE5B5X,WAAY,CACVlM,YAAa,qDACb6M,KAAM,IAAIwP,eAAe,IAAID,YAAY,IAAIC,eAAe0H,MAC5DpF,QAASqC,GAAUA,EAAOgD,qBAInBD,GAAc,IAAIhI,kBAAkB,CAC/ClgB,KAAM,cACNmE,YAAa,0XACb2O,OAAQ,MACN9S,KAAM,CACJgR,KAAM,IAAIwP,eAAe6F,IACzBvD,QAASsF,GAAaA,EAAUpoB,MAElCmE,YAAa,CACX6M,KAAMqV,GACNvD,QAASsF,GAAaA,EAAUjkB,aAElCkkB,aAAc,CACZrX,KAAM,IAAIwP,eAAe8F,IACzBxD,QAASsF,GAAaA,EAAUC,cAElC/kB,UAAW,CACT0N,KAAM,IAAIwP,eAAe,IAAID,YAAY,IAAIC,eAAe8H,MAC5DxF,QAASsF,GAAaA,EAAU9kB,WAElC4Q,KAAM,CACJlD,KAAM,IAAIwP,eAAe,IAAID,YAAY,IAAIC,eAAe+H,MAC5DzF,QAASsF,GAAaA,EAAUlU,UAIzBoU,GAAsB,IAAIjI,gBAAgB,CACrDrgB,KAAM,sBACNmE,YAAa,oIACbyO,OAAQ,CACN/H,MAAO,CACLvM,MAAOsM,EAAkBC,MACzB1G,YAAa,2CAEf2G,SAAU,CACRxM,MAAOsM,EAAkBE,SACzB3G,YAAa,8CAEf4G,aAAc,CACZzM,MAAOsM,EAAkBG,aACzB5G,YAAa,kDAEfQ,MAAO,CACLrG,MAAOsM,EAAkBjG,MACzBR,YAAa,iCAEfY,oBAAqB,CACnBzG,MAAOsM,EAAkB7F,oBACzBZ,YAAa,+CAEfU,gBAAiB,CACfvG,MAAOsM,EAAkB/F,gBACzBV,YAAa,2CAEfW,gBAAiB,CACfxG,MAAOsM,EAAkB9F,gBACzBX,YAAa,4CAEfM,oBAAqB,CACnBnG,MAAOsM,EAAkBnG,oBACzBN,YAAa,+CAEf6G,OAAQ,CACN1M,MAAOsM,EAAkBI,OACzB7G,YAAa,6CAEf8G,OAAQ,CACN3M,MAAOsM,EAAkBK,OACzB9G,YAAa,6CAEfqB,OAAQ,CACNlH,MAAOsM,EAAkBpF,OACzBrB,YAAa,mDAEf+B,iBAAkB,CAChB5H,MAAOsM,EAAkB1E,iBACzB/B,YAAa,4CAEf+G,oBAAqB,CACnB5M,MAAOsM,EAAkBM,oBACzB/G,YAAa,gDAEfgH,UAAW,CACT7M,MAAOsM,EAAkBO,UACzBhH,YAAa,iDAEfiH,MAAO,CACL9M,MAAOsM,EAAkBQ,MACzBjH,YAAa,4CAEfmB,KAAM,CACJhH,MAAOsM,EAAkBtF,KACzBnB,YAAa,4CAEfkH,WAAY,CACV/M,MAAOsM,EAAkBS,WACzBlH,YAAa,kDAEfmH,aAAc,CACZhN,MAAOsM,EAAkBU,aACzBnH,YAAa,yDAEfoH,uBAAwB,CACtBjN,MAAOsM,EAAkBW,uBACzBpH,YAAa,6DAINujB,GAAS,IAAIxH,kBAAkB,CAC1ClgB,KAAM,SACNmE,YAAa,siBACb2O,OAAQ,MACNtL,KAAM,CACJwJ,KAAM,IAAIwP,eAAegI,IAEzB1F,QAAQ9R,GACFyO,GAAazO,GACRyX,GAASxd,OAGdyU,GAAa1O,GACRyX,GAASjjB,OAGdma,GAAgB3O,GACXyX,GAAStd,UAGdyU,GAAY5O,GACPyX,GAASrd,MAGdyU,GAAW7O,GACNyX,GAASnjB,KAGdwa,GAAkB9O,GACbyX,GAASnd,aAGdyU,GAAW/O,GACNyX,GAASljB,KAIdya,GAAchP,GACTyX,GAASC,cAITzJ,GAAU,EAAG,qBAAqBjW,EAAQgI,SAIvDhR,KAAM,CACJgR,KAAMqV,GACNvD,QAAS9R,QAAsB9P,IAAd8P,EAAKhR,KAAqBgR,EAAKhR,UAAOkB,GAEzDiD,YAAa,CACX6M,KAAMqV,GACNvD,QAAS9R,QAA6B9P,IAArB8P,EAAK7M,YAA4B6M,EAAK7M,iBAAcjD,GAEvEygB,eAAgB,CACd3Q,KAAMqV,GACNvD,QAASnI,QAA8BzZ,IAAvByZ,EAAIgH,eAA+BhH,EAAIgH,oBAAiBzgB,GAE1E4R,OAAQ,CACN9B,KAAM,IAAIuP,YAAY,IAAIC,eAAemI,KACzCzU,KAAM,CACJ0U,kBAAmB,CACjB5X,KAAMsV,GACNpV,cAAc,IAIlB4R,QAAQ9R,GAAM4X,kBACZA,IAEA,GAAIlJ,GAAa1O,IAAS2O,GAAgB3O,GAAO,CAC/C,MAAM8B,EAAS4H,EAAa1J,EAAKuR,aACjC,OAAOqG,EAAoB9V,EAASA,EAAO9R,QAAOue,GAAoC,MAA3BA,EAAM2D,uBAKvErP,WAAY,CACV7C,KAAM,IAAIuP,YAAY,IAAIC,eAAekH,KAEzC5E,QAAQ9R,GACN,GAAI0O,GAAa1O,IAAS2O,GAAgB3O,GACxC,OAAOA,EAAKwR,kBAKlBqG,cAAe,CACb7X,KAAM,IAAIuP,YAAY,IAAIC,eAAekH,KAEzC5E,QAAQ9R,EAAM8X,EAAOC,GAAU5D,OAC7BA,IAEA,GAAIpE,GAAe/P,GACjB,OAAOmU,EAAOK,iBAAiBxU,KAKrCgY,WAAY,CACVhY,KAAM,IAAIuP,YAAY,IAAIC,eAAeyI,KACzC/U,KAAM,CACJ0U,kBAAmB,CACjB5X,KAAMsV,GACNpV,cAAc,IAIlB4R,QAAQ9R,GAAM4X,kBACZA,IAEA,GAAI/I,GAAW7O,GAAO,CACpB,MAAM4B,EAAS5B,EAAKoT,YACpB,OAAOwE,EAAoBhW,EAASA,EAAO5R,QAAOue,GAAoC,MAA3BA,EAAM2D,uBAKvEgG,YAAa,CACXlY,KAAM,IAAIuP,YAAY,IAAIC,eAAe+H,KACzCrU,KAAM,CACJ0U,kBAAmB,CACjB5X,KAAMsV,GACNpV,cAAc,IAIlB4R,QAAQ9R,GAAM4X,kBACZA,IAEA,GAAI9I,GAAkB9O,GAAO,CAC3B,MAAM4B,EAAS8H,EAAa1J,EAAKuR,aACjC,OAAOqG,EAAoBhW,EAASA,EAAO5R,QAAOue,GAAoC,MAA3BA,EAAM2D,uBAKvEvC,OAAQ,CACN3P,KAAM0W,GACN5E,QAAS9R,QAAwB9P,IAAhB8P,EAAK2P,OAAuB3P,EAAK2P,YAASzf,OAIpDynB,GAAU,IAAIzI,kBAAkB,CAC3ClgB,KAAM,UACNmE,YAAa,8IACb2O,OAAQ,MACN9S,KAAM,CACJgR,KAAM,IAAIwP,eAAe6F,IACzBvD,QAASvD,GAASA,EAAMvf,MAE1BmE,YAAa,CACX6M,KAAMqV,GACNvD,QAASvD,GAASA,EAAMpb,aAE1B+P,KAAM,CACJlD,KAAM,IAAIwP,eAAe,IAAID,YAAY,IAAIC,eAAe+H,MAC5DrU,KAAM,CACJ0U,kBAAmB,CACjB5X,KAAMsV,GACNpV,cAAc,IAIlB4R,QAAO,CAACvD,GAAOqJ,kBACbA,KAEOA,EAAoBrJ,EAAMrL,KAAOqL,EAAMrL,KAAKlT,QAAOqiB,GAAgC,MAAzBA,EAAIH,qBAIzElS,KAAM,CACJA,KAAM,IAAIwP,eAAekH,IACzB5E,QAASvD,GAASA,EAAMvO,MAE1BmY,aAAc,CACZnY,KAAM,IAAIwP,eAAe8F,IACzBxD,QAASvD,GAAoC,MAA3BA,EAAM2D,mBAE1BA,kBAAmB,CACjBlS,KAAMqV,GACNvD,QAASvD,GAASA,EAAM2D,uBAIjBqF,GAAe,IAAIrI,kBAAkB,CAChDlgB,KAAM,eACNmE,YAAa,8KACb2O,OAAQ,MACN9S,KAAM,CACJgR,KAAM,IAAIwP,eAAe6F,IACzBvD,QAASyB,GAAcA,EAAWvkB,MAEpCmE,YAAa,CACX6M,KAAMqV,GACNvD,QAASyB,GAAcA,EAAWpgB,aAEpC6M,KAAM,CACJA,KAAM,IAAIwP,eAAekH,IACzB5E,QAASyB,GAAcA,EAAWvT,MAEpCE,aAAc,CACZF,KAAMqV,GACNliB,YAAa,kFAEb2e,QAAQyB,GACN,MAAMvT,KACJA,EAAIE,aACJA,GACEqT,EACE6E,EAAW1C,GAAaxV,EAAcF,GAC5C,OAAOoY,EAAWnL,EAAMmL,GAAY,OAIxCD,aAAc,CACZnY,KAAM,IAAIwP,eAAe8F,IACzBxD,QAASvD,GAAoC,MAA3BA,EAAM2D,mBAE1BA,kBAAmB,CACjBlS,KAAMqV,GACNvD,QAASnI,GAAOA,EAAIuI,uBAIb+F,GAAc,IAAI/I,kBAAkB,CAC/ClgB,KAAM,cACNmE,YAAa,yLACb2O,OAAQ,MACN9S,KAAM,CACJgR,KAAM,IAAIwP,eAAe6F,IACzBvD,QAASoB,GAAaA,EAAUlkB,MAElCmE,YAAa,CACX6M,KAAMqV,GACNvD,QAASoB,GAAaA,EAAU/f,aAElCglB,aAAc,CACZnY,KAAM,IAAIwP,eAAe8F,IACzBxD,QAASoB,GAA4C,MAA/BA,EAAUhB,mBAElCA,kBAAmB,CACjBlS,KAAMqV,GACNvD,QAASoB,GAAaA,EAAUhB,uBAIzBuF,GAAWxlB,OAAOoB,OAAO,CACpC4G,OAAQ,SACRzF,OAAQ,SACR2F,UAAW,YACXC,MAAO,QACP9F,KAAM,OACNgG,aAAc,eACd/F,KAAM,OACNmjB,SAAU,aAECF,GAAa,IAAInI,gBAAgB,CAC5CrgB,KAAM,aACNmE,YAAa,4DACbyO,OAAQ,CACN3H,OAAQ,CACN3M,MAAOmqB,GAASxd,OAChB9G,YAAa,oCAEfqB,OAAQ,CACNlH,MAAOmqB,GAASjjB,OAChBrB,YAAa,iFAEfgH,UAAW,CACT7M,MAAOmqB,GAAStd,UAChBhH,YAAa,sGAEfiH,MAAO,CACL9M,MAAOmqB,GAASrd,MAChBjH,YAAa,qEAEfmB,KAAM,CACJhH,MAAOmqB,GAASnjB,KAChBnB,YAAa,kEAEfmH,aAAc,CACZhN,MAAOmqB,GAASnd,aAChBnH,YAAa,2EAEfoB,KAAM,CACJjH,MAAOmqB,GAASljB,KAChBpB,YAAa,6DAEfukB,SAAU,CACRpqB,MAAOmqB,GAASC,SAChBvkB,YAAa,oEASNklB,GAAqB,CAChCrpB,KAAM,WACNgR,KAAM,IAAIwP,eAAeiH,IACzBtjB,YAAa,iDACb+P,KAAM,GACN4O,QAAS,CAACvgB,EAASumB,EAAOC,GACxB5D,OAAAA,KACIA,EACNjC,uBAAmBhiB,EACnBiB,gBAAYjB,EACZ4gB,aAAS5gB,GAEEooB,GAAmB,CAC9BtpB,KAAM,SACNgR,KAAM0W,GACNvjB,YAAa,iDACb+P,KAAM,CAAC,CACLlU,KAAM,OACNmE,iBAAajD,EACb8P,KAAM,IAAIwP,eAAe6F,IACzBnV,kBAAchQ,EACdgiB,uBAAmBhiB,EACnBiB,gBAAYjB,EACZ4gB,aAAS5gB,IAEX4hB,QAAS,CAACvgB,GACRvC,KAAAA,GACC+oB,GACD5D,OAAAA,KACIA,EAAOoE,QAAQvpB,GACrBkjB,uBAAmBhiB,EACnBiB,gBAAYjB,EACZ4gB,aAAS5gB,GAEEsoB,GAAuB,CAClCxpB,KAAM,aACNgR,KAAM,IAAIwP,eAAe6F,IACzBliB,YAAa,kDACb+P,KAAM,GACN4O,QAAS,CAACvgB,EAASumB,EAAOC,GACxBU,WAAAA,KACIA,EAAWzpB,KACjBkjB,uBAAmBhiB,EACnBiB,gBAAYjB,EACZ4gB,aAAS5gB,GAEEwoB,GAAqBzmB,OAAOoB,OAAO,CAACojB,GAAUS,GAAaI,GAAqBZ,GAAQiB,GAASJ,GAAcU,GAAaT,KAClI,SAASmB,GAAoB3Y,GAClC,OAAO0Y,GAAmB1K,MAAK,EAC7Bhf,KAAAA,KACIgR,EAAKhR,OAASA,IC3ef,SAAS4pB,GAAYxB,GAC1B,OAAOjZ,EAAWiZ,EAAWyB,kBAcxB,MAAMA,iBACXhoB,YAAY4f,GACVte,KAAKnD,KAAOyhB,EAAOzhB,KACnBmD,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKG,UAAYme,EAAOne,UACxBH,KAAKklB,aAAe5G,EAAO4G,eAAgB,EAC3CllB,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtBL,EAAOzhB,MAAQwK,EAAU,EAAG,4BAC5B9I,MAAMY,QAAQmf,EAAOne,YAAckH,EAAU,EAAG,IAAIiX,EAAOzhB,oCAC3D,MAAMkU,EAAOuN,EAAOvN,MAAQ,GAC5B7V,EAAa6V,KAAUxS,MAAMY,QAAQ4R,IAAS1J,EAAU,EAAG,IAAIiX,EAAOzhB,4DACtEmD,KAAK+Q,KAAO2G,EAAc3G,GAAMrT,KAAI,EAAEmiB,EAASC,OAC7CjjB,KAAMgjB,EACN7e,YAAa8e,EAAU9e,YACvB6M,KAAMiS,EAAUjS,KAChBE,aAAc+R,EAAU/R,aACxBgS,kBAAmBD,EAAUC,kBAC7B/gB,WAAY8gB,EAAU9gB,YAAcgZ,EAAS8H,EAAU9gB,YACvD2f,QAASmB,EAAUnB,YAIvBE,WACE,MAAO,CACLhiB,KAAMmD,KAAKnD,KACXmE,YAAahB,KAAKgB,YAClBb,UAAWH,KAAKG,UAChB4Q,KAAMkP,GAAiBjgB,KAAK+Q,MAC5BmU,aAAcllB,KAAKklB,aACnBlmB,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,SAIlBne,WACE,MAAO,IAAMR,KAAKnD,KAGpBqH,SACE,OAAOlE,KAAKQ,WAIdI,IAAKC,OAAOC,eACV,MAAO,oBAQJ,MAAM6lB,GAA0B,IAAID,iBAAiB,CAC1D7pB,KAAM,UACNmE,YAAa,8FACbb,UAAW,CAACsH,EAAkBjG,MAAOiG,EAAkB/F,gBAAiB+F,EAAkB9F,iBAC1FoP,KAAM,CACJ6V,GAAI,CACF/Y,KAAM,IAAIwP,eAAe8F,IACzBniB,YAAa,0BAQN6lB,GAAuB,IAAIH,iBAAiB,CACvD7pB,KAAM,OACNmE,YAAa,sFACbb,UAAW,CAACsH,EAAkBjG,MAAOiG,EAAkB/F,gBAAiB+F,EAAkB9F,iBAC1FoP,KAAM,CACJ6V,GAAI,CACF/Y,KAAM,IAAIwP,eAAe8F,IACzBniB,YAAa,yBAQN8lB,GAA6B,sBAK7BC,GAA6B,IAAIL,iBAAiB,CAC7D7pB,KAAM,aACNmE,YAAa,+DACbb,UAAW,CAACsH,EAAkB1E,iBAAkB0E,EAAkBM,oBAAqBN,EAAkBW,uBAAwBX,EAAkBS,YACnJ6I,KAAM,CACJiW,OAAQ,CACNnZ,KAAMqV,GACNliB,YAAa,sNACb+M,aAAc+Y,OAQPG,GAA8B,IAAIP,iBAAiB,CAC9D7pB,KAAM,cACNmE,YAAa,6DACbb,UAAW,CAACsH,EAAkBK,QAC9BiJ,KAAM,CACJmW,IAAK,CACHrZ,KAAM,IAAIwP,eAAe6F,IACzBliB,YAAa,2DAQNmmB,GAAsBrnB,OAAOoB,OAAO,CAACylB,GAAyBE,GAAsBE,GAA4BE,KCnItH,SAASG,GAAapF,GAC3B,IAJK,SAAkBA,GACvB,OAAOhW,EAAWgW,EAAQqF,eAGrBC,CAAStF,GACZ,MAAM,IAAIvjB,MAAM,YAAYoH,EAAQmc,8BAGtC,OAAOA,EAkEF,MAAMqF,cAEX3oB,YAAY4f,GAGVte,KAAKunB,oBAA4C,IAAvBjJ,EAAOkJ,YAAuB,QAAKzpB,EAE7D7C,EAAaojB,IAAWjX,EAAU,EAAG,uCACpCiX,EAAOpN,OAAS3S,MAAMY,QAAQmf,EAAOpN,QAAU7J,EAAU,EAAG,8CAA8CxB,EAAQyY,EAAOpN,YACzHoN,EAAOpR,YAAc3O,MAAMY,QAAQmf,EAAOpR,aAAe7F,EAAU,EAAwD,mDAAGxB,EAAQyY,EAAOpR,gBAC9IlN,KAAKgB,YAAcsd,EAAOtd,YAC1BhB,KAAKhB,WAAasf,EAAOtf,YAAcgZ,EAASsG,EAAOtf,YACvDgB,KAAK2e,QAAUL,EAAOK,QACtB3e,KAAK4e,kBAAoBN,EAAOM,kBAChC5e,KAAKynB,WAAanJ,EAAOoJ,MACzB1nB,KAAK2nB,cAAgBrJ,EAAOsJ,SAC5B5nB,KAAK6nB,kBAAoBvJ,EAAOwJ,aAEhC9nB,KAAK+nB,YAAczJ,EAAOpR,YAAcia,GAGxC,MAAMa,EAAqB,IAAIC,IAAI3J,EAAOpN,OAE1C,GAAoB,MAAhBoN,EAAOpN,MACT,IAAK,MAAMrD,KAAQyQ,EAAOpN,MAGxB8W,EAAmBE,OAAOra,GAC1Bsa,GAAuBta,EAAMma,GAIV,MAAnBhoB,KAAKynB,YACPU,GAAuBnoB,KAAKynB,WAAYO,GAGhB,MAAtBhoB,KAAK2nB,eACPQ,GAAuBnoB,KAAK2nB,cAAeK,GAGf,MAA1BhoB,KAAK6nB,mBACPM,GAAuBnoB,KAAK6nB,kBAAmBG,GAGjD,IAAK,MAAM/C,KAAajlB,KAAK+nB,YAE3B,GAAItB,GAAYxB,GACd,IAAK,MAAM/E,KAAO+E,EAAUlU,KAC1BoX,GAAuBjI,EAAIrS,KAAMma,GAKvCG,GAAuB7D,GAAU0D,GAEjChoB,KAAKooB,SAAWtoB,OAAOgY,OAAO,MAC9B9X,KAAKqoB,YAAcvoB,OAAOgY,OAAO,MAEjC9X,KAAKsoB,oBAAsBxoB,OAAOgY,OAAO,MAEzC,IAAK,MAAMyQ,KAAahqB,MAAMslB,KAAKmE,GAAqB,CACtD,GAAiB,MAAbO,EACF,SAGF,MAAM/H,EAAW+H,EAAU1rB,KAG3B,GAFA2jB,GAAYnZ,EAAU,EAAG,6EAEOtJ,IAA5BiC,KAAKooB,SAAS5H,GAChB,MAAM,IAAI/hB,MAAM,+EAA+E+hB,OAKjG,GAFAxgB,KAAKooB,SAAS5H,GAAY+H,EAEtB/L,GAAgB+L,IAElB,IAAK,MAAMC,KAASD,EAAUlJ,gBAC5B,GAAI7C,GAAgBgM,GAAQ,CAC1B,IAAIC,EAAkBzoB,KAAKsoB,oBAAoBE,EAAM3rB,WAE7BkB,IAApB0qB,IACFA,EAAkBzoB,KAAKsoB,oBAAoBE,EAAM3rB,MAAQ,CACvD6rB,QAAS,GACThY,WAAY,KAIhB+X,EAAgB/X,WAAWnT,KAAKgrB,SAG/B,GAAIhM,GAAagM,GAEtB,IAAK,MAAMC,KAASD,EAAUlJ,gBAC5B,GAAI7C,GAAgBgM,GAAQ,CAC1B,IAAIC,EAAkBzoB,KAAKsoB,oBAAoBE,EAAM3rB,WAE7BkB,IAApB0qB,IACFA,EAAkBzoB,KAAKsoB,oBAAoBE,EAAM3rB,MAAQ,CACvD6rB,QAAS,GACThY,WAAY,KAIhB+X,EAAgBC,QAAQnrB,KAAKgrB,KAOvC7D,eACE,OAAO1kB,KAAKynB,WAGd7C,kBACE,OAAO5kB,KAAK2nB,cAGd7C,sBACE,OAAO9kB,KAAK6nB,kBAGdrD,aACE,OAAOxkB,KAAKooB,SAGdhC,QAAQvpB,GACN,OAAOmD,KAAKwkB,aAAa3nB,GAG3BwlB,iBAAiBsG,GACf,OAAOlM,GAAYkM,GAAgBA,EAAapI,WAAavgB,KAAK4oB,mBAAmBD,GAAcD,QAGrGE,mBAAmBC,GAEjB,OADwB7oB,KAAKsoB,oBAAoBO,EAAchsB,OACrC,CACxB6rB,QAAS,GACThY,WAAY,IAIhByR,UAAUwG,EAAc1G,GACtB,IAAIvkB,EAAMsC,KAAKqoB,YAAYM,EAAa9rB,MAExC,QAAYkB,IAARL,EAAmB,CAGrB,GAFAA,EAAMoC,OAAOgY,OAAO,MAEhB2E,GAAYkM,GACd,IAAK,MAAM9a,KAAQ8a,EAAapI,WAC9B7iB,EAAImQ,EAAKhR,OAAQ,MAEd,CACL,MAAM4rB,EAAkBzoB,KAAK4oB,mBAAmBD,GAEhD,IAAK,MAAM9a,KAAQ4a,EAAgBC,QACjChrB,EAAImQ,EAAKhR,OAAQ,EAGnB,IAAK,MAAMgR,KAAQ4a,EAAgB/X,WACjChT,EAAImQ,EAAKhR,OAAQ,EAIrBmD,KAAKqoB,YAAYM,EAAa9rB,MAAQa,EAGxC,YAAkCK,IAA3BL,EAAIukB,EAAaplB,MAG1BmoB,gBACE,OAAOhlB,KAAK+nB,YAGde,aAAajsB,GACX,OAAOmD,KAAKglB,gBAAgB+D,MAAK9D,GAAaA,EAAUpoB,OAASA,IAGnEgiB,WACE,MAAO,CACL7d,YAAahB,KAAKgB,YAClB0mB,MAAO1nB,KAAK0kB,eACZkD,SAAU5nB,KAAK4kB,kBACfkD,aAAc9nB,KAAK8kB,sBACnB5T,MAAOqG,EAAavX,KAAKwkB,cACzBtX,WAAYlN,KAAKglB,gBAAgBxnB,QACjCwB,WAAYgB,KAAKhB,WACjB2f,QAAS3e,KAAK2e,QACdC,kBAAmB5e,KAAK4e,mBAAqB,GAC7C4I,iBAAyCzpB,IAA5BiC,KAAKunB,oBAKtB3mB,IAAKC,OAAOC,eACV,MAAO,iBAKX,SAASqnB,GAAuBta,EAAMmb,GACpC,MAAMT,EAAYvK,GAAanQ,GAE/B,IAAKmb,EAAQC,IAAIV,GAGf,GAFAS,EAAQE,IAAIX,GAER9L,GAAY8L,GACd,IAAK,MAAMY,KAAcZ,EAAUhI,WACjC4H,GAAuBgB,EAAYH,QAEhC,GAAIzM,GAAagM,IAAc/L,GAAgB+L,GAAY,CAChE,IAAK,MAAMM,KAAiBN,EAAUlJ,gBACpC8I,GAAuBU,EAAeG,GAGxC,IAAK,MAAM5M,KAAS7E,EAAagR,EAAUnJ,aAAc,CACvD+I,GAAuB/L,EAAMvO,KAAMmb,GAEnC,IAAK,MAAM9I,KAAO9D,EAAMrL,KACtBoX,GAAuBjI,EAAIrS,KAAMmb,SAGhC,GAAIrM,GAAkB4L,GAC3B,IAAK,MAAMnM,KAAS7E,EAAagR,EAAUnJ,aACzC+I,GAAuB/L,EAAMvO,KAAMmb,GAKzC,OAAOA,EC3SF,SAASI,GAAepH,GAI7B,GAFAoF,GAAapF,GAETA,EAAOuF,mBACT,OAAOvF,EAAOuF,mBAIhB,MAAM8B,EAAU,IAAIC,wBAAwBtH,IA6C9C,SAA2BqH,GACzB,MAAMrH,EAASqH,EAAQrH,OACjByC,EAAYzC,EAAO0C,eAEpBD,EAEOlI,GAAakI,IACvB4E,EAAQE,YAAY,qDAAqD1jB,EAAQ4e,MAAe+E,GAAqBxH,EAAQ,UAAYyC,EAAU9F,SAFnJ0K,EAAQE,YAAY,oCAAqCvH,EAAOrD,SAKlE,MAAMgG,EAAe3C,EAAO4C,kBAExBD,IAAiBpI,GAAaoI,IAChC0E,EAAQE,YAAkF,oEAAG1jB,EAAQ8e,MAAkB6E,GAAqBxH,EAAQ,aAAe2C,EAAahG,SAGlL,MAAMkG,EAAmB7C,EAAO8C,sBAE5BD,IAAqBtI,GAAasI,IACpCwE,EAAQE,YAAsF,wEAAG1jB,EAAQgf,MAAsB2E,GAAqBxH,EAAQ,iBAAmB6C,EAAiBlG,SA/DlM8K,CAAkBJ,GA+EpB,SAA4BA,GAC1B,IAAK,MAAMpE,KAAaoE,EAAQrH,OAAOgD,gBAErC,GAAKyB,GAAYxB,GAAjB,CAMAyE,GAAaL,EAASpE,GAGtB,IAAK,MAAM/E,KAAO+E,EAAUlU,KAE1B2Y,GAAaL,EAASnJ,GAEjB5C,GAAY4C,EAAIrS,OACnBwb,EAAQE,YAAY,gBAAgBtE,EAAUpoB,QAAQqjB,EAAIrjB,sCAA2CgJ,EAAQqa,EAAIrS,SAAUqS,EAAIvB,SAG7HwB,GAAmBD,IAAiC,MAAzBA,EAAIH,mBACjCsJ,EAAQE,YAAY,sBAAsBtE,EAAUpoB,QAAQqjB,EAAIrjB,+BAAgC,CAAC8sB,GAA2BzJ,EAAIvB,SAChIuB,EAAIvB,SAAS9Q,YAlBfwb,EAAQE,YAAY,+BAA+B1jB,EAAQof,MAAeA,GAAWtG,SAlFzFiL,CAAmBP,GAmHrB,SAAuBA,GACrB,MAAMQ,EAiOR,SAAgDR,GAI9C,MAAMS,EAAehqB,OAAOgY,OAAO,MAE7BiS,EAAY,GAEZC,EAA2BlqB,OAAOgY,OAAO,MAC/C,OAAOmS,EAIP,SAASA,EAAqBC,GAC5B,GAAIJ,EAAaI,EAASrtB,MACxB,OAGFitB,EAAaI,EAASrtB,OAAQ,EAC9BmtB,EAAyBE,EAASrtB,MAAQktB,EAAUjuB,OACpD,MAAM6T,EAAS4H,EAAa2S,EAAS9K,aAErC,IAAK,MAAMhD,KAASzM,EAClB,GAAIkN,GAAcT,EAAMvO,OAAS8O,GAAkBP,EAAMvO,KAAK2P,QAAS,CACrE,MAAM2M,EAAY/N,EAAMvO,KAAK2P,OACvB4M,EAAaJ,EAAyBG,EAAUttB,MAGtD,GAFAktB,EAAUxsB,KAAK6e,QAEIre,IAAfqsB,EACFH,EAAqBE,OAChB,CACL,MAAME,EAAYN,EAAUvsB,MAAM4sB,GAC5BE,EAAUD,EAAU3sB,KAAI6sB,GAAYA,EAAS1tB,OAAMwB,KAAK,KAC9DgrB,EAAQE,YAAY,kCAAkCY,EAAUttB,6DAA6DytB,MAAaD,EAAU3sB,KAAI6sB,GAAYA,EAAS5L,WAG/KoL,EAAU7T,MAId8T,EAAyBE,EAASrtB,WAAQkB,GAzQJysB,CAAuCnB,GACzEoB,EAAUpB,EAAQrH,OAAOwC,aAE/B,IAAK,MAAM3W,KAAQ0J,EAAakT,GAEzB1M,GAAYlQ,IAMZ2Y,GAAoB3Y,IACvB6b,GAAaL,EAASxb,GAGpB0O,GAAa1O,IAKN2O,GAAgB3O,IAHzB6c,GAAerB,EAASxb,GAExB8c,GAAmBtB,EAASxb,IAMnB4O,GAAY5O,GAErB+c,GAAqBvB,EAASxb,GACrB6O,GAAW7O,GAEpBgd,GAAmBxB,EAASxb,GACnB8O,GAAkB9O,KAE3Bid,GAAoBzB,EAASxb,GAE7Bgc,EAAgChc,KA7BhCwb,EAAQE,YAAY,wCAAwC1jB,EAAQgI,MAAUA,EAAK8Q,SAzHvFoM,CAAc1B,GAGd,MAAM2B,EAAS3B,EAAQ4B,YAEvB,OADAjJ,EAAOuF,mBAAqByD,EACrBA,EAeT,MAAM1B,wBACJ5qB,YAAYsjB,GACVhiB,KAAKkrB,QAAU,GACflrB,KAAKgiB,OAASA,EAGhBuH,YAAY5qB,EAASC,GACnB,MAAMM,EAASX,MAAMY,QAAQP,GAASA,EAAMf,OAAO0J,SAAW3I,EAE9DoB,KAAKmrB,SAAS,IAAI3sB,aAAaG,EAASO,IAG1CisB,SAAS1qB,GACPT,KAAKkrB,QAAQ3tB,KAAKkD,GAGpBwqB,YACE,OAAOjrB,KAAKkrB,SA4BhB,SAAS1B,GAAqBxH,EAAQhV,GACpC,MAAMoe,EAAiBC,GAAerJ,GAAQtiB,GAAQA,EAAK8Q,iBAE3D,IAAK,MAAM9Q,KAAQ0rB,EACjB,GAAI1rB,EAAKsN,YAAcA,EACrB,OAAOtN,EAAKmO,KAmClB,SAAS6b,GAAaL,EAAS3pB,GAE7B,MAAMe,GpBpHU,iBADe5D,EoBqHA6C,EAAK7C,OpBpHRwK,EAAU,EAAG,iCAErCxK,EAAKf,OAAS,GAAiB,MAAZe,EAAK,IAA0B,MAAZA,EAAK,GACtC,IAAI2B,aAAa,SAAS3B,4EAG9B4a,EAAQ2M,KAAKvnB,QAAlB,EACS,IAAI2B,aAAa,oDAAoD3B,iBARzE,IAA0BA,EoBuH3B4D,GACF4oB,EAAQ8B,SCpIL,SAAsBG,EAAkB1sB,EAAOE,GAEpD,MAAMC,EAAgBusB,aAA4B7sB,MAAQ6sB,EAAmB,IAAI7sB,MAAM,2BAA6BoH,EAAQylB,IAE5H,OAAI/sB,MAAMY,QAAQJ,EAAcD,MACvBC,EAGF,IAAIP,aAAaO,EAAcJ,QAASI,EAAcH,OAASA,EAAOG,EAAc1D,OAAQ0D,EAAcF,UAAWC,EAAMC,GD4H/GwsB,CAAa9qB,EAAOf,EAAKif,UA6C9C,SAAS+L,GAAerB,EAASxb,GAC/B,MAAM8B,EAAS4H,EAAa1J,EAAKuR,aAEX,IAAlBzP,EAAO7T,QACTutB,EAAQE,YAAY,QAAQ1b,EAAKhR,uCAAwC2uB,GAAY3d,IAGvF,IAAK,MAAMuO,KAASzM,EAAQ,CAE1B+Z,GAAaL,EAASjN,GAEjBqB,GAAarB,EAAMvO,OACtBwb,EAAQE,YAAY,eAAe1b,EAAKhR,QAAQuf,EAAMvf,qCAA0CgJ,EAAQuW,EAAMvO,SAAUuO,EAAMuC,SAAS9Q,MAIzI,IAAK,MAAMqS,KAAO9D,EAAMrL,KAAM,CAC5B,MAAM8O,EAAUK,EAAIrjB,KAEpB6sB,GAAaL,EAASnJ,GAEjB5C,GAAY4C,EAAIrS,OACnBwb,EAAQE,YAAY,eAAe1b,EAAKhR,QAAQuf,EAAMvf,QAAQgjB,mCAA8Cha,EAAQqa,EAAIrS,SAAUqS,EAAIvB,SAAS9Q,MAG7IsS,GAAmBD,IAAiC,MAAzBA,EAAIH,mBACjCsJ,EAAQE,YAAY,qBAAqB1b,EAAKhR,QAAQuf,EAAMvf,QAAQgjB,4BAAmC,CAAC8J,GAA2BzJ,EAAIvB,SACvIuB,EAAIvB,SAAS9Q,SAMrB,SAAS8c,GAAmBtB,EAASxb,GACnC,MAAM4d,EAAiB3rB,OAAOgY,OAAO,MAErC,IAAK,MAAM0Q,KAAS3a,EAAKwR,gBAClB7C,GAAgBgM,GAKjB3a,IAAS2a,EAKTiD,EAAejD,EAAM3rB,MACvBwsB,EAAQE,YAAY,QAAQ1b,EAAKhR,2BAA2B2rB,EAAM3rB,aAAc6uB,GAA+B7d,EAAM2a,KAIvHiD,EAAejD,EAAM3rB,OAAQ,EAC7B8uB,GAAgCtC,EAASxb,EAAM2a,GAC/CoD,GAAgCvC,EAASxb,EAAM2a,IAX7Ca,EAAQE,YAAY,QAAQ1b,EAAKhR,6EAA8E6uB,GAA+B7d,EAAM2a,IALpJa,EAAQE,YAAY,QAAQ1jB,EAAQgI,+DAAuEhI,EAAQ2iB,MAAWkD,GAA+B7d,EAAM2a,IAoBzK,SAASoD,GAAgCvC,EAASxb,EAAM2a,GACtD,MAAMqD,EAAehe,EAAKuR,YAE1B,IAAK,MAAM0M,KAAcvU,EAAaiR,EAAMpJ,aAAc,CACxD,MAAMM,EAAYoM,EAAWjvB,KACvBkvB,EAAYF,EAAanM,GAE/B,GAAKqM,EAAL,CAOKhK,GAAgBsH,EAAQrH,OAAQ+J,EAAUle,KAAMie,EAAWje,OAC9Dwb,EAAQE,YAAY,mBAAmBf,EAAM3rB,QAAQ6iB,kBAA+B7Z,EAAQimB,EAAWje,aAAaA,EAAKhR,QAAQ6iB,aAA0B7Z,EAAQkmB,EAAUle,SAAU,CACvLie,EAAWnN,SAAS9Q,KACpBke,EAAUpN,SAAS9Q,OAIrB,IAAK,MAAMme,KAAYF,EAAW/a,KAAM,CACtC,MAAM8O,EAAUmM,EAASnvB,KACnBovB,EAAUF,EAAUhb,KAAKgY,MAAK7I,GAAOA,EAAIrjB,OAASgjB,IAEnDoM,EAQArK,GAAYoK,EAASne,KAAMoe,EAAQpe,OACtCwb,EAAQE,YAAY,4BAA4Bf,EAAM3rB,QAAQ6iB,KAAaG,oBAA+Bha,EAAQmmB,EAASne,aAAkBA,EAAKhR,QAAQ6iB,KAAaG,eAA0Bha,EAAQomB,EAAQpe,SAAU,CAC3Nme,EAASrN,SAAS9Q,KAClBoe,EAAQtN,SAAS9Q,OAVjBwb,EAAQE,YAAY,4BAA4Bf,EAAM3rB,QAAQ6iB,KAAaG,oBAA0BhS,EAAKhR,QAAQ6iB,yBAAkC,CAACsM,EAASrN,QAASoN,EAAUpN,UAgBrL,IAAK,MAAMsN,KAAWF,EAAUhb,KAAM,CACpC,MAAM8O,EAAUoM,EAAQpvB,MACPivB,EAAW/a,KAAKgY,MAAK7I,GAAOA,EAAIrjB,OAASgjB,KAEzCM,GAAmB8L,IAClC5C,EAAQE,YAAY,gBAAgB1b,EAAKhR,QAAQ6iB,gCAAwCG,8CAAoD2I,EAAM3rB,QAAQ6iB,KAAc,CAACuM,EAAQtN,QAASmN,EAAWnN,gBAvCxM0K,EAAQE,YAAY,mBAAmBf,EAAM3rB,QAAQ6iB,kBAA0B7R,EAAKhR,4BAA6B,CAACivB,EAAWnN,WAAY6M,GAAY3d,MA6C3J,SAAS8d,GAAgCtC,EAASxb,EAAM2a,GACtD,MAAM0D,EAAkBre,EAAKwR,gBAE7B,IAAK,MAAM8M,KAAc3D,EAAMnJ,iBACgB,IAAzC6M,EAAgB/lB,QAAQgmB,IAC1B9C,EAAQE,YAAY4C,IAAete,EAAO,QAAQA,EAAKhR,yBAAyB2rB,EAAM3rB,qDAAuD,QAAQgR,EAAKhR,uBAAuBsvB,EAAWtvB,qCAAqC2rB,EAAM3rB,QAAS,IAAI6uB,GAA+BlD,EAAO2D,MAAgBT,GAA+B7d,EAAM2a,KAKrV,SAASoC,GAAqBvB,EAAS+C,GACrC,MAAMC,EAAcD,EAAM7L,WAEC,IAAvB8L,EAAYvwB,QACdutB,EAAQE,YAAY,cAAc6C,EAAMvvB,6CAA8C2uB,GAAYY,IAGpG,MAAME,EAAoBxsB,OAAOgY,OAAO,MAExC,IAAK,MAAMqR,KAAckD,EACnBC,EAAkBnD,EAAWtsB,MAC/BwsB,EAAQE,YAAY,cAAc6C,EAAMvvB,8BAA8BssB,EAAWtsB,aAAc0vB,GAAwBH,EAAOjD,EAAWtsB,QAI3IyvB,EAAkBnD,EAAWtsB,OAAQ,EAEhC0f,GAAa4M,IAChBE,EAAQE,YAAY,cAAc6C,EAAMvvB,yDAA8DgJ,EAAQsjB,MAAgBoD,GAAwBH,EAAOhlB,OAAO+hB,MAK1K,SAAS0B,GAAmBxB,EAAS7H,GACnC,MAAMqE,EAAarE,EAASP,YAEF,IAAtB4E,EAAW/pB,QACbutB,EAAQE,YAAY,aAAa/H,EAAS3kB,uCAAwC2uB,GAAYhK,IAGhG,IAAK,MAAMT,KAAa8E,EAAY,CAClC,MAAMlF,EAAYI,EAAUlkB,KAE5B6sB,GAAaL,EAAStI,GAEJ,SAAdJ,GAAsC,UAAdA,GAAuC,SAAdA,GACnD0I,EAAQE,YAAY,aAAa/H,EAAS3kB,8BAA8B8jB,KAAcI,EAAUpC,UAKtG,SAASmM,GAAoBzB,EAASa,GACpC,MAAMva,EAAS4H,EAAa2S,EAAS9K,aAEf,IAAlBzP,EAAO7T,QACTutB,EAAQE,YAAY,qBAAqBW,EAASrtB,uCAAwC2uB,GAAYtB,IAIxG,IAAK,MAAM9N,KAASzM,EAElB+Z,GAAaL,EAASjN,GAEjBkB,GAAYlB,EAAMvO,OACrBwb,EAAQE,YAAY,eAAeW,EAASrtB,QAAQuf,EAAMvf,oCAAyCgJ,EAAQuW,EAAMvO,SAAUuO,EAAMuC,SAAS9Q,MAGxI8T,GAAqBvF,IAAqC,MAA3BA,EAAM2D,mBACvCsJ,EAAQE,YAAY,wBAAwBW,EAASrtB,QAAQuf,EAAMvf,6BAA8B,CAAC8sB,GAA2BvN,EAAMuC,SACnIvC,EAAMuC,SAAS9Q,OAiDrB,SAAS2d,GAAY9kB,GACnB,MAAMiY,QACJA,EAAOC,kBACPA,GACElY,EACJ,OAAOiY,EAAUC,EAAoB,CAACD,GAAS6N,OAAO5N,GAAqB,CAACD,GAAWC,GAAqB,GAG9G,SAASyM,GAAe3kB,EAAQ+lB,GAC9B,IAAIC,EAAW,GAEf,IAAK,MAAMhtB,KAAQ8rB,GAAY9kB,GAE7BgmB,EAAWA,EAASF,OAAOC,EAAO/sB,IAAS,IAG7C,OAAOgtB,EAGT,SAAShB,GAA+B7d,EAAM2a,GAC5C,OAAO6C,GAAexd,GAAM8e,GAAYA,EAASjc,aAAY7S,QAAO+uB,GAAaA,EAAU/vB,KAAK1B,QAAUqtB,EAAM3rB,OAGlH,SAAS0vB,GAAwBH,EAAO5L,GACtC,OAAO6K,GAAee,GAAOS,GAAaA,EAAU3b,QAAOrT,QAAO8uB,GAAYA,EAAS9vB,KAAK1B,QAAUqlB,IAGxG,SAASmJ,GAA2BmD,GAElC,OAAOA,GAAgB5f,YAAY6b,MAAKrpB,GAAQA,EAAK7C,KAAK1B,QAAU4rB,GAA2BlqB,OE7a1F,SAASkwB,GAAY/K,EAAQ2K,GAElC,IAAIK,EAEJ,OAAIL,EAAStoB,OAASpD,EAAKwB,WACzBuqB,EAAYD,GAAY/K,EAAQ2K,EAAS9e,MAClCmf,GAAa,IAAI5P,YAAY4P,IAGlCL,EAAStoB,OAASpD,EAAKyB,eACzBsqB,EAAYD,GAAY/K,EAAQ2K,EAAS9e,MAClCmf,GAAa,IAAI3P,eAAe2P,IAIrCL,EAAStoB,OAASpD,EAAKuB,WAClBwf,EAAOoE,QAAQuG,EAAS9vB,KAAK1B,YAI7B2gB,GAAU,EAAG,yBAA2BjW,EAAQ8mB,ICtBpD,MAAMM,SACXvuB,YAAYsjB,EAGZkL,EAEAC,GACEntB,KAAKotB,QAAUpL,EACfhiB,KAAKqtB,WAAa,GAClBrtB,KAAKstB,iBAAmB,GACxBttB,KAAKutB,gBAAkB,GACvBvtB,KAAKwtB,eAAiB,GACtBxtB,KAAKytB,mBAAqB,GAC1BztB,KAAK0tB,WAAa,KAClB1tB,KAAK2tB,UAAY,KACjB3tB,KAAK4tB,WAAa,KAClB5tB,KAAK6tB,aAAeX,GAAiBY,GAEjCX,IACE7P,GAAY6P,IACdntB,KAAKutB,gBAAgBhwB,KAAK4vB,GAGxBxP,GAAgBwP,IAClBntB,KAAKstB,iBAAiB/vB,KAAK4vB,GAGzB1P,GAAa0P,IACfntB,KAAKqtB,WAAW9vB,KAAK4vB,IAK3B/G,UACE,GAAIpmB,KAAKqtB,WAAWvxB,OAAS,EAC3B,OAAOkE,KAAKqtB,WAAWrtB,KAAKqtB,WAAWvxB,OAAS,GAIpDiyB,gBACE,GAAI/tB,KAAKstB,iBAAiBxxB,OAAS,EACjC,OAAOkE,KAAKstB,iBAAiBttB,KAAKstB,iBAAiBxxB,OAAS,GAIhEkyB,eACE,GAAIhuB,KAAKutB,gBAAgBzxB,OAAS,EAChC,OAAOkE,KAAKutB,gBAAgBvtB,KAAKutB,gBAAgBzxB,OAAS,GAI9DmyB,qBACE,GAAIjuB,KAAKutB,gBAAgBzxB,OAAS,EAChC,OAAOkE,KAAKutB,gBAAgBvtB,KAAKutB,gBAAgBzxB,OAAS,GAI9DgyB,cACE,GAAI9tB,KAAKwtB,eAAe1xB,OAAS,EAC/B,OAAOkE,KAAKwtB,eAAextB,KAAKwtB,eAAe1xB,OAAS,GAI5DoyB,kBACE,GAAIluB,KAAKytB,mBAAmB3xB,OAAS,EACnC,OAAOkE,KAAKytB,mBAAmBztB,KAAKytB,mBAAmB3xB,OAAS,GAIpEgtB,eACE,OAAO9oB,KAAK0tB,WAGdS,cACE,OAAOnuB,KAAK2tB,UAGdS,eACE,OAAOpuB,KAAK4tB,WAGd7W,MAAMrX,GACJ,MAAMsiB,EAAShiB,KAAKotB,QAKpB,OAAQ1tB,EAAK2E,MACX,KAAKpD,EAAKM,cACR,CACE,MAAMgnB,EAAYvK,GAAahe,KAAKomB,WAEpCpmB,KAAKstB,iBAAiB/vB,KAAKogB,GAAgB4K,GAAaA,OAAYxqB,GAEpE,MAGJ,KAAKkD,EAAKO,MACR,CACE,MAAM8kB,EAAatmB,KAAK+tB,gBACxB,IAAIM,EACAlE,EAEA7D,IACF+H,EAAWruB,KAAK6tB,aAAa7L,EAAQsE,EAAY5mB,GAE7C2uB,IACFlE,EAAYkE,EAASxgB,OAIzB7N,KAAKwtB,eAAejwB,KAAK8wB,GAEzBruB,KAAKqtB,WAAW9vB,KAAKkgB,GAAa0M,GAAaA,OAAYpsB,GAE3D,MAGJ,KAAKkD,EAAKsB,UACRvC,KAAK0tB,WAAa1L,EAAO8G,aAAappB,EAAK7C,KAAK1B,OAChD,MAEF,KAAK8F,EAAKI,qBACR,CACE,IAAIwM,EAEJ,OAAQnO,EAAKsN,WACX,IAAK,QACHa,EAAOmU,EAAO0C,eACd,MAEF,IAAK,WACH7W,EAAOmU,EAAO4C,kBACd,MAEF,IAAK,eACH/W,EAAOmU,EAAO8C,sBAIlB9kB,KAAKqtB,WAAW9vB,KAAKgf,GAAa1O,GAAQA,OAAO9P,GAEjD,MAGJ,KAAKkD,EAAKU,gBACV,KAAKV,EAAKW,oBACR,CACE,MAAM0sB,EAAmB5uB,EAAKuP,cACxBsf,EAAaD,EAAmBvB,GAAY/K,EAAQsM,GAAoBtQ,GAAahe,KAAKomB,WAEhGpmB,KAAKqtB,WAAW9vB,KAAKkgB,GAAa8Q,GAAcA,OAAaxwB,GAE7D,MAGJ,KAAKkD,EAAKK,oBACR,CACE,MAAMktB,EAAYzB,GAAY/K,EAAQtiB,EAAKmO,MAE3C7N,KAAKutB,gBAAgBhwB,KAAK+f,GAAYkR,GAAaA,OAAYzwB,GAE/D,MAGJ,KAAKkD,EAAKQ,SACR,CACE,IAAIgtB,EACAC,EACJ,MAAMC,EAAmB3uB,KAAK8oB,gBAAkB9oB,KAAK8tB,cAEjDa,IACFF,EAASE,EAAiB5d,KAAKgY,MAAK7I,GAAOA,EAAIrjB,OAAS6C,EAAK7C,KAAK1B,QAE9DszB,IACFC,EAAUD,EAAO5gB,OAIrB7N,KAAK2tB,UAAYc,EAEjBzuB,KAAKytB,mBAAmBlwB,KAAKkxB,EAASA,EAAO1gB,kBAAehQ,GAE5DiC,KAAKutB,gBAAgBhwB,KAAK+f,GAAYoR,GAAWA,OAAU3wB,GAE3D,MAGJ,KAAKkD,EAAKmB,KACR,CACE,MAAMwsB,EAAW9Q,GAAgB9d,KAAKguB,gBAChCvK,EAAW7G,GAAWgS,GAAYA,EAASpR,OAASoR,EAE1D5uB,KAAKytB,mBAAmBlwB,UAAKQ,GAE7BiC,KAAKutB,gBAAgBhwB,KAAK+f,GAAYmG,GAAYA,OAAW1lB,GAE7D,MAGJ,KAAKkD,EAAKqB,aACR,CACE,MAAMusB,EAAa7Q,GAAahe,KAAKguB,gBACrC,IAAIc,EACAC,EAEApS,GAAkBkS,KACpBE,EAAaF,EAAWzP,YAAY1f,EAAK7C,KAAK1B,OAE1C4zB,IACFD,EAAiBC,EAAWlhB,OAIhC7N,KAAKytB,mBAAmBlwB,KAAKwxB,EAAaA,EAAWhhB,kBAAehQ,GAEpEiC,KAAKutB,gBAAgBhwB,KAAK+f,GAAYwR,GAAkBA,OAAiB/wB,GAEzE,MAGJ,KAAKkD,EAAKkB,KACR,CACE,MAAMqf,EAAWxD,GAAahe,KAAKguB,gBACnC,IAAIjN,EAEArE,GAAW8E,KACbT,EAAYS,EAASN,SAASxhB,EAAKvE,QAGrC6E,KAAK4tB,WAAa7M,EAClB,QAKR7J,MAAMxX,GACJ,OAAQA,EAAK2E,MACX,KAAKpD,EAAKM,cACRvB,KAAKstB,iBAAiBpX,MAEtB,MAEF,KAAKjV,EAAKO,MACRxB,KAAKwtB,eAAetX,MAEpBlW,KAAKqtB,WAAWnX,MAEhB,MAEF,KAAKjV,EAAKsB,UACRvC,KAAK0tB,WAAa,KAClB,MAEF,KAAKzsB,EAAKI,qBACV,KAAKJ,EAAKU,gBACV,KAAKV,EAAKW,oBACR5B,KAAKqtB,WAAWnX,MAEhB,MAEF,KAAKjV,EAAKK,oBACRtB,KAAKutB,gBAAgBrX,MAErB,MAEF,KAAKjV,EAAKQ,SACRzB,KAAK2tB,UAAY,KAEjB3tB,KAAKytB,mBAAmBvX,MAExBlW,KAAKutB,gBAAgBrX,MAErB,MAEF,KAAKjV,EAAKmB,KACV,KAAKnB,EAAKqB,aACRtC,KAAKytB,mBAAmBvX,MAExBlW,KAAKutB,gBAAgBrX,MAErB,MAEF,KAAKjV,EAAKkB,KACRnC,KAAK4tB,WAAa,OAY1B,SAASE,GAAY9L,EAAQsE,EAAY0I,GACvC,MAAMnyB,EAAOmyB,EAAUnyB,KAAK1B,MAE5B,OAAI0B,IAASqpB,GAAmBrpB,MAAQmlB,EAAO0C,iBAAmB4B,EACzDJ,GAGLrpB,IAASspB,GAAiBtpB,MAAQmlB,EAAO0C,iBAAmB4B,EACvDH,GAGLtpB,IAASwpB,GAAqBxpB,MAAQ8gB,GAAgB2I,GACjDD,GAGL9J,GAAa+J,IAAe9J,GAAgB8J,GACvCA,EAAWlH,YAAYviB,QADhC,EAUK,SAASoyB,GAAkBC,EAAUzZ,GAC1C,MAAO,CACLsB,MAAMrX,GACJwvB,EAASnY,MAAMrX,GACf,MAAMsX,EAAKL,EAAWlB,EAAS/V,EAAK2E,MAEpC,GAEA,GAAI2S,EAAI,CACN,MAAMxN,EAASwN,EAAGC,MAAMxB,EAASjH,WAUjC,YARezQ,IAAXyL,IACF0lB,EAAShY,MAAMxX,GAEX8E,EAAOgF,IACT0lB,EAASnY,MAAMvN,IAIZA,IAIX0N,MAAMxX,GACJ,MAAMsX,EAAKL,EAAWlB,EAAS/V,EAAK2E,MAEpC,GACA,IAAImF,EAOJ,OALIwN,IACFxN,EAASwN,EAAGC,MAAMxB,EAASjH,YAG7B0gB,EAAShY,MAAMxX,GACR8J,IC3WN,SAAS2lB,GAA2BzvB,GACzC,OAAOA,EAAK2E,OAASpD,EAAKI,sBAAwB3B,EAAK2E,OAASpD,EAAKW,oBAchE,SAASwtB,GAAqB1vB,GACnC,OAAOA,EAAK2E,OAASpD,EAAK4B,wBAA0BnD,EAAK2E,OAASpD,EAAK6B,wBAA0BpD,EAAK2E,OAASpD,EAAKgC,2BAA6BvD,EAAK2E,OAASpD,EAAKiC,uBAAyBxD,EAAK2E,OAASpD,EAAKkC,sBAAwBzD,EAAK2E,OAASpD,EAAKoC,6BAKtP,SAASgsB,GAAoB3vB,GAClC,OAAOA,EAAK2E,OAASpD,EAAKuC,uBAAyB9D,EAAK2E,OAASpD,EAAKwC,uBAAyB/D,EAAK2E,OAASpD,EAAKyC,0BAA4BhE,EAAK2E,OAASpD,EAAK0C,sBAAwBjE,EAAK2E,OAASpD,EAAK2C,qBAAuBlE,EAAK2E,OAASpD,EAAK4C,4BCbjP,SAASyrB,GAAmBjG,GACjC,MAAMrH,EAASqH,EAAQkG,YACjBC,EAAmBxN,EAASA,EAAOwC,aAAe1kB,OAAOgY,OAAO,MAChE2X,EAAe3vB,OAAOgY,OAAO,MAEnC,IAAK,MAAM4X,KAAOrG,EAAQsG,cAAcrjB,YAClC8iB,GAAqBM,KACvBD,EAAaC,EAAI7yB,KAAK1B,QAAS,GAInC,MAAMy0B,EAAY9vB,OAAO6G,KAAK6oB,GAAkBhD,OAAO1sB,OAAO6G,KAAK8oB,IACnE,MAAO,CACLzb,UAAUtU,EAAMmwB,EAAIla,EAAQma,EAAIha,GAC9B,MAAM0K,EAAW9gB,EAAK7C,KAAK1B,MAE3B,IAAKq0B,EAAiBhP,KAAciP,EAAajP,GAAW,CAC1D,MAAMsM,EAAiBhX,EAAU,IAAMH,EACjCoa,EAA0B,MAAlBjD,IAmBH3xB,EAnBuC2xB,GAoBhDvuB,MAAMY,QAAQhE,KDnCjB,SAAoCuE,GACzC,OAAOA,EAAK2E,OAASpD,EAAK0B,mBAAqBysB,GAAqB1vB,IAASA,EAAK2E,OAASpD,EAAKqC,qBCkC/D0sB,CAA2B70B,ID7BvD,SAAmCuE,GACxC,OAAOA,EAAK2E,OAASpD,EAAKsC,kBAAoB8rB,GAAoB3vB,GC4BIuwB,CAA0B90B,KAlB1F,GAAI40B,GAaZ,SAA4BvP,GAC1B,OAAgD,IAAzC0P,GAAkB/pB,QAAQqa,GAdd2P,CAAmB3P,GAC9B,OAGF,MAAM4P,EAAiBtX,EAAe0H,EAAUuP,EAAQG,GAAkB1D,OAAOoD,GAAaA,GAC9FvG,EAAQE,YAAY,IAAI/qB,aAAa,iBAAiBgiB,MAAepI,EAAWgY,GAAiB1wB,IAYzG,IAAmBvE,IANnB,MAAM+0B,GAAoB,IAAI7M,MAAyBkD,IAAoB7oB,KAAImQ,GAAQA,EAAKhR,OCpCrF,SAASwzB,GAAsBhH,GACpC,MAAMiH,EAAgB,GAChBC,EAAe,GACrB,MAAO,CACL1d,oBAAoBnT,IAClB4wB,EAAc/yB,KAAKmC,IACZ,GAGT2T,mBAAmB3T,IACjB6wB,EAAahzB,KAAKmC,IACX,GAGTkT,SAAU,CACRsE,QACE,MAAMsZ,EAAmB1wB,OAAOgY,OAAO,MAEvC,IAAK,MAAM9K,KAAasjB,EACtB,IAAK,MAAMG,KAAYpH,EAAQqH,kCAAkC1jB,GAC/DwjB,EAAiBC,EAAS5zB,KAAK1B,QAAS,EAI5C,IAAK,MAAMw1B,KAAeJ,EAAc,CACtC,MAAMK,EAAWD,EAAY9zB,KAAK1B,OAEC,IAA/Bq1B,EAAiBI,IACnBvH,EAAQE,YAAY,IAAI/qB,aAAa,aAAaoyB,oBAA4BD,QCvBnF,SAASE,GAAoBxH,GAClC,MAAMyH,EAAehxB,OAAOgY,OAAO,MAC7BkK,EAASqH,EAAQkG,YACjBwB,EAAoB/O,EAASA,EAAOgD,gBAAkBmC,GAE5D,IAAK,MAAMlC,KAAa8L,EACtBD,EAAa7L,EAAUpoB,MAAQooB,EAAU9kB,UAG3C,MAAM6wB,EAAiB3H,EAAQsG,cAAcrjB,YAE7C,IAAK,MAAMojB,KAAOsB,EACZtB,EAAIrrB,OAASpD,EAAKqC,uBACpBwtB,EAAapB,EAAI7yB,KAAK1B,OAASu0B,EAAIvvB,UAAUzC,KAAIb,GAAQA,EAAK1B,SAIlE,MAAO,CACL4Y,UAAUrU,EAAMuxB,EAAMC,EAASC,EAAOrb,GACpC,MAAMjZ,EAAO6C,EAAK7C,KAAK1B,MACjBgF,EAAY2wB,EAAaj0B,GAE/B,IAAKsD,EAEH,YADAkpB,EAAQE,YAAY,IAAI/qB,aAAa,uBAAuB3B,MAAU6C,IAIxE,MAAM0xB,EAUZ,SAAwCtb,GACtC,MAAMub,EAAYvb,EAAUA,EAAUha,OAAS,GAG/C,QAFCyC,MAAMY,QAAQkyB,IAAcvV,GAAU,GAE/BuV,EAAUhtB,MAChB,KAAKpD,EAAKI,qBACR,OA2DN,SAA0C2L,GACxC,OAAQA,GACN,IAAK,QACH,OAAOvF,EAAkBC,MAE3B,IAAK,WACH,OAAOD,EAAkBE,SAE3B,IAAK,eACH,OAAOF,EAAkBG,aAIpBkU,GAAU,EAAG,yBAA2BjW,EAAQmH,IAxE9CskB,CAAiCD,EAAUrkB,WAEpD,KAAK/L,EAAKO,MACR,OAAOiG,EAAkBjG,MAE3B,KAAKP,EAAKS,gBACR,OAAO+F,EAAkB/F,gBAE3B,KAAKT,EAAKU,gBACR,OAAO8F,EAAkB9F,gBAE3B,KAAKV,EAAKW,oBACR,OAAO6F,EAAkB7F,oBAE3B,KAAKX,EAAKK,oBACR,OAAOmG,EAAkBnG,oBAE3B,KAAKL,EAAK0B,kBACV,KAAK1B,EAAKsC,iBACR,OAAOkE,EAAkBI,OAE3B,KAAK5G,EAAK4B,uBACV,KAAK5B,EAAKuC,sBACR,OAAOiE,EAAkBK,OAE3B,KAAK7G,EAAK6B,uBACV,KAAK7B,EAAKwC,sBACR,OAAOgE,EAAkBpF,OAE3B,KAAKpB,EAAK8B,iBACR,OAAO0E,EAAkB1E,iBAE3B,KAAK9B,EAAKgC,0BACV,KAAKhC,EAAKyC,yBACR,OAAO+D,EAAkBO,UAE3B,KAAK/G,EAAKiC,sBACV,KAAKjC,EAAK0C,qBACR,OAAO8D,EAAkBQ,MAE3B,KAAKhH,EAAKkC,qBACV,KAAKlC,EAAK2C,oBACR,OAAO6D,EAAkBtF,KAE3B,KAAKlB,EAAKmC,sBACR,OAAOqE,EAAkBS,WAE3B,KAAKjH,EAAKoC,6BACV,KAAKpC,EAAK4C,4BACR,OAAO4D,EAAkBU,aAE3B,KAAKlH,EAAK+B,uBAGN,OADmB8S,EAAUA,EAAUha,OAAS,GAC9BuI,OAASpD,EAAKoC,6BAA+BoE,EAAkBW,uBAAyBX,EAAkBM,qBAtEpGwpB,CAA+Bzb,GAErDsb,IAA+D,IAA1CjxB,EAAUgG,QAAQirB,IACzC/H,EAAQE,YAAY,IAAI/qB,aAAa,eAAe3B,yBAA4Bu0B,KAAsB1xB,MChCvG,SAAS8xB,GAAgCnI,GAC9C,MAAMoI,EAAqB3xB,OAAOgY,OAAO,MACnCkK,EAASqH,EAAQkG,YACjBwB,EAAoB/O,EAASA,EAAOgD,gBAAkBmC,GAE5D,IAAK,MAAMlC,KAAa8L,EACtBU,EAAmBxM,EAAUpoB,OAASooB,EAAUC,aAGlD,MAAM8L,EAAiB3H,EAAQsG,cAAcrjB,YAE7C,IAAK,MAAMojB,KAAOsB,EACZtB,EAAIrrB,OAASpD,EAAKqC,uBACpBmuB,EAAmB/B,EAAI7yB,KAAK1B,QAAUu0B,EAAI5d,YAI9C,MAAM4f,EAAmB5xB,OAAOgY,OAAO,MACjC6Z,EAAoB7xB,OAAOgY,OAAO,MACxC,MAAO,CAILf,MAAMrX,GACJ,GAAuB,MAAnBA,EAAKwN,WACP,OAGF,IAAI0kB,EAEJ,GAAIlyB,EAAK2E,OAASpD,EAAK0B,mBAAqBjD,EAAK2E,OAASpD,EAAKsC,iBAC7DquB,EAAiBF,OACZ,GAAItC,GAAqB1vB,IAAS2vB,GAAoB3vB,GAAO,CAClE,MAAM8gB,EAAW9gB,EAAK7C,KAAK1B,MAC3By2B,EAAiBD,EAAkBnR,QAEZziB,IAAnB6zB,IACFD,EAAkBnR,GAAYoR,EAAiB9xB,OAAOgY,OAAO,YAG/D8Z,EAAiB9xB,OAAOgY,OAAO,MAGjC,IAAK,MAAMmN,KAAavlB,EAAKwN,WAAY,CACvC,MAAM2kB,EAAgB5M,EAAUpoB,KAAK1B,MAEjCs2B,EAAmBI,KACjBD,EAAeC,GACjBxI,EAAQE,YAAY,IAAI/qB,aAAa,mBAAmBqzB,6CAA0D,CAACD,EAAeC,GAAgB5M,KAElJ2M,EAAeC,GAAiB5M,MC1BrC,SAAS6M,GAAmCzI,GACjD,MAAM0I,EAAgBjyB,OAAOgY,OAAO,MAC9BkK,EAASqH,EAAQkG,YACjBwB,EAAoB/O,EAASA,EAAOgD,gBAAkBmC,GAE5D,IAAK,MAAMlC,KAAa8L,EACtBgB,EAAc9M,EAAUpoB,MAAQooB,EAAUlU,KAAKrT,KAAIwiB,GAAOA,EAAIrjB,OAGhE,MAAMm0B,EAAiB3H,EAAQsG,cAAcrjB,YAE7C,IAAK,MAAMojB,KAAOsB,EAChB,GAAItB,EAAIrrB,OAASpD,EAAKqC,qBAAsB,CAE1C,MAAM0uB,EAAYtC,EAAIlhB,WAAa,GACnCujB,EAAcrC,EAAI7yB,KAAK1B,OAAS62B,EAAUt0B,KAAIwiB,GAAOA,EAAIrjB,KAAK1B,QAIlE,MAAO,CACL4Y,UAAUke,GACR,MAAMJ,EAAgBI,EAAcp1B,KAAK1B,MACnC+2B,EAAYH,EAAcF,GAEhC,GAAII,EAAczjB,WAAa0jB,EAC7B,IAAK,MAAMC,KAAWF,EAAczjB,UAAW,CAC7C,MAAMqR,EAAUsS,EAAQt1B,KAAK1B,MAE7B,IAAoC,IAAhC+2B,EAAU/rB,QAAQ0Z,GAAiB,CACrC,MAAMpH,EAAcK,EAAe+G,EAASqS,GAC5C7I,EAAQE,YAAY,IAAI/qB,aAAa,qBAAqBqhB,qBAA2BgS,MAAoBzZ,EAAWK,GAAc0Z,KAKxI,OAAO,IC9DN,SAASC,GAAwB/I,GACtC,IAAIgJ,EAAgBvyB,OAAOgY,OAAO,MAClC,MAAO,CACL7E,QACEof,EAAgBvyB,OAAOgY,OAAO,OAGhC/D,YACEse,EAAgBvyB,OAAOgY,OAAO,OAGhC5E,SAASxT,GACP,MAAMmgB,EAAUngB,EAAK7C,KAAK1B,MAQ1B,OANIk3B,EAAcxS,GAChBwJ,EAAQE,YAAY,IAAI/qB,aAAa,yCAAyCqhB,MAAa,CAACwS,EAAcxS,GAAUngB,EAAK7C,QAEzHw1B,EAAcxS,GAAWngB,EAAK7C,MAGzB,ICmDb,SAASy1B,GAAiBjJ,EAAS3pB,GAEjC,MAAM6yB,EAAelJ,EAAQ2E,eAE7B,IAAKuE,EACH,OAGF,MAAM1kB,EAAOmQ,GAAauU,GAE1B,GAAK7U,GAAW7P,GAQhB,IAKE,QAAoB9P,IAJA8P,EAAK6Q,aAAahf,OAAM3B,GAIb,CAC7B,MAAMy0B,EAAU3sB,EAAQ0sB,GACxBlJ,EAAQE,YAAY,IAAI/qB,aAAa,2BAA2Bg0B,aAAmB1X,EAAMpb,MAAUA,KAErG,MAAOe,GACP,MAAM+xB,EAAU3sB,EAAQ0sB,GAEpB9xB,aAAiBjC,aACnB6qB,EAAQE,YAAY9oB,GAEpB4oB,EAAQE,YAAY,IAAI/qB,aAAa,2BAA2Bg0B,aAAmB1X,EAAMpb,OAAYe,EAAM9B,QAASe,OAAM3B,OAAWA,OAAWA,EAAW0C,QAvB/J,CACE,MAAM+xB,EAAU3sB,EAAQ0sB,GACxBlJ,EAAQE,YAAY,IAAI/qB,aAAa,2BAA2Bg0B,aAAmB1X,EAAMpb,MAAUA,KC5ChG,SAAS+yB,GAA0CpJ,GACxD,MAAMqJ,EAAkB5yB,OAAOgY,OAAO,MAChCkK,EAASqH,EAAQkG,YACjBwB,EAAoB/O,EAASA,EAAOgD,gBAAkBmC,GAE5D,IAAK,MAAMlC,KAAa8L,EACtB2B,EAAgBzN,EAAUpoB,MAAQ+a,EAAOqN,EAAUlU,KAAKlT,OAAOsiB,KAAqBD,GAAOA,EAAIrjB,OAGjG,MAAMm0B,EAAiB3H,EAAQsG,cAAcrjB,YAE7C,IAAK,MAAMojB,KAAOsB,EAChB,GAAItB,EAAIrrB,OAASpD,EAAKqC,qBAAsB,CAE1C,MAAMqvB,EAAWjD,EAAIlhB,WAAa,GAClCkkB,EAAgBhD,EAAI7yB,KAAK1B,OAASyc,EAAO+a,EAAS90B,OAAO+0B,KAAyB1S,GAAOA,EAAIrjB,KAAK1B,QAItG,MAAO,CACL4Y,UAAW,CAETmD,MAAM+a,GACJ,MAAMJ,EAAgBI,EAAcp1B,KAAK1B,MACnC03B,EAAeH,EAAgBb,GAErC,GAAIgB,EAAc,CAEhB,MACMC,EAAalb,EADFqa,EAAczjB,WAAa,IACR0R,GAAOA,EAAIrjB,KAAK1B,QAEpD,IAAK,MAAM0kB,KAAW/f,OAAO6G,KAAKksB,GAChC,IAAKC,EAAWjT,GAAU,CACxB,MAAM6O,EAAUmE,EAAahT,GAAShS,KAChCklB,EAAa1W,GAAOqS,GAAW7oB,EAAQ6oB,GAAW5T,EAAM4T,GAC9DrF,EAAQE,YAAY,IAAI/qB,aAAa,eAAeqzB,gBAA4BhS,eAAqBkT,2CAAqDd,SAUxK,SAASW,GAAuB1S,GAC9B,OAAOA,EAAIrS,KAAKxJ,OAASpD,EAAKyB,eAAqC,MAApBwd,EAAInS,aChCrD,SAASilB,GAAqBhR,EAAQiR,EAASC,EAAiBX,EAAcY,GAC5E,GAAItW,GAAc0V,KAAkB1V,GAAcoW,GAAU,CAC1D,MACMG,OAAmDr1B,IAAzBo1B,EAEhC,KAH0D,MAAnBD,GAA2BA,EAAgB7uB,OAASpD,EAAKiB,QAGxDkxB,EACtC,OAAO,EAIT,OAAOrR,GAAgBC,EAAQiR,EADFV,EAAa/U,QAI5C,OAAOuE,GAAgBC,EAAQiR,EAASV,GClE1C,SAASc,GAAcrM,GACrB,OAAIzoB,MAAMY,QAAQ6nB,GACTA,EAAOtpB,KAAI,EAAE41B,EAAcC,KAAe,cAAcD,uBAAoCD,GAAcE,KAAYl1B,KAAK,SAG7H2oB,EAqHT,SAASwM,GAAyCnK,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBrU,EAAUsU,GACzJ,MAAMpD,EAAWpH,EAAQyK,YAAYD,GAErC,IAAKpD,EACH,OAGF,MAAOsD,EAAWC,GAAkBC,GAAoC5K,EAASqK,EAA8BjD,GAE/G,GAAIlR,IAAawU,EAAjB,CAMAG,GAAwB7K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBrU,EAAUwU,GAGjI,IAAK,IAAIz2B,EAAI,EAAGA,EAAI02B,EAAel4B,OAAQwB,IACzCk2B,GAAyCnK,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBrU,EAAUyU,EAAe12B,KAMrK,SAAS62B,GAAiC9K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBQ,EAAeC,GAEtJ,GAAID,IAAkBC,EACpB,OAIF,GAAIV,EAAsB1K,IAAImL,EAAeC,EAAeT,GAC1D,OAGFD,EAAsBzK,IAAIkL,EAAeC,EAAeT,GACxD,MAAMU,EAAYjL,EAAQyK,YAAYM,GAChCG,EAAYlL,EAAQyK,YAAYO,GAEtC,IAAKC,IAAcC,EACjB,OAGF,MAAOC,EAAWC,GAAkBR,GAAoC5K,EAASqK,EAA8BY,IACxGP,EAAWC,GAAkBC,GAAoC5K,EAASqK,EAA8Ba,GAG/GL,GAAwB7K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBY,EAAWT,GAGlI,IAAK,IAAIzZ,EAAI,EAAGA,EAAI0Z,EAAel4B,OAAQwe,IACzC6Z,GAAiC9K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBQ,EAAeJ,EAAe1Z,IAKhK,IAAK,IAAIhd,EAAI,EAAGA,EAAIm3B,EAAe34B,OAAQwB,IACzC62B,GAAiC9K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBa,EAAen3B,GAAI+2B,GAuEvJ,SAASH,GAAwB7K,EAASoK,EAAWC,EAA8BC,EAAuBe,EAAkCF,EAAWT,GAMrJ,IAAK,MAAMT,KAAgBxzB,OAAO6G,KAAK6tB,GAAY,CACjD,MAAMG,EAAUZ,EAAUT,GAE1B,GAAIqB,EAAS,CACX,MAAMC,EAAUJ,EAAUlB,GAE1B,IAAK,IAAIh2B,EAAI,EAAGA,EAAIs3B,EAAQ94B,OAAQwB,IAClC,IAAK,IAAIgd,EAAI,EAAGA,EAAIqa,EAAQ74B,OAAQwe,IAAK,CACvC,MAAMua,EAAWC,GAAazL,EAASqK,EAA8BC,EAAuBe,EAAkCpB,EAAcsB,EAAQt3B,GAAIq3B,EAAQra,IAE5Jua,GACFpB,EAAUl2B,KAAKs3B,MAU3B,SAASC,GAAazL,EAASqK,EAA8BC,EAAuBe,EAAkCpB,EAAcyB,EAAQC,GAC1I,MAAOC,EAAaC,EAAOC,GAAQJ,GAC5BK,EAAaC,EAAOC,GAAQN,EAS7BpB,EAAuBc,GAAoCO,IAAgBG,GAAe7Y,GAAa0Y,IAAgB1Y,GAAa6Y,GAE1I,IAAKxB,EAAsB,CAEzB,MAAM2B,EAAQL,EAAMr4B,KAAK1B,MACnBq6B,EAAQH,EAAMx4B,KAAK1B,MAEzB,GAAIo6B,IAAUC,EACZ,MAAO,CAAC,CAAClC,EAAc,IAAIiC,WAAeC,2BAAgC,CAACN,GAAQ,CAACG,IAQtF,IAyBJ,SAAuBI,EAAYC,GACjC,GAAID,EAAW35B,SAAW45B,EAAW55B,OACnC,OAAO,EAGT,OAAO25B,EAAWE,OAAMC,IACtB,MAAMC,EAAYH,EAAW3M,MAAK+M,GAAYA,EAASj5B,KAAK1B,QAAUy6B,EAAU/4B,KAAK1B,QAErF,QAAK06B,IAQUE,EAJEH,EAAUz6B,MAIJ66B,EAJWH,EAAU16B,MAKvC2f,EAAMib,KAAYjb,EAAMkb,IADjC,IAAmBD,EAAQC,KAzClBC,CAJSf,EAAM1mB,WAAa,GAEnB6mB,EAAM7mB,WAAa,IAG/B,MAAO,CAAC,CAAC8kB,EAAc,iCAAkC,CAAC4B,GAAQ,CAACG,IAKvE,MAAMa,EAAQf,GAAMtnB,KACdsoB,EAAQb,GAAMznB,KAEpB,GAAIqoB,GAASC,GAASC,GAAgBF,EAAOC,GAC3C,MAAO,CAAC,CAAC7C,EAAc,kCAAkCztB,EAAQqwB,YAAgBrwB,EAAQswB,OAAY,CAACjB,GAAQ,CAACG,IAMjH,MAAMgB,EAAgBnB,EAAM/nB,aACtBmpB,EAAgBjB,EAAMloB,aAE5B,GAAIkpB,GAAiBC,EAAe,CAElC,OA6HJ,SAA2B7C,EAAWH,EAAc4B,EAAOG,GACzD,GAAI5B,EAAU33B,OAAS,EACrB,MAAO,CAAC,CAACw3B,EAAcG,EAAU/1B,KAAI,EAAEspB,KAAYA,KAAUyM,EAAUj0B,QAAO,CAAC+2B,IAAc3B,KAAa2B,EAAU/J,OAAOoI,IAAU,CAACM,IAASzB,EAAUj0B,QAAO,CAAC+2B,KAAe5B,KAAa4B,EAAU/J,OAAOmI,IAAU,CAACU,KA/HlNmB,CA3IX,SAA8CnN,EAASqK,EAA8BC,EAAuBC,EAAsBqB,EAAaoB,EAAejB,EAAakB,GACzK,MAAM7C,EAAY,IACXe,EAAWC,GAAkBgC,GAA0BpN,EAASqK,EAA8BuB,EAAaoB,IAC3GtC,EAAWC,GAAkByC,GAA0BpN,EAASqK,EAA8B0B,EAAakB,GAKlH,GAHApC,GAAwB7K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBY,EAAWT,GAGpG,IAA1BC,EAAel4B,OACjB,IAAK,IAAIwe,EAAI,EAAGA,EAAI0Z,EAAel4B,OAAQwe,IACzCkZ,GAAyCnK,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBY,EAAWR,EAAe1Z,IAMtK,GAA8B,IAA1Bma,EAAe34B,OACjB,IAAK,IAAIwB,EAAI,EAAGA,EAAIm3B,EAAe34B,OAAQwB,IACzCk2B,GAAyCnK,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBG,EAAWU,EAAen3B,IAOtK,IAAK,IAAIA,EAAI,EAAGA,EAAIm3B,EAAe34B,OAAQwB,IACzC,IAAK,IAAIgd,EAAI,EAAGA,EAAI0Z,EAAel4B,OAAQwe,IACzC6Z,GAAiC9K,EAASoK,EAAWC,EAA8BC,EAAuBC,EAAsBa,EAAen3B,GAAI02B,EAAe1Z,IAItK,OAAOmZ,EA2GaiD,CAAqCrN,EAASqK,EAA8BC,EAAuBC,EAAsB5V,GAAakY,GAAQG,EAAerY,GAAamY,GAAQG,GAChKhD,EAAc4B,EAAOG,IA2B7D,SAASe,GAAgBF,EAAOC,GAC9B,OAAIvZ,GAAWsZ,IACNtZ,GAAWuZ,IAASC,GAAgBF,EAAM1Y,OAAQ2Y,EAAM3Y,UAG7DZ,GAAWuZ,KAIXtZ,GAAcqZ,IACTrZ,GAAcsZ,IAASC,GAAgBF,EAAM1Y,OAAQ2Y,EAAM3Y,UAGhEX,GAAcsZ,OAIdzY,GAAWwY,KAAUxY,GAAWyY,KAC3BD,IAAUC,GASrB,SAASM,GAA0BpN,EAASqK,EAA8BpN,EAAYnZ,GACpF,IAAIwpB,EAASjD,EAA6B9yB,IAAIuM,GAE9C,IAAKwpB,EAAQ,CACX,MAAMC,EAAc92B,OAAOgY,OAAO,MAC5B+e,EAAgB/2B,OAAOgY,OAAO,MAEpCgf,GAA+BzN,EAAS/C,EAAYnZ,EAAcypB,EAAaC,GAE/EF,EAAS,CAACC,EAAa92B,OAAO6G,KAAKkwB,IACnCnD,EAA6BqD,IAAI5pB,EAAcwpB,GAGjD,OAAOA,EAKT,SAAS1C,GAAoC5K,EAASqK,EAA8BjD,GAElF,MAAMkG,EAASjD,EAA6B9yB,IAAI6vB,EAAStjB,cAEzD,GAAIwpB,EACF,OAAOA,EAGT,MAAMK,EAAejK,GAAY1D,EAAQkG,YAAakB,EAASxhB,eAC/D,OAAOwnB,GAA0BpN,EAASqK,EAA8BsD,EAAcvG,EAAStjB,cAGjG,SAAS2pB,GAA+BzN,EAAS/C,EAAYnZ,EAAcypB,EAAaC,GACtF,IAAK,MAAMI,KAAa9pB,EAAae,WACnC,OAAQ+oB,EAAU5yB,MAChB,KAAKpD,EAAKO,MACR,CACE,MAAMke,EAAYuX,EAAUp6B,KAAK1B,MACjC,IAAIkzB,GAEA9R,GAAa+J,IAAe9J,GAAgB8J,MAC9C+H,EAAW/H,EAAWlH,YAAYM,IAGpC,MAAM4T,EAAe2D,EAAU1oB,MAAQ0oB,EAAU1oB,MAAMpT,MAAQukB,EAE1DkX,EAAYtD,KACfsD,EAAYtD,GAAgB,IAG9BsD,EAAYtD,GAAc/1B,KAAK,CAAC+oB,EAAY2Q,EAAW5I,IACvD,MAGJ,KAAKptB,EAAKS,gBACRm1B,EAAcI,EAAUp6B,KAAK1B,QAAS,EACtC,MAEF,KAAK8F,EAAKU,gBACR,CACE,MAAMsN,EAAgBgoB,EAAUhoB,cAC1BioB,EAAqBjoB,EAAgB8d,GAAY1D,EAAQkG,YAAatgB,GAAiBqX,EAE7FwQ,GAA+BzN,EAAS6N,EAAoBD,EAAU9pB,aAAcypB,EAAaC,GAEjG,QAmBV,MAAMM,QACJz4B,cACEsB,KAAKo3B,MAAQt3B,OAAOgY,OAAO,MAG7BmR,IAAI5d,EAAGC,EAAGsoB,GACR,MAAMyD,EAAQr3B,KAAKo3B,MAAM/rB,GACnB7B,EAAS6tB,GAASA,EAAM/rB,GAE9B,YAAevN,IAAXyL,KAOyB,IAAzBoqB,IACgB,IAAXpqB,GAMX0f,IAAI7d,EAAGC,EAAGsoB,GACR5zB,KAAKs3B,YAAYjsB,EAAGC,EAAGsoB,GAEvB5zB,KAAKs3B,YAAYhsB,EAAGD,EAAGuoB,GAGzB0D,YAAYjsB,EAAGC,EAAGsoB,GAChB,IAAIl2B,EAAMsC,KAAKo3B,MAAM/rB,GAEhB3N,IACHA,EAAMoC,OAAOgY,OAAO,MACpB9X,KAAKo3B,MAAM/rB,GAAK3N,GAGlBA,EAAI4N,GAAKsoB,GCnfN,SAAS2D,GAA0BlO,GACxC,MAAMmO,EAAiB,GACvB,IAAIC,EAAa33B,OAAOgY,OAAO,MAC/B,MAAO,CACLjE,YAAa,CACXkD,QACEygB,EAAej6B,KAAKk6B,GACpBA,EAAa33B,OAAOgY,OAAO,OAG7BZ,QACEugB,EAAaD,EAAethB,QAKhCpC,YAAYpU,GACV,MAAMggB,EAAYhgB,EAAK7C,KAAK1B,MAExBs8B,EAAW/X,GACb2J,EAAQE,YAAY,IAAI/qB,aAAa,4CAA4CkhB,MAAe,CAAC+X,EAAW/X,GAAYhgB,EAAK7C,QAE7H46B,EAAW/X,GAAahgB,EAAK7C,OCkBrC,SAAS66B,GAAS7pB,EAAM6R,GACtB,SAAInD,GAAa1O,IAAS2O,GAAgB3O,IAAS8O,GAAkB9O,KAC7B,MAA/BA,EAAKuR,YAAYM,GCY5B,MAAMiY,GAAmB,CACvB,CAAC12B,EAAK4B,wBAAyB5B,EAAKuC,sBACpC,CAACvC,EAAK6B,wBAAyB7B,EAAKwC,sBACpC,CAACxC,EAAKgC,2BAA4BhC,EAAKyC,yBACvC,CAACzC,EAAKiC,uBAAwBjC,EAAK0C,qBACnC,CAAC1C,EAAKkC,sBAAuBlC,EAAK2C,oBAClC,CAAC3C,EAAKoC,8BAA+BpC,EAAK4C,6BCDrC,MAAM+zB,GAAiB93B,OAAOoB,OAAO,CCzDrC,SAAmCmoB,GACxC,MAAO,CACLzW,SAASlT,GACP,IAAK,MAAMm4B,KAAcn4B,EAAK4M,YAC5B,IAAK6iB,GAA2B0I,GAAa,CAC3C,MAAMC,EAAUD,EAAWxzB,OAASpD,EAAK0B,mBAAqBk1B,EAAWxzB,OAASpD,EAAKsC,iBAAmB,SAAW,IAAMs0B,EAAWh7B,KAAK1B,MAAQ,IACnJkuB,EAAQE,YAAY,IAAI/qB,aAAa,OAAOs5B,kCAAyCD,IAIzF,OAAO,KCbN,SAAkCxO,GACvC,MAAM0O,EAAsBj4B,OAAOgY,OAAO,MAC1C,MAAO,CACLjF,oBAAoBnT,GAClB,MAAMs4B,EAAgBt4B,EAAK7C,KAU3B,OARIm7B,IACED,EAAoBC,EAAc78B,OACpCkuB,EAAQE,YAAY,IAAI/qB,aAAa,0CAA0Cw5B,EAAc78B,UAAW,CAAC48B,EAAoBC,EAAc78B,OAAQ68B,KAEnJD,EAAoBC,EAAc78B,OAAS68B,IAIxC,GAGT3kB,mBAAoB,KAAM,ICfvB,SAAoCgW,GACzC,IAAI4O,EAAiB,EACrB,MAAO,CACLrlB,SAASlT,GACPu4B,EAAiBv4B,EAAK4M,YAAYzO,QAAOg6B,GAAcA,EAAWxzB,OAASpD,EAAKI,uBAAsBvF,QAGxG+W,oBAAoBnT,IACbA,EAAK7C,MAAQo7B,EAAiB,GACjC5O,EAAQE,YAAY,IAAI/qB,aAAa,+DAAgEkB,OCXtG,SAAsC2pB,GAC3C,MAAO,CACLxW,oBAAoBnT,GACK,iBAAnBA,EAAKsN,WACqC,IAAxCtN,EAAKyN,aAAae,WAAWpS,QAC/ButB,EAAQE,YAAY,IAAI/qB,aAAakB,EAAK7C,KAAO,iBAAiB6C,EAAK7C,KAAK1B,+CAAiD,+DAAgEuE,EAAKyN,aAAae,WAAW1Q,MAAM,QJuD9E8xB,GKvDrJ,SAAuCjG,GAC5C,MAAO,CACLjW,eAAe1T,GACb,MAAMuP,EAAgBvP,EAAKuP,cAE3B,GAAIA,EAAe,CACjB,MAAMpB,EAAOkf,GAAY1D,EAAQkG,YAAatgB,GAE9C,GAAIpB,IAAS8P,GAAgB9P,GAAO,CAClC,MAAM2kB,EAAU1X,EAAM7L,GACtBoa,EAAQE,YAAY,IAAI/qB,aAAa,oDAAoDg0B,MAAavjB,OAK5GoE,mBAAmB3T,GACjB,MAAMmO,EAAOkf,GAAY1D,EAAQkG,YAAa7vB,EAAKuP,eAEnD,GAAIpB,IAAS8P,GAAgB9P,GAAO,CAClC,MAAM2kB,EAAU1X,EAAMpb,EAAKuP,eAC3Boa,EAAQE,YAAY,IAAI/qB,aAAa,aAAakB,EAAK7C,KAAK1B,kDAAkDq3B,MAAa9yB,EAAKuP,oBCrBjI,SAAoCoa,GACzC,MAAO,CACLvW,mBAAmBpT,GACjB,MAAMmO,EAAOkf,GAAY1D,EAAQkG,YAAa7vB,EAAKmO,MAEnD,GAAIA,IAASyP,GAAYzP,GAAO,CAC9B,MAAMqqB,EAAex4B,EAAKiO,SAAS9Q,KAAK1B,MAClCqlB,EAAW1F,EAAMpb,EAAKmO,MAC5Bwb,EAAQE,YAAY,IAAI/qB,aAAa,cAAc05B,gCAA2C1X,MAAc9gB,EAAKmO,WCTlH,SAAyBwb,GAC9B,MAAO,CACLpW,MAAMvT,GACJ,MAAMmO,EAAOwb,EAAQjD,UACfjZ,EAAezN,EAAKyN,aAE1B,GAAIU,EACF,GAAI6P,GAAWM,GAAanQ,KAC1B,GAAIV,EAAc,CAChB,MAAMuS,EAAYhgB,EAAK7C,KAAK1B,MACtBq3B,EAAU3sB,EAAQgI,GACxBwb,EAAQE,YAAY,IAAI/qB,aAAa,UAAUkhB,4CAAoD8S,uBAA8BrlB,UAE9H,IAAKA,EAAc,CACxB,MAAMuS,EAAYhgB,EAAK7C,KAAK1B,MACtBq3B,EAAU3sB,EAAQgI,GACxBwb,EAAQE,YAAY,IAAI/qB,aAAa,UAAUkhB,eAAuB8S,wDAA8D9S,cAAuBhgB,QCf9J,SAAiC2pB,GACtC,MAAO,CACLpW,MAAMvT,GACJ,MAAMmO,EAAOwb,EAAQ0E,gBAErB,GAAIlgB,EAAM,CAGR,IAFiBwb,EAAQyE,cAEV,CAEb,MAAM9L,EAASqH,EAAQkG,YACjB7P,EAAYhgB,EAAK7C,KAAK1B,MAE5B,IAAIg9B,EAAa/f,EAAW,+BAoBtC,SAA+B4J,EAAQnU,EAAM6R,GAC3C,IAAK9B,GAAe/P,GAElB,MAAO,GAGT,MAAMuiB,EAAiB,IAAInI,IACrBmQ,EAAat4B,OAAOgY,OAAO,MAEjC,IAAK,MAAMugB,KAAgBrW,EAAOK,iBAAiBxU,GACjD,GAAKwqB,EAAajZ,YAAYM,GAA9B,CAKA0Q,EAAelH,IAAImP,GACnBD,EAAWC,EAAax7B,MAAQ,EAEhC,IAAK,MAAMy7B,KAAqBD,EAAahZ,gBACtCiZ,EAAkBlZ,YAAYM,KAKnC0Q,EAAelH,IAAIoP,GACnBF,EAAWE,EAAkBz7B,OAASu7B,EAAWE,EAAkBz7B,OAAS,GAAK,GAIrF,OAAO0B,MAAMslB,KAAKuM,GAAgB7W,MAAK,CAACsI,EAAOC,KAE7C,MAAMyW,EAAiBH,EAAWtW,EAAMjlB,MAAQu7B,EAAWvW,EAAMhlB,MAEjE,OAAuB,IAAnB07B,EACKA,EAIL/b,GAAgBqF,IAAUG,EAAOG,UAAUN,EAAOC,IAC5C,EAGNtF,GAAgBsF,IAAUE,EAAOG,UAAUL,EAAOD,GAC7C,EAGFA,EAAMhlB,KAAK4c,cAAcqI,EAAMjlB,SACrCa,KAAIgb,GAAKA,EAAE7b,OAnEsD27B,CAAsBxW,EAAQnU,EAAM6R,IAE7E,KAAfyY,IACFA,EAAa/f,EAwEzB,SAAgCvK,EAAM6R,GACpC,GAAInD,GAAa1O,IAAS2O,GAAgB3O,GAAO,CAE/C,OAAOiL,EAAe4G,EADK5f,OAAO6G,KAAKkH,EAAKuR,cAK9C,MAAO,GA/E2BqZ,CAAuB5qB,EAAM6R,KAIvD2J,EAAQE,YAAY,IAAI/qB,aAAa,uBAAuBkhB,eAAuB7R,EAAKhR,SAAWs7B,EAAYz4B,SCxBlH,SAAiC2pB,GACtC,MAAMqP,EAAqB54B,OAAOgY,OAAO,MACzC,MAAO,CACLjF,oBAAqB,KAAM,EAE3BQ,mBAAmB3T,GACjB,MAAMm0B,EAAen0B,EAAK7C,KAAK1B,MAQ/B,OANIu9B,EAAmB7E,GACrBxK,EAAQE,YAAY,IAAI/qB,aAAa,yCAAyCq1B,MAAkB,CAAC6E,EAAmB7E,GAAen0B,EAAK7C,QAExI67B,EAAmB7E,GAAgBn0B,EAAK7C,MAGnC,KCbN,SAAgCwsB,GACrC,MAAO,CACLlW,eAAezT,GACb,MAAMm0B,EAAen0B,EAAK7C,KAAK1B,MACdkuB,EAAQyK,YAAYD,IAGnCxK,EAAQE,YAAY,IAAI/qB,aAAa,qBAAqBq1B,MAAkBn0B,EAAK7C,UVoD6OwzB,GWtD/T,SAAqChH,GAC1C,MAAO,CACLjW,eAAe1T,GACb,MAAMi5B,EAAWtP,EAAQjD,UACnBE,EAAa+C,EAAQ0E,gBAE3B,GAAIpQ,GAAgBgb,IAAahb,GAAgB2I,KAAgBlE,GAAeiH,EAAQkG,YAAaoJ,EAAUrS,GAAa,CAC1H,MAAMsS,EAAgB/yB,EAAQygB,GACxBuS,EAAchzB,EAAQ8yB,GAC5BtP,EAAQE,YAAY,IAAI/qB,aAAa,sDAAsDo6B,4BAAwCC,MAAiBn5B,MAIxJyT,eAAezT,GACb,MAAMkxB,EAAWlxB,EAAK7C,KAAK1B,MACrBw9B,EAaZ,SAAyBtP,EAASxsB,GAChC,MAAMi8B,EAAOzP,EAAQyK,YAAYj3B,GAEjC,GAAIi8B,EAAM,CACR,MAAMjrB,EAAOkf,GAAY1D,EAAQkG,YAAauJ,EAAK7pB,eAEnD,GAAI0O,GAAgB9P,GAClB,OAAOA,GApBUkrB,CAAgB1P,EAASuH,GACpCtK,EAAa+C,EAAQ0E,gBAE3B,GAAI4K,GAAYrS,IAAelE,GAAeiH,EAAQkG,YAAaoJ,EAAUrS,GAAa,CACxF,MAAMsS,EAAgB/yB,EAAQygB,GACxBuS,EAAchzB,EAAQ8yB,GAC5BtP,EAAQE,YAAY,IAAI/qB,aAAa,aAAaoyB,gDAAuDgI,4BAAwCC,MAAiBn5B,QCjCnK,SAA8B2pB,GAGnC,MAAM2P,EAAel5B,OAAOgY,OAAO,MAE7BmhB,EAAa,GAEbC,EAAwBp5B,OAAOgY,OAAO,MAC5C,MAAO,CACLjF,oBAAqB,KAAM,EAE3BQ,mBAAmB3T,IACjBuqB,EAAqBvqB,IACd,IAOX,SAASuqB,EAAqBwG,GAC5B,GAAIuI,EAAavI,EAAS5zB,KAAK1B,OAC7B,OAGF,MAAM04B,EAAepD,EAAS5zB,KAAK1B,MACnC69B,EAAanF,IAAgB,EAC7B,MAAMsF,EAAc9P,EAAQ+P,mBAAmB3I,EAAStjB,cAExD,GAA2B,IAAvBgsB,EAAYr9B,OAAhB,CAIAo9B,EAAsBrF,GAAgBoF,EAAWn9B,OAEjD,IAAK,MAAMu9B,KAAcF,EAAa,CACpC,MAAMG,EAAaD,EAAWx8B,KAAK1B,MAC7BivB,EAAa8O,EAAsBI,GAGzC,GAFAL,EAAW17B,KAAK87B,QAEGt7B,IAAfqsB,EAA0B,CAC5B,MAAMmP,EAAiBlQ,EAAQyK,YAAYwF,GAEvCC,GACFtP,EAAqBsP,OAElB,CACL,MAAMlP,EAAY4O,EAAWz7B,MAAM4sB,GAC7BoP,EAAUnP,EAAU7sB,MAAM,GAAI,GAAGE,KAAI+7B,GAAK,IAAMA,EAAE58B,KAAK1B,MAAQ,MAAKkD,KAAK,MAC/EgrB,EAAQE,YAAY,IAAI/qB,aAAa,2BAA2B86B,oBAA2C,KAAZE,EAAiB,QAAQA,KAAa,KAAMnP,IAG7I4O,EAAW/iB,MAGbgjB,EAAsBrF,QAAgB91B,KCjDnC,SAAiCsrB,GACtC,IAAIqQ,EAAqB55B,OAAOgY,OAAO,MACvC,MAAO,CACLjF,sBACE6mB,EAAqB55B,OAAOgY,OAAO,OAGrChF,mBAAmBpT,GACjB,MAAMw4B,EAAex4B,EAAKiO,SAAS9Q,KAAK1B,MAEpCu+B,EAAmBxB,GACrB7O,EAAQE,YAAY,IAAI/qB,aAAa,0CAA0C05B,MAAkB,CAACwB,EAAmBxB,GAAex4B,EAAKiO,SAAS9Q,QAElJ68B,EAAmBxB,GAAgBx4B,EAAKiO,SAAS9Q,QCZlD,SAAkCwsB,GACvC,IAAIsQ,EAAsB75B,OAAOgY,OAAO,MACxC,MAAO,CACLjF,oBAAqB,CACnBkE,QACE4iB,EAAsB75B,OAAOgY,OAAO,OAGtCZ,MAAMlK,GACJ,MAAM4sB,EAASvQ,EAAQwQ,2BAA2B7sB,GAElD,IAAK,MAAMtN,KACTA,KACGk6B,EAAQ,CACX,MAAME,EAAUp6B,EAAK7C,KAAK1B,OAEW,IAAjCw+B,EAAoBG,IACtBzQ,EAAQE,YAAY,IAAI/qB,aAAawO,EAAUnQ,KAAO,cAAci9B,mCAAyC9sB,EAAUnQ,KAAK1B,UAAY,cAAc2+B,qBAA4B,CAACp6B,EAAMsN,QAOjM8F,mBAAmBpT,GACjBi6B,EAAoBj6B,EAAKiO,SAAS9Q,KAAK1B,QAAS,KCzB/C,SAA+BkuB,GACpC,IAAI0Q,EAAe,GACnB,MAAO,CACLlnB,oBAAqB,CACnBkE,QACEgjB,EAAe,IAGjB7iB,MAAMlK,GACJ,MAAMgtB,EAAmBl6B,OAAOgY,OAAO,MACjC8hB,EAASvQ,EAAQwQ,2BAA2B7sB,GAElD,IAAK,MAAMtN,KACTA,KACGk6B,EACHI,EAAiBt6B,EAAK7C,KAAK1B,QAAS,EAGtC,IAAK,MAAM8+B,KAAeF,EAAc,CACtC,MAAM7B,EAAe+B,EAAYtsB,SAAS9Q,KAAK1B,OAER,IAAnC6+B,EAAiB9B,IACnB7O,EAAQE,YAAY,IAAI/qB,aAAawO,EAAUnQ,KAAO,cAAcq7B,kCAA6ClrB,EAAUnQ,KAAK1B,UAAY,cAAc+8B,oBAAgC+B,OAOlMnnB,mBAAmB4c,GACjBqK,EAAax8B,KAAKmyB,Mf6BkcmB,GAAqBW,GTvDxe,SAAgCnI,GACrC,MAAO,IACFyI,GAAmCzI,GAEtCnW,SAASif,GACP,MAAM1D,EAASpF,EAAQ8E,cACjBE,EAAWhF,EAAQyE,cACnBxH,EAAa+C,EAAQ0E,gBAE3B,IAAKU,GAAUJ,GAAY/H,EAAY,CACrC,MAAMzG,EAAUsS,EAAQt1B,KAAK1B,MAEvBsd,EAAcK,EAAe+G,EADZwO,EAAStd,KAAKrT,KAAIwiB,GAAOA,EAAIrjB,QAEpDwsB,EAAQE,YAAY,IAAI/qB,aAAa,qBAAqBqhB,gBAAsByG,EAAWzpB,QAAQwxB,EAASxxB,SAAWub,EAAWK,GAAc0Z,QS0CgZC,GPpDjiB,SAAiC/I,GACtC,MAAO,CACLzV,UAAUlU,GAKR,IAAKkd,GAFQkB,GAAgBuL,EAAQ4E,uBAInC,OADAqE,GAAiBjJ,EAAS3pB,IACnB,GAIXmU,YAAYnU,GACV,MAAMmO,EAAOmQ,GAAaqL,EAAQ2E,gBAElC,IAAKrR,GAAkB9O,GAErB,OADAykB,GAAiBjJ,EAAS3pB,IACnB,EAIT,MAAMw6B,EAAetiB,EAAOlY,EAAKiQ,QAAQyM,GAASA,EAAMvf,KAAK1B,QAE7D,IAAK,MAAMkzB,KAAY9W,EAAa1J,EAAKuR,aAAc,CAGrD,IAFkB8a,EAAa7L,EAASxxB,OAEtB8kB,GAAqB0M,GAAW,CAChD,MAAMmE,EAAU3sB,EAAQwoB,EAASxgB,MACjCwb,EAAQE,YAAY,IAAI/qB,aAAa,UAAUqP,EAAKhR,QAAQwxB,EAASxxB,2BAA2B21B,uBAA8B9yB,OAKpIoU,YAAYpU,GACV,MAAM4mB,EAAatI,GAAaqL,EAAQ4E,sBAGxC,IAFkB5E,EAAQ2E,gBAERrR,GAAkB2J,GAAa,CAC/C,MAAM7N,EAAcK,EAAepZ,EAAK7C,KAAK1B,MAAO2E,OAAO6G,KAAK2f,EAAWlH,cAC3EiK,EAAQE,YAAY,IAAI/qB,aAAa,UAAUkB,EAAK7C,KAAK1B,kCAAkCmrB,EAAWzpB,SAAWub,EAAWK,GAAc/Y,MAI9IgU,UAAUhU,GACR,MAAMmO,EAAOwb,EAAQ2E,eAEjBnR,GAAchP,IAChBwb,EAAQE,YAAY,IAAI/qB,aAAa,2BAA2BqH,EAAQgI,cAAiBiN,EAAMpb,MAAUA,KAI7GiU,UAAWjU,GAAQ4yB,GAAiBjJ,EAAS3pB,GAC7C4T,SAAU5T,GAAQ4yB,GAAiBjJ,EAAS3pB,GAC5C6T,WAAY7T,GAAQ4yB,GAAiBjJ,EAAS3pB,GAC9C8T,YAAa9T,GAAQ4yB,GAAiBjJ,EAAS3pB,GAC/C+T,aAAc/T,GAAQ4yB,GAAiBjJ,EAAS3pB,KCzD7C,SAAuC2pB,GAC5C,MAAO,IACFoJ,GAA0CpJ,GAC7CpW,MAAO,CAELiE,MAAM8X,GACJ,MAAMX,EAAWhF,EAAQyE,cAEzB,IAAKO,EACH,OAAO,EAIT,MACMyE,EAAalb,EADFoX,EAAUxgB,WAAa,IACJ0R,GAAOA,EAAIrjB,KAAK1B,QAEpD,IAAK,MAAMszB,KAAUJ,EAAStd,KAAM,CAGlC,IAFgB+hB,EAAWrE,EAAO5xB,OAElBsjB,GAAmBsO,GAAS,CAC1C,MAAMsE,EAAaltB,EAAQ4oB,EAAO5gB,MAClCwb,EAAQE,YAAY,IAAI/qB,aAAa,UAAU6vB,EAASxxB,mBAAmB4xB,EAAO5xB,kBAAkBk2B,2CAAqD/D,UCzB9J,SAAwC3F,GAC7C,IAAI8Q,EAAYr6B,OAAOgY,OAAO,MAC9B,MAAO,CACLjF,oBAAqB,CACnBkE,QACEojB,EAAYr6B,OAAOgY,OAAO,OAG5BZ,MAAMlK,GACJ,MAAM4sB,EAASvQ,EAAQwQ,2BAA2B7sB,GAElD,IAAK,MAAMtN,KACTA,EAAImO,KACJA,EAAIE,aACJA,KACG6rB,EAAQ,CACX,MAAME,EAAUp6B,EAAK7C,KAAK1B,MACpBi/B,EAASD,EAAUL,GAEzB,GAAIM,GAAUvsB,EAAM,CAMlB,MAAMmU,EAASqH,EAAQkG,YACjB0D,EAAUlG,GAAY/K,EAAQoY,EAAOvsB,MAE3C,GAAIolB,IAAYD,GAAqBhR,EAAQiR,EAASmH,EAAOrsB,aAAcF,EAAME,GAAe,CAC9F,MAAMssB,EAAax0B,EAAQotB,GACrBT,EAAU3sB,EAAQgI,GACxBwb,EAAQE,YAAY,IAAI/qB,aAAa,cAAcs7B,eAAqBO,uCAAgD7H,MAAa,CAAC4H,EAAQ16B,UAQxJoT,mBAAmBpT,GACjBy6B,EAAUz6B,EAAKiO,SAAS9Q,KAAK1B,OAASuE,KC1BrC,SAA0C2pB,GAI/C,MAAMsK,EAAwB,IAAIwD,QAI5BzD,EAA+B,IAAI5S,IACzC,MAAO,CACL9N,aAAa7F,GACX,MAAMsmB,EAoEZ,SAAyCpK,EAASqK,EAA8BC,EAAuBrN,EAAYnZ,GACjH,MAAMsmB,EAAY,IACXlU,EAAUsX,GAAiBJ,GAA0BpN,EAASqK,EAA8BpN,EAAYnZ,GAK/G,GAwHF,SAAgCkc,EAASoK,EAAWC,EAA8BC,EAAuBpU,GAKvG,IAAK,MAAO+T,EAAc3jB,KAAW+H,EAAc6H,GAIjD,GAAI5P,EAAO7T,OAAS,EAClB,IAAK,IAAIwB,EAAI,EAAGA,EAAIqS,EAAO7T,OAAQwB,IACjC,IAAK,IAAIgd,EAAIhd,EAAI,EAAGgd,EAAI3K,EAAO7T,OAAQwe,IAAK,CAC1C,MAAMua,EAAWC,GAAazL,EAASqK,EAA8BC,GAAuB,EAC5FL,EAAc3jB,EAAOrS,GAAIqS,EAAO2K,IAE5Bua,GACFpB,EAAUl2B,KAAKs3B,IA1IzByF,CAAuBjR,EAASoK,EAAWC,EAA8BC,EAAuBpU,GAEnE,IAAzBsX,EAAc/6B,OAGhB,IAAK,IAAIwB,EAAI,EAAGA,EAAIu5B,EAAc/6B,OAAQwB,IAAK,CAC7Ck2B,GAAyCnK,EAASoK,EAAWC,EAA8BC,GAAuB,EAAOpU,EAAUsX,EAAcv5B,IAKjJ,IAAK,IAAIgd,EAAIhd,EAAI,EAAGgd,EAAIuc,EAAc/6B,OAAQwe,IAC5C6Z,GAAiC9K,EAASoK,EAAWC,EAA8BC,GAAuB,EAAOkD,EAAcv5B,GAAIu5B,EAAcvc,IAKvJ,OAAOmZ,EA1Fe8G,CAAgClR,EAASqK,EAA8BC,EAAuBtK,EAAQ0E,gBAAiB5gB,GAEzI,IAAK,OAAQmmB,EAActM,GAAS4N,EAASD,KAAYlB,EAAW,CAClE,MAAM+G,EAAYnH,GAAcrM,GAChCqC,EAAQE,YAAY,IAAI/qB,aAAa,WAAW80B,uBAAkCkH,gFAAyF5F,EAAQpI,OAAOmI,SI4Byf4C,KAK9qBkD,GAAoB36B,OAAOoB,OAAO,CgBjExC,SAAkCmoB,GACvC,MAAMqR,EAAYrR,EAAQkG,YACpBoL,EAAiBD,GAAW/b,SAAW+b,GAAWhW,gBAAkBgW,GAAW9V,mBAAqB8V,GAAW5V,sBACrH,IAAI8V,EAAyB,EAC7B,MAAO,CACLzmB,iBAAiBzU,GACXi7B,EACFtR,EAAQE,YAAY,IAAI/qB,aAAa,wDAAyDkB,KAI5Fk7B,EAAyB,GAC3BvR,EAAQE,YAAY,IAAI/qB,aAAa,2CAA4CkB,MAGjFk7B,MCfD,SAAkCvR,GACvC,MAAMrH,EAASqH,EAAQkG,YACjBsL,EAAwB/6B,OAAOgY,OAAO,MACtCgjB,EAAyB9Y,EAAS,CACtC0F,MAAO1F,EAAO0C,eACdkD,SAAU5F,EAAO4C,kBACjBkD,aAAc9F,EAAO8C,uBACnB,GACJ,MAAO,CACL3Q,iBAAkB4mB,EAClBhmB,gBAAiBgmB,GAGnB,SAASA,EAAoBr7B,GAE3B,MAAMs7B,EAAsBt7B,EAAK8Q,gBAAkB,GAEnD,IAAK,MAAMyqB,KAAiBD,EAAqB,CAC/C,MAAMhuB,EAAYiuB,EAAcjuB,UAC1BkuB,EAA8BL,EAAsB7tB,GAEtD8tB,EAAuB9tB,GACzBqc,EAAQE,YAAY,IAAI/qB,aAAa,YAAYwO,2DAAoEiuB,IAC5GC,EACT7R,EAAQE,YAAY,IAAI/qB,aAAa,yBAAyBwO,oBAA6B,CAACkuB,EAA6BD,KAEzHJ,EAAsB7tB,GAAaiuB,EAIvC,OAAO,IC9BJ,SAA6B5R,GAClC,MAAM8R,EAAiBr7B,OAAOgY,OAAO,MAC/BkK,EAASqH,EAAQkG,YACvB,MAAO,CACLlb,qBAAsB+mB,EACtB9mB,qBAAsB8mB,EACtB3mB,wBAAyB2mB,EACzB1mB,oBAAqB0mB,EACrBzmB,mBAAoBymB,EACpBvmB,0BAA2BumB,GAG7B,SAASA,EAAc17B,GACrB,MAAM8gB,EAAW9gB,EAAK7C,KAAK1B,MAE3B,IAAI6mB,GAAQoE,QAAQ5F,GAWpB,OANI2a,EAAe3a,GACjB6I,EAAQE,YAAY,IAAI/qB,aAAa,qCAAqCgiB,MAAc,CAAC2a,EAAe3a,GAAW9gB,EAAK7C,QAExHs+B,EAAe3a,GAAY9gB,EAAK7C,MAG3B,EAVLwsB,EAAQE,YAAY,IAAI/qB,aAAa,SAASgiB,sFAA8F9gB,EAAK7C,SCfhJ,SAAkCwsB,GACvC,MAAMrH,EAASqH,EAAQkG,YACjB8L,EAAkBrZ,EAASA,EAAOwC,aAAe1kB,OAAOgY,OAAO,MAC/DwjB,EAAkBx7B,OAAOgY,OAAO,MACtC,MAAO,CACLnD,mBAAoB4mB,EACpBnmB,kBAAmBmmB,GAGrB,SAASA,EAAqB77B,GAC5B,MAAM8gB,EAAW9gB,EAAK7C,KAAK1B,MAEtBmgC,EAAgB9a,KACnB8a,EAAgB9a,GAAY1gB,OAAOgY,OAAO,OAI5C,MAAM0jB,EAAa97B,EAAK+P,QAAU,GAC5BgsB,EAAaH,EAAgB9a,GAEnC,IAAK,MAAMkb,KAAYF,EAAY,CACjC,MAAM7a,EAAY+a,EAAS7+B,KAAK1B,MAC1BwgC,EAAeN,EAAgB7a,GAEjC9D,GAAWif,IAAiBA,EAAaza,SAASP,GACpD0I,EAAQE,YAAY,IAAI/qB,aAAa,eAAegiB,KAAYG,qFAA8F+a,EAAS7+B,OAC9J4+B,EAAW9a,GACpB0I,EAAQE,YAAY,IAAI/qB,aAAa,eAAegiB,KAAYG,+BAAwC,CAAC8a,EAAW9a,GAAY+a,EAAS7+B,QAEzI4+B,EAAW9a,GAAa+a,EAAS7+B,KAIrC,OAAO,IrBjCJ,SAAwCwsB,GAC7C,MAAMrH,EAASqH,EAAQkG,YACjB8L,EAAkBrZ,EAASA,EAAOwC,aAAe1kB,OAAOgY,OAAO,MAC/D8jB,EAAkB97B,OAAOgY,OAAO,MACtC,MAAO,CACLjD,0BAA2BgnB,EAC3BxmB,yBAA0BwmB,EAC1BpnB,wBAAyBonB,EACzB3mB,uBAAwB2mB,EACxBvnB,qBAAsBunB,EACtB5mB,oBAAqB4mB,GAGvB,SAASA,EAAqBn8B,GAC5B,MAAM8gB,EAAW9gB,EAAK7C,KAAK1B,MAEtBygC,EAAgBpb,KACnBob,EAAgBpb,GAAY1gB,OAAOgY,OAAO,OAI5C,MAAMiM,EAAarkB,EAAKiQ,QAAU,GAC5BmsB,EAAaF,EAAgBpb,GAEnC,IAAK,MAAM6N,KAAYtK,EAAY,CACjC,MAAMrE,EAAY2O,EAASxxB,KAAK1B,MAE5Bu8B,GAAS2D,EAAgB7a,GAAWd,GACtC2J,EAAQE,YAAY,IAAI/qB,aAAa,UAAUgiB,KAAYd,qFAA8F2O,EAASxxB,OACzJi/B,EAAWpc,GACpB2J,EAAQE,YAAY,IAAI/qB,aAAa,UAAUgiB,KAAYd,+BAAwC,CAACoc,EAAWpc,GAAY2O,EAASxxB,QAEpIi/B,EAAWpc,GAAa2O,EAASxxB,KAIrC,OAAO,IsBrCJ,SAAkCwsB,GACvC,MAAM0S,EAAsBj8B,OAAOgY,OAAO,MACpCkK,EAASqH,EAAQkG,YACvB,MAAO,CACLza,oBAAoBpV,GAClB,MAAMmyB,EAAgBnyB,EAAK7C,KAAK1B,MAEhC,IAAI6mB,GAAQ8G,aAAa+I,GAWzB,OANIkK,EAAoBlK,GACtBxI,EAAQE,YAAY,IAAI/qB,aAAa,2CAA2CqzB,MAAmB,CAACkK,EAAoBlK,GAAgBnyB,EAAK7C,QAE7Ik/B,EAAoBlK,GAAiBnyB,EAAK7C,MAGrC,EAVLwsB,EAAQE,YAAY,IAAI/qB,aAAa,eAAeqzB,2DAAwEnyB,EAAK7C,UpByDoEyyB,GAAoBuB,GAAqBW,GD1D/O,SAAoCnI,GACzC,MAAMrH,EAASqH,EAAQkG,YACjBE,EAAe3vB,OAAOgY,OAAO,MAEnC,IAAK,MAAM4X,KAAOrG,EAAQsG,cAAcrjB,YAClC8iB,GAAqBM,KACvBD,EAAaC,EAAI7yB,KAAK1B,OAASu0B,GAInC,MAAO,CACL1a,oBAAqBgnB,EACrB/mB,oBAAqB+mB,EACrB9mB,uBAAwB8mB,EACxB7mB,mBAAoB6mB,EACpB5mB,kBAAmB4mB,EACnB3mB,yBAA0B2mB,GAG5B,SAASA,EAAet8B,GACtB,MAAM8gB,EAAW9gB,EAAK7C,KAAK1B,MACrB8gC,EAAUxM,EAAajP,GACvBmb,EAAe3Z,GAAQoE,QAAQ5F,GACrC,IAAI0b,EAQJ,GANID,EACFC,EAAevE,GAAiBsE,EAAQ53B,MAC/Bs3B,IACTO,EA6BN,SAAuBruB,GACrB,GAAIyO,GAAazO,GACf,OAAO5M,EAAKuC,sBAGd,GAAI+Y,GAAa1O,GACf,OAAO5M,EAAKwC,sBAGd,GAAI+Y,GAAgB3O,GAClB,OAAO5M,EAAKyC,yBAGd,GAAI+Y,GAAY5O,GACd,OAAO5M,EAAK0C,qBAGd,GAAI+Y,GAAW7O,GACb,OAAO5M,EAAK2C,oBAId,GAAI+Y,GAAkB9O,GACpB,OAAO5M,EAAK4C,4BAILiY,GAAU,EAAG,oBAAsBjW,EAAQgI,IAxDjCsuB,CAAcR,IAG3BO,GACF,GAAIA,IAAiBx8B,EAAK2E,KAAM,CAC9B,MAAM+3B,EAsDd,SAAiC/3B,GAC/B,OAAQA,GACN,KAAKpD,EAAKuC,sBACR,MAAO,SAET,KAAKvC,EAAKwC,sBACR,MAAO,SAET,KAAKxC,EAAKyC,yBACR,MAAO,YAET,KAAKzC,EAAK0C,qBACR,MAAO,QAET,KAAK1C,EAAK2C,oBACR,MAAO,OAET,KAAK3C,EAAK4C,4BACR,MAAO,eAIFiY,GAAU,EAAG,oBAAsBjW,EAAQxB,IA5E9Bg4B,CAAwB38B,EAAK2E,MAC7CglB,EAAQE,YAAY,IAAI/qB,aAAa,qBAAqB49B,WAAiB5b,MAAcyb,EAAU,CAACA,EAASv8B,GAAQA,SAElH,CACL,IAAI48B,EAAex8B,OAAO6G,KAAK8oB,GAE3BzN,IACFsa,EAAeA,EAAa9P,OAAO1sB,OAAO6G,KAAKqb,EAAOwC,gBAGxD,MAAM4L,EAAiBtX,EAAe0H,EAAU8b,GAChDjT,EAAQE,YAAY,IAAI/qB,aAAa,uBAAuBgiB,gCAAyCpI,EAAWgY,GAAiB1wB,EAAK7C,UCcuKi1B,GAAoCM,GAAyBmF,GAA2B9E,KqB/DpY,MAAM8J,qBACX79B,YAAYqc,EAAKyhB,GACfx8B,KAAKy8B,KAAO1hB,EACZ/a,KAAK08B,gBAAa3+B,EAClBiC,KAAK28B,iBAAmB,IAAI7b,IAC5B9gB,KAAK48B,gCAAkC,IAAI9b,IAC3C9gB,KAAK68B,SAAWL,EAGlBjT,YAAY9oB,GACVT,KAAK68B,SAASp8B,GAGhBkvB,cACE,OAAO3vB,KAAKy8B,KAGd3I,YAAYj3B,GACV,IAAIigC,EAAY98B,KAAK08B,WAYrB,OAVKI,IACH98B,KAAK08B,WAAaI,EAAY98B,KAAK2vB,cAAcrjB,YAAY9M,QAAO,CAACu9B,EAAOC,KACtEA,EAAU34B,OAASpD,EAAKW,sBAC1Bm7B,EAAMC,EAAUngC,KAAK1B,OAAS6hC,GAGzBD,IACNj9B,OAAOgY,OAAO,QAGZglB,EAAUjgC,GAGnBu8B,mBAAmB15B,GACjB,IAAIu9B,EAAUj9B,KAAK28B,iBAAiB/7B,IAAIlB,GAExC,IAAKu9B,EAAS,CACZA,EAAU,GACV,MAAMC,EAAc,CAACx9B,GAErB,KAA8B,IAAvBw9B,EAAYphC,QAAc,CAC/B,MAAMi7B,EAAMmG,EAAYhnB,MAExB,IAAK,MAAM+gB,KAAaF,EAAI7oB,WACtB+oB,EAAU5yB,OAASpD,EAAKS,gBAC1Bu7B,EAAQ1/B,KAAK05B,GACJA,EAAU9pB,cACnB+vB,EAAY3/B,KAAK05B,EAAU9pB,cAKjCnN,KAAK28B,iBAAiB5F,IAAIr3B,EAAMu9B,GAGlC,OAAOA,EAGTvM,kCAAkC1jB,GAChC,IAAI8vB,EAAY98B,KAAK48B,gCAAgCh8B,IAAIoM,GAEzD,IAAK8vB,EAAW,CACdA,EAAY,GACZ,MAAMK,EAAiBr9B,OAAOgY,OAAO,MAC/BslB,EAAe,CAACpwB,EAAUG,cAEhC,KAA+B,IAAxBiwB,EAAathC,QAAc,CAChC,MAAM4D,EAAO09B,EAAalnB,MAE1B,IAAK,MAAMmnB,KAAUr9B,KAAKo5B,mBAAmB15B,GAAO,CAClD,MAAMkxB,EAAWyM,EAAOxgC,KAAK1B,MAE7B,IAAiC,IAA7BgiC,EAAevM,GAAoB,CACrCuM,EAAevM,IAAY,EAC3B,MAAMH,EAAWzwB,KAAK8zB,YAAYlD,GAE9BH,IACFqM,EAAUv/B,KAAKkzB,GACf2M,EAAa7/B,KAAKkzB,EAAStjB,iBAMnCnN,KAAK48B,gCAAgC7F,IAAI/pB,EAAW8vB,GAGtD,OAAOA,GAIJ,MAAMQ,6BAA6Bf,qBACxC79B,YAAYqc,EAAKiH,EAAQwa,GACvBv9B,MAAM8b,EAAKyhB,GACXx8B,KAAKotB,QAAUpL,EAGjBuN,YACE,OAAOvvB,KAAKotB,SAIT,MAAMmQ,0BAA0BhB,qBACrC79B,YAAYsjB,EAAQjH,EAAKmU,EAAUsN,GACjCv9B,MAAM8b,EAAKyhB,GACXx8B,KAAKotB,QAAUpL,EACfhiB,KAAKw9B,UAAYtO,EACjBlvB,KAAKy9B,gBAAkB,IAAI3c,IAC3B9gB,KAAK09B,yBAA2B,IAAI5c,IAGtCyO,YACE,OAAOvvB,KAAKotB,QAGduQ,kBAAkBj+B,GAChB,IAAIk6B,EAAS55B,KAAKy9B,gBAAgB78B,IAAIlB,GAEtC,IAAKk6B,EAAQ,CACX,MAAMgE,EAAY,GACZ1O,EAAW,IAAIjC,SAASjtB,KAAKotB,SACnC7X,EAAM7V,EAAMuvB,GAAkBC,EAAU,CACtCpc,mBAAoB,KAAM,EAE1BC,SAASpF,GACPiwB,EAAUrgC,KAAK,CACbmC,KAAMiO,EACNE,KAAMqhB,EAASlB,eACfjgB,aAAcmhB,EAAShB,wBAK7B0L,EAASgE,EAET59B,KAAKy9B,gBAAgB1G,IAAIr3B,EAAMk6B,GAGjC,OAAOA,EAGTC,2BAA2B7sB,GACzB,IAAI4sB,EAAS55B,KAAK09B,yBAAyB98B,IAAIoM,GAE/C,IAAK4sB,EAAQ,CACXA,EAAS55B,KAAK29B,kBAAkB3wB,GAEhC,IAAK,MAAM8rB,KAAQ94B,KAAK0wB,kCAAkC1jB,GACxD4sB,EAASA,EAAOpN,OAAOxsB,KAAK29B,kBAAkB7E,IAGhD94B,KAAK09B,yBAAyB3G,IAAI/pB,EAAW4sB,GAG/C,OAAOA,EAGTxT,UACE,OAAOpmB,KAAKw9B,UAAUpX,UAGxB2H,gBACE,OAAO/tB,KAAKw9B,UAAUzP,gBAGxBC,eACE,OAAOhuB,KAAKw9B,UAAUxP,eAGxBC,qBACE,OAAOjuB,KAAKw9B,UAAUvP,qBAGxBH,cACE,OAAO9tB,KAAKw9B,UAAU1P,cAGxBhF,eACE,OAAO9oB,KAAKw9B,UAAU1U,eAGxBqF,cACE,OAAOnuB,KAAKw9B,UAAUrP,cAGxBC,eACE,OAAOpuB,KAAKw9B,UAAUpP,gBC3KnB,SAASyP,GAAS7b,EAAQ8b,EAAaC,EAAQnG,GAAgB1I,EAAW,IAAIjC,SAASjL,GAASpW,EAAU,CAC/GoyB,eAAWjgC,IAEX+/B,GAAez2B,EAAU,EAAG,0BxCevB,SAA2B2a,GAChC,MAAMgJ,EAAS5B,GAAepH,GAE9B,GAAsB,IAAlBgJ,EAAOlvB,OACT,MAAM,IAAI2C,MAAMusB,EAAOttB,KAAI+C,GAASA,EAAM9B,UAASN,KAAK,SwCjB1D4/B,CAAkBjc,GAClB,MAAMkc,EAAWp+B,OAAOoB,OAAO,IACzB8pB,EAAS,GACT3B,EAAU,IAAIkU,kBAAkBvb,EAAQ8b,EAAa5O,GAAUzuB,IACnE,GAAyB,MAArBmL,EAAQoyB,WAAqBhT,EAAOlvB,QAAU8P,EAAQoyB,UAExD,MADAhT,EAAOztB,KAAK,IAAIiB,aAAa,yEACvB0/B,EAGRlT,EAAOztB,KAAKkD,MAIRgV,EAAUmB,EAAgBmnB,EAAMrgC,KAAIygC,GAAQA,EAAK9U,MAEvD,IACE9T,EAAMuoB,EAAa7O,GAAkBC,EAAUzZ,IAC/C,MAAO2oB,GACP,GAAIA,IAAMF,EACR,MAAME,EAIV,OAAOpT,EAMF,SAASqT,GAAYP,EAAaQ,EAAgBP,EAAQtD,IAC/D,MAAMzP,EAAS,GACT3B,EAAU,IAAIiU,qBAAqBQ,EAAaQ,GAAgB79B,IACpEuqB,EAAOztB,KAAKkD,MAId,OADA8U,EAAMuoB,EAAalnB,EADFmnB,EAAMrgC,KAAIygC,GAAQA,EAAK9U,OAEjC2B,ECtCF,SAASuT,GAAaviB,EAAWnO,EAAMoO,GAC5C,GAAKD,EAAL,CAMA,GAAIA,EAAU3X,OAASpD,EAAKY,SAAU,CACpC,MAAMq2B,EAAelc,EAAUnf,KAAK1B,MAEpC,GAAiB,MAAb8gB,QAAiDle,IAA5Bke,EAAUic,GAEjC,OAGF,MAAMsG,EAAgBviB,EAAUic,GAEhC,GAAsB,OAAlBsG,GAA0B3hB,GAAchP,GAC1C,OAMF,OAAO2wB,EAGT,GAAI3hB,GAAchP,GAAO,CACvB,GAAImO,EAAU3X,OAASpD,EAAKiB,KAC1B,OAGF,OAAOq8B,GAAaviB,EAAWnO,EAAK2P,OAAQvB,GAG9C,GAAID,EAAU3X,OAASpD,EAAKiB,KAE1B,OAAO,KAGT,GAAI0a,GAAW/O,GAAO,CACpB,MAAM4V,EAAW5V,EAAK2P,OAEtB,GAAIxB,EAAU3X,OAASpD,EAAKmB,KAAM,CAChC,MAAMq8B,EAAgB,GAEtB,IAAK,MAAM3a,KAAY9H,EAAUvM,OAC/B,GAAIivB,GAAkB5a,EAAU7H,GAAY,CAG1C,GAAIY,GAAc4G,GAChB,OAGFgb,EAAclhC,KAAK,UACd,CACL,MAAMohC,EAAYJ,GAAaza,EAAUL,EAAUxH,GAEnD,QAAkBle,IAAd4gC,EACF,OAGFF,EAAclhC,KAAKohC,GAIvB,OAAOF,EAGT,MAAMhc,EAAe8b,GAAaviB,EAAWyH,EAAUxH,GAEvD,QAAqBle,IAAjB0kB,EACF,OAGF,MAAO,CAACA,GAGV,GAAI9F,GAAkB9O,GAAO,CAC3B,GAAImO,EAAU3X,OAASpD,EAAKoB,OAC1B,OAGF,MAAMu8B,EAAa9+B,OAAOgY,OAAO,MAC3BiM,EAAanM,EAAOoE,EAAUrM,QAAQyM,GAASA,EAAMvf,KAAK1B,QAEhE,IAAK,MAAMihB,KAAS7E,EAAa1J,EAAKuR,aAAc,CAClD,MAAM4P,EAAYjL,EAAW3H,EAAMvf,MAEnC,IAAKmyB,GAAa0P,GAAkB1P,EAAU7zB,MAAO8gB,GAAY,CAC/D,QAA2Ble,IAAvBqe,EAAMrO,aACR6wB,EAAWxiB,EAAMvf,MAAQuf,EAAMrO,kBAC1B,GAAI8O,GAAcT,EAAMvO,MAC7B,OAGF,SAGF,MAAMmW,EAAaua,GAAavP,EAAU7zB,MAAOihB,EAAMvO,KAAMoO,GAE7D,QAAmBle,IAAfimB,EACF,OAGF4a,EAAWxiB,EAAMvf,MAAQmnB,EAG3B,OAAO4a,EAIT,GAAIlhB,GAAW7P,GAAO,CAIpB,IAAIrE,EAEJ,IACEA,EAASqE,EAAK6Q,aAAa1C,EAAWC,GACtC,MAAO4iB,GACP,OAGF,QAAe9gC,IAAXyL,EACF,OAGF,OAAOA,EAIAsS,GAAU,EAAG,0BAA4BjW,EAAQgI,KAI5D,SAAS6wB,GAAkB1iB,EAAWC,GACpC,OAAOD,EAAU3X,OAASpD,EAAKY,WAA0B,MAAboa,QAAyDle,IAApCke,EAAUD,EAAUnf,KAAK1B,QCcrF,SAAS2jC,GAAmBC,EAAcr/B,EAAMs/B,GAErD,MAAM/M,EAAgBvyB,EAAKwN,YAAY6b,MAAK9D,GAAaA,EAAUpoB,KAAK1B,QAAU4jC,EAAaliC,OAE/F,GAAIo1B,EACF,OA3EG,SAA2BvC,EAAKhwB,EAAMs/B,GAC3C,MAAMP,EAAgB,GAGhB3L,EAAalb,EADGlY,EAAK8O,WAAa,IACC0R,GAAOA,EAAIrjB,KAAK1B,QAEzD,IAAK,MAAMszB,KAAUiB,EAAI3e,KAAM,CAC7B,MAAMlU,EAAO4xB,EAAO5xB,KACd6xB,EAAUD,EAAO5gB,KACjBoxB,EAAenM,EAAWj2B,GAEhC,IAAKoiC,EAAc,CACjB,QAA4BlhC,IAAxB0wB,EAAO1gB,aACT0wB,EAAc5hC,GAAQ4xB,EAAO1gB,kBACxB,GAAI8O,GAAc6R,GACvB,MAAM,IAAIlwB,aAAa,aAAa3B,wBAA2BgJ,EAAQ6oB,wBAAoChvB,GAG7G,SAGF,MAAMsc,EAAYijB,EAAa9jC,MAC/B,IAAI+jC,EAASljB,EAAU3X,OAASpD,EAAKiB,KAErC,GAAI8Z,EAAU3X,OAASpD,EAAKY,SAAU,CACpC,MAAMq2B,EAAelc,EAAUnf,KAAK1B,MAEpC,GAAsB,MAAlB6jC,IAoDcxnB,EApD4BwnB,EAoDvBG,EApDuCjH,GAqD3Dp4B,OAAO+G,UAAUu4B,eAAet4B,KAAK0Q,EAAK2nB,IArDgC,CAC3E,QAA4BphC,IAAxB0wB,EAAO1gB,aACT0wB,EAAc5hC,GAAQ4xB,EAAO1gB,kBACxB,GAAI8O,GAAc6R,GACvB,MAAM,IAAIlwB,aAAa,aAAa3B,wBAA2BgJ,EAAQ6oB,mCAA8CwJ,6CAAyDlc,GAGhL,SAGFkjB,EAAyC,MAAhCF,EAAe9G,GAG1B,GAAIgH,GAAUriB,GAAc6R,GAC1B,MAAM,IAAIlwB,aAAa,aAAa3B,wBAA2BgJ,EAAQ6oB,wBAAoC1S,GAG7G,MAAMyG,EAAe8b,GAAaviB,EAAW0S,EAASsQ,GAEtD,QAAqBjhC,IAAjB0kB,EAIF,MAAM,IAAIjkB,aAAa,aAAa3B,wBAA2Bie,EAAMkB,MAAeA,GAGtFyiB,EAAc5hC,GAAQ4lB,EA0B1B,IAAwBjL,EAAK2nB,EAvB3B,OAAOV,EAmBEY,CAAkBN,EAAc9M,EAAe+M,GC9JnD,SAASM,GAAkBC,EAAe3zB,GAC/C1Q,EAAaqkC,IAAkBrkC,EAAaqkC,EAAcC,WAAan4B,EAAU,EAAG,6JAA6JxB,EAAQ05B,OAEzP,MAAME,EAAsBF,EAAcC,SAEpC/U,EAAUvS,EAAUunB,EAAoBvuB,OAAOwuB,GAAqBA,EAAkB7iC,OAAM6iC,GA8ElG,SAAmB7xB,GACjB,GAAY,MAARA,GAA6B,MAAbA,EAAKhR,MAA6B,MAAbgR,EAAKxJ,KAC5C,OAAQwJ,EAAKxJ,MACX,KAAKihB,GAASxd,OACZ,OAwBC,IAAIgV,kBAAkB,CAC3BjgB,MAFoB8iC,EAvBM9xB,GAyBAhR,KAC1BmE,YAAa2+B,EAAoB3+B,YACjCwd,eAAgBmhB,EAAoBnhB,iBAzBlC,KAAK8G,GAASjjB,OACZ,OA4CC,IAAI0a,kBAAkB,CAC3BlgB,MAFoB+iC,EA3CM/xB,GA6CAhR,KAC1BmE,YAAa4+B,EAAoB5+B,YACjC0P,WAAY,IAAMmvB,EAAyBD,GAC3CjwB,OAAQ,IAAMmwB,EAAiBF,KA9C7B,KAAKta,GAAStd,UACZ,OAkDC,IAAIgV,qBAAqB,CAC9BngB,MAFuBkjC,EAjDMlyB,GAmDAhR,KAC7BmE,YAAa++B,EAAuB/+B,YACpC0P,WAAY,IAAMmvB,EAAyBE,GAC3CpwB,OAAQ,IAAMmwB,EAAiBC,KApD7B,KAAKza,GAASrd,MACZ,OAuDR,SAAuB+3B,GACrB,IAAKA,EAAmBta,cAAe,CACrC,MAAMua,EAAwBp6B,EAAQm6B,GACtC,MAAM,IAAIvhC,MAAM,+CAA+CwhC,MAGjE,OAAO,IAAIhjB,iBAAiB,CAC1BpgB,KAAMmjC,EAAmBnjC,KACzBmE,YAAag/B,EAAmBh/B,YAChCkQ,MAAO,IAAM8uB,EAAmBta,cAAchoB,IAAIwiC,KAhEvCC,CAActyB,GAEvB,KAAKyX,GAASnjB,KACZ,OAiER,SAAsBi+B,GACpB,IAAKA,EAAkBva,WAAY,CACjC,MAAMwa,EAAuBx6B,EAAQu6B,GACrC,MAAM,IAAI3hC,MAAM,4CAA4C4hC,MAG9D,OAAO,IAAInjB,gBAAgB,CACzBrgB,KAAMujC,EAAkBvjC,KACxBmE,YAAao/B,EAAkBp/B,YAC/ByO,OAAQyI,EAAUkoB,EAAkBva,YAAYya,GAAsBA,EAAmBzjC,OAAMyjC,KAC7Ft/B,YAAas/B,EAAmBt/B,YAChC+e,kBAAmBugB,EAAmBvgB,wBA5E7BwgB,CAAa1yB,GAEtB,KAAKyX,GAASnd,aACZ,OA8ER,SAA6Bq4B,GAC3B,IAAKA,EAAyBza,YAAa,CACzC,MAAM0a,EAA8B56B,EAAQ26B,GAC5C,MAAM,IAAI/hC,MAAM,6CAA6CgiC,MAG/D,OAAO,IAAItjB,uBAAuB,CAChCtgB,KAAM2jC,EAAyB3jC,KAC/BmE,YAAaw/B,EAAyBx/B,YACtC2O,OAAQ,IAAM+wB,EAAsBF,EAAyBza,eAvFlD4a,CAAoB9yB,GAwCnC,IAA2BkyB,EAT3B,IAAwBH,EAvBxB,IAAwBD,EAJtB,MAAMnN,EAAU3sB,EAAQgI,GACxB,MAAM,IAAIpP,MAAM,iIAAiI+zB,MAtG5BoO,CAAUlB,KAEjI,IAAK,MAAMmB,IAAW,IAAIxd,MAAyBkD,IAC7CkE,EAAQoW,EAAQhkC,QAClB4tB,EAAQoW,EAAQhkC,MAAQgkC,GAK5B,MAAMpc,EAAYgb,EAAoBhb,UAAYyb,EAAcT,EAAoBhb,WAAa,KAC3FE,EAAe8a,EAAoB9a,aAAeub,EAAcT,EAAoB9a,cAAgB,KACpGE,EAAmB4a,EAAoB5a,iBAAmBqb,EAAcT,EAAoB5a,kBAAoB,KAGhH3X,EAAauyB,EAAoBvyB,WAAauyB,EAAoBvyB,WAAWxP,KAgOnF,SAAwBojC,GACtB,IAAKA,EAAuB/vB,KAAM,CAChC,MAAMgwB,EAA4Bl7B,EAAQi7B,GAC1C,MAAM,IAAIriC,MAAM,gDAAgDsiC,MAGlE,IAAKD,EAAuB3gC,UAAW,CACrC,MAAM4gC,EAA4Bl7B,EAAQi7B,GAC1C,MAAM,IAAIriC,MAAM,qDAAqDsiC,MAGvE,OAAO,IAAIra,iBAAiB,CAC1B7pB,KAAMikC,EAAuBjkC,KAC7BmE,YAAa8/B,EAAuB9/B,YACpCkkB,aAAc4b,EAAuB5b,aACrC/kB,UAAW2gC,EAAuB3gC,UAAU3C,QAC5CuT,KAAM2vB,EAAsBI,EAAuB/vB,WAhPkD,GAEzG,OAAO,IAAIsW,cAAc,CACvBrmB,YAAay+B,EAAoBz+B,YACjC0mB,MAAOjD,EACPmD,SAAUjD,EACVmD,aAAcjD,EACd3T,MAAOqG,EAAakT,GACpBvd,WAAAA,EACAsa,YAAa5b,GAAS4b,cAIxB,SAASpB,EAAQ4a,GACf,GAAIA,EAAQ38B,OAASihB,GAASljB,KAAM,CAClC,MAAM6+B,EAAUD,EAAQxjB,OAExB,IAAKyjB,EACH,MAAM,IAAIxiC,MAAM,mDAGlB,OAAO,IAAI2e,YAAYgJ,EAAQ6a,IAGjC,GAAID,EAAQ38B,OAASihB,GAASC,SAAU,CACtC,MAAM2b,EAAcF,EAAQxjB,OAE5B,IAAK0jB,EACH,MAAM,IAAIziC,MAAM,mDAGlB,MAAM0iC,EAAe/a,EAAQ8a,GAC7B,OAAO,IAAI7jB,enDqNV,SAA4BxP,GACjC,IAAKgQ,GAAehQ,GAClB,MAAM,IAAIpP,MAAM,YAAYoH,EAAQgI,qCAGtC,OAAOA,EmD1NuBuzB,CAAmBD,IAG/C,OAAOnjB,EAAagjB,GAGtB,SAAShjB,EAAagjB,GACpB,MAAMxgB,EAAWwgB,EAAQnkC,KAEzB,IAAK2jB,EACH,MAAM,IAAI/hB,MAAM,2BAA2BoH,EAAQm7B,OAGrD,MAAMnzB,EAAO4c,EAAQjK,GAErB,IAAK3S,EACH,MAAM,IAAIpP,MAAM,+CAA+C+hB,wFAGjE,OAAO3S,EAGT,SAASqyB,EAAcc,GACrB,OnDtDG,SAA0BnzB,GAC/B,IAAK0O,GAAa1O,GAChB,MAAM,IAAIpP,MAAM,YAAYoH,EAAQgI,mCAGtC,OAAOA,EmDiDEwzB,CAAiBrjB,EAAagjB,IAGvC,SAASM,EAAiBN,GACxB,OnD/CG,SAA6BnzB,GAClC,IAAK2O,GAAgB3O,GACnB,MAAM,IAAIpP,MAAM,YAAYoH,EAAQgI,sCAGtC,OAAOA,EmD0CE0zB,CAAoBvjB,EAAagjB,IAwC1C,SAASnB,EAAyB2B,GAGhC,GAA6C,OAAzCA,EAA0B9wB,YAAuB8wB,EAA0Bn9B,OAASihB,GAAStd,UAC/F,MAAO,GAGT,IAAKw5B,EAA0B9wB,WAAY,CACzC,MAAM+wB,EAA+B57B,EAAQ27B,GAC7C,MAAM,IAAI/iC,MAAM,4CAA4CgjC,MAG9D,OAAOD,EAA0B9wB,WAAWhT,IAAI4jC,GA+DlD,SAASxB,EAAiBJ,GACxB,IAAKA,EAAkB/vB,OACrB,MAAM,IAAIlR,MAAM,wCAAwCoH,EAAQ65B,OAGlE,OAAOxnB,EAAUwnB,EAAkB/vB,QAAQ+xB,GAAsBA,EAAmB7kC,MAAM8kC,GAG5F,SAASA,EAAWD,GAClB,MAAM7zB,EAAOuY,EAAQsb,EAAmB7zB,MAExC,IAAK4P,GAAa5P,GAAO,CACvB,MAAM2kB,EAAU3sB,EAAQgI,GACxB,MAAM,IAAIpP,MAAM,oEAAoE+zB,MAGtF,IAAKkP,EAAmB3wB,KAAM,CAC5B,MAAM6wB,EAAwB/7B,EAAQ67B,GACtC,MAAM,IAAIjjC,MAAM,4CAA4CmjC,MAG9D,MAAO,CACL5gC,YAAa0gC,EAAmB1gC,YAChC+e,kBAAmB2hB,EAAmB3hB,kBACtClS,KAAAA,EACAkD,KAAM2vB,EAAsBgB,EAAmB3wB,OAInD,SAAS2vB,EAAsBmB,GAC7B,OAAO3pB,EAAU2pB,GAA0BzgB,GAAcA,EAAWvkB,MAAMilC,GAG5E,SAASA,EAAgBC,GACvB,MAAMl0B,EAAOuY,EAAQ2b,EAAwBl0B,MAE7C,IAAKyP,GAAYzP,GAAO,CACtB,MAAM2kB,EAAU3sB,EAAQgI,GACxB,MAAM,IAAIpP,MAAM,sEAAsE+zB,MAGxF,MAAMzkB,EAAuD,MAAxCg0B,EAAwBh0B,aAAuBwwB,GlErOjE,SAAoBljC,EAAQuQ,GACjC,MAAMo2B,EAAS,IAAIn2B,OAAOxQ,EAAQuQ,GAClCo2B,EAAO31B,YAAY3H,EAAUC,KAC7B,MAAMxJ,EAAQ6mC,EAAO/zB,mBAAkB,GAEvC,OADA+zB,EAAO31B,YAAY3H,EAAUE,KACtBzJ,EkEgO4EojB,CAAWwjB,EAAwBh0B,cAAeF,QAAQ9P,EAC3I,MAAO,CACLiD,YAAa+gC,EAAwB/gC,YACrC6M,KAAAA,EACAE,aAAAA,EACAgS,kBAAmBgiB,EAAwBhiB,oBC3N1C,SAASkiB,GAAiBC,EAAcpE,EAAalyB,GAE1D,MAAMu2B,EAAW,GACXC,EAAoBtiC,OAAOgY,OAAO,MAGlCuqB,EAAgB,GACtB,IAAIC,EAEJ,MAAMC,EAAmB,GAEzB,IAAK,MAAM7S,KAAOoO,EAAYxxB,YAC5B,GAAIojB,EAAIrrB,OAASpD,EAAK0B,kBACpB2/B,EAAY5S,OACP,GAAIA,EAAIrrB,OAASpD,EAAKsC,iBAC3Bg/B,EAAiBhlC,KAAKmyB,QACjB,GAAIN,GAAqBM,GAC9ByS,EAAS5kC,KAAKmyB,QACT,GAAIL,GAAoBK,GAAM,CACnC,MAAM8S,EAAmB9S,EAAI7yB,KAAK1B,MAC5BsnC,EAAyBL,EAAkBI,GACjDJ,EAAkBI,GAAoBC,EAAyBA,EAAuBjW,OAAO,CAACkD,IAAQ,CAACA,QAC9FA,EAAIrrB,OAASpD,EAAKqC,sBAC3B++B,EAAc9kC,KAAKmyB,GAMvB,GAA8C,IAA1C5vB,OAAO6G,KAAKy7B,GAAmBtmC,QAAoC,IAApBqmC,EAASrmC,QAAyC,IAAzBumC,EAAcvmC,QAA4C,IAA5BymC,EAAiBzmC,QAA6B,MAAbwmC,EACzI,OAAOJ,EAGT,MAAMzX,EAAU3qB,OAAOgY,OAAO,MAE9B,IAAK,MAAM6jB,KAAgBuG,EAAahxB,MACtCuZ,EAAQkR,EAAa9+B,MAAQ6lC,EAAgB/G,GAG/C,IAAK,MAAMhP,KAAYwV,EAAU,CAC/B,MAAMtlC,EAAO8vB,EAAS9vB,KAAK1B,MAC3BsvB,EAAQ5tB,GAAQ8lC,GAAW9lC,IAAS+jC,EAAUjU,GAGhD,MAAMnc,EAAiB,CAErBkX,MAAOwa,EAAaxa,OAASkb,EAAiBV,EAAaxa,OAC3DE,SAAUsa,EAAata,UAAYgb,EAAiBV,EAAata,UACjEE,aAAcoa,EAAapa,cAAgB8a,EAAiBV,EAAapa,iBAErEwa,GAAaO,EAAkB,CAACP,OACjCO,EAAkBN,IAGvB,MAAO,CACLvhC,YAAashC,GAAWthC,aAAa7F,SAClCqV,EACHU,MAAOqG,EAAakT,GACpBvd,WAAY,IAAIg1B,EAAah1B,WAAWxP,KA6B1C,SAA0BunB,GACxB,MAAM3G,EAAS2G,EAAUpG,WACzB,OAAO,IAAI6H,iBAAiB,IAAKpI,EAC/BvN,KAAMgH,EAASuG,EAAOvN,KAAM+xB,WAhCoCT,EAAc3kC,KAuMlF,SAAwBgC,GACtB,MAAMS,EAAYT,EAAKS,UAAUzC,KAAI,EACnCvC,MAAAA,KACIA,IACN,OAAO,IAAIurB,iBAAiB,CAC1B7pB,KAAM6C,EAAK7C,KAAK1B,MAChB6F,YAAatB,EAAKsB,aAAa7F,MAC/BgF,UAAAA,EACA+kB,aAAcxlB,EAAKoS,WACnBf,KAAMgyB,EAAiBrjC,EAAK8O,WAC5BmQ,QAASjf,QAhNXV,gBAAYjB,EACZ4gB,QAAS2jB,GAAaJ,EAAavjB,QACnCC,kBAAmBsjB,EAAatjB,kBAAkB4N,OAAO+V,GACzD/a,YAAa5b,GAAS4b,cAAe,GAIvC,SAASwb,EAAYn1B,GACnB,OAAI+O,GAAW/O,GAEN,IAAIuP,YAAY4lB,EAAYn1B,EAAK2P,SAGtCX,GAAchP,GAET,IAAIwP,eAAe2lB,EAAYn1B,EAAK2P,SAGtColB,EAAiB/0B,GAG1B,SAAS+0B,EAAiB/0B,GAIxB,OAAO4c,EAAQ5c,EAAKhR,MAUtB,SAAS6lC,EAAgB70B,GACvB,OAAI2Y,GAAoB3Y,IAASyV,GAAsBzV,GAE9CA,EAGLyO,GAAazO,GAqDnB,SAA0BA,GACxB,MAAMyQ,EAASzQ,EAAKgR,WACd7f,EAAaojC,EAAkB9jB,EAAOzhB,OAAS,GACrD,IAAI2hB,EAAiBF,EAAOE,eAE5B,IAAK,MAAMykB,KAAiBjkC,EAC1Bwf,EAAiB0kB,GAAkBD,IAAkBzkB,EAGvD,OAAO,IAAI1B,kBAAkB,IAAKwB,EAChCE,eAAAA,EACAI,kBAAmBN,EAAOM,kBAAkB4N,OAAOxtB,KA/D5CmkC,CAAiBt1B,GAGtB0O,GAAa1O,GAgEnB,SAA0BA,GACxB,MAAMyQ,EAASzQ,EAAKgR,WACd7f,EAAaojC,EAAkB9jB,EAAOzhB,OAAS,GACrD,OAAO,IAAIkgB,kBAAkB,IAAKuB,EAChC5N,WAAY,IAAM,IAAI7C,EAAKwR,gBAAgB3hB,IAAIklC,MAAsBQ,EAAgBpkC,IACrF2Q,OAAQ,SAAYoI,EAASuG,EAAO3O,OAAQ0zB,MACvCC,EAActkC,KAEnB4f,kBAAmBN,EAAOM,kBAAkB4N,OAAOxtB,KAvE5CukC,CAAiB11B,GAGtB2O,GAAgB3O,GAwEtB,SAA6BA,GAC3B,MAAMyQ,EAASzQ,EAAKgR,WACd7f,EAAaojC,EAAkB9jB,EAAOzhB,OAAS,GACrD,OAAO,IAAImgB,qBAAqB,IAAKsB,EACnC5N,WAAY,IAAM,IAAI7C,EAAKwR,gBAAgB3hB,IAAIklC,MAAsBQ,EAAgBpkC,IACrF2Q,OAAQ,SAAYoI,EAASuG,EAAO3O,OAAQ0zB,MACvCC,EAActkC,KAEnB4f,kBAAmBN,EAAOM,kBAAkB4N,OAAOxtB,KA/E5CwkC,CAAoB31B,GAGzB4O,GAAY5O,GAgFlB,SAAyBA,GACvB,MAAMyQ,EAASzQ,EAAKgR,WACd7f,EAAaojC,EAAkB9jB,EAAOzhB,OAAS,GACrD,OAAO,IAAIogB,iBAAiB,IAAKqB,EAC/BpN,MAAO,IAAM,IAAIrD,EAAK0S,WAAW7iB,IAAIklC,MAAsBa,EAAgBzkC,IAC3E4f,kBAAmBN,EAAOM,kBAAkB4N,OAAOxtB,KApF5C0kC,CAAgB71B,GAGrB6O,GAAW7O,GA0BjB,SAAwBA,GACtB,MAAMyQ,EAASzQ,EAAKgR,WACd7f,EAAaojC,EAAkBv0B,EAAKhR,OAAS,GACnD,OAAO,IAAIqgB,gBAAgB,IAAKoB,EAC9B7O,OAAQ,IAAK6O,EAAO7O,UACfk0B,EAAkB3kC,IAEvB4f,kBAAmBN,EAAOM,kBAAkB4N,OAAOxtB,KAhC5C4kC,CAAe/1B,GAIpB8O,GAAkB9O,GAQxB,SAA+BA,GAC7B,MAAMyQ,EAASzQ,EAAKgR,WACd7f,EAAaojC,EAAkB9jB,EAAOzhB,OAAS,GACrD,OAAO,IAAIsgB,uBAAuB,IAAKmB,EACrC3O,OAAQ,SAAYoI,EAASuG,EAAO3O,QAAQyM,QAAeA,EACvDvO,KAAMm1B,EAAY5mB,EAAMvO,aAEvBg2B,EAAmB7kC,KAExB4f,kBAAmBN,EAAOM,kBAAkB4N,OAAOxtB,KAhB5C8kC,CAAsBj2B,QAItBiO,GAAU,EAAG,oBAAsBjW,EAAQgI,IA2EtD,SAASw1B,EAAYjnB,GACnB,MAAO,IAAKA,EACVvO,KAAMm1B,EAAY5mB,EAAMvO,MAExBkD,KAAMgH,EAASqE,EAAMrL,KAAM+xB,IAI/B,SAASA,EAAU5iB,GACjB,MAAO,IAAKA,EACVrS,KAAMm1B,EAAY9iB,EAAIrS,OAI1B,SAASg1B,EAAkBjkC,GACzB,MAAMmlC,EAAU,GAEhB,IAAK,MAAMrkC,KAAQd,EAAO,CAExB,MAAMo8B,EAAsBt7B,EAAK8Q,gBAAkB,GAEnD,IAAK,MAAMyqB,KAAiBD,EAC1B+I,EAAQ9I,EAAcjuB,WAAagR,EAAaid,EAAcptB,MAOlE,OAAOk2B,EAGT,SAAS/lB,EAAate,GACpB,MAAM7C,EAAO6C,EAAK7C,KAAK1B,MACjB0S,EAAO80B,GAAW9lC,IAAS4tB,EAAQ5tB,GAEzC,QAAakB,IAAT8P,EACF,MAAM,IAAIpP,MAAM,kBAAkB5B,OAGpC,OAAOgR,EAGT,SAASm2B,EAAetkC,GACtB,OAAIA,EAAK2E,OAASpD,EAAKwB,UACd,IAAI2a,YAAY4mB,EAAetkC,EAAKmO,OAGzCnO,EAAK2E,OAASpD,EAAKyB,cAEd,IAAI2a,eAAe2mB,EAAetkC,EAAKmO,OAGzCmQ,EAAate,GAiBtB,SAAS4jC,EAAc1kC,GACrB,MAAMqlC,EAAiBnkC,OAAOgY,OAAO,MAErC,IAAK,MAAMpY,KAAQd,EAAO,CAExB,MAAMslC,EAAaxkC,EAAKiQ,QAAU,GAElC,IAAK,MAAMyM,KAAS8nB,EAClBD,EAAe7nB,EAAMvf,KAAK1B,OAAS,CAIjC0S,KAAMm2B,EAAe5nB,EAAMvO,MAC3B7M,YAAaob,EAAMpb,aAAa7F,MAChC4V,KAAMgyB,EAAiB3mB,EAAM5N,WAC7BuR,kBAAmBokB,GAAqB/nB,GACxCuC,QAASvC,GAKf,OAAO6nB,EAGT,SAASlB,EAAiBhyB,GAExB,MAAMihB,EAAYjhB,GAAQ,GACpBqzB,EAAetkC,OAAOgY,OAAO,MAEnC,IAAK,MAAMoI,KAAO8R,EAAW,CAI3B,MAAMnkB,EAAOm2B,EAAe9jB,EAAIrS,MAChCu2B,EAAalkB,EAAIrjB,KAAK1B,OAAS,CAC7B0S,KAAAA,EACA7M,YAAakf,EAAIlf,aAAa7F,MAC9B4S,aAAcwwB,GAAare,EAAInS,aAAcF,GAC7CkS,kBAAmBokB,GAAqBjkB,GACxCvB,QAASuB,GAIb,OAAOkkB,EAGT,SAASP,EAAmBjlC,GAC1B,MAAMylC,EAAgBvkC,OAAOgY,OAAO,MAEpC,IAAK,MAAMpY,KAAQd,EAAO,CAExB,MAAM0lC,EAAc5kC,EAAKiQ,QAAU,GAEnC,IAAK,MAAMyM,KAASkoB,EAAa,CAI/B,MAAMz2B,EAAOm2B,EAAe5nB,EAAMvO,MAClCw2B,EAAcjoB,EAAMvf,KAAK1B,OAAS,CAChC0S,KAAAA,EACA7M,YAAaob,EAAMpb,aAAa7F,MAChC4S,aAAcwwB,GAAaniB,EAAMrO,aAAcF,GAC/CkS,kBAAmBokB,GAAqB/nB,GACxCuC,QAASvC,IAKf,OAAOioB,EAGT,SAASV,EAAkB/kC,GACzB,MAAM2lC,EAAezkC,OAAOgY,OAAO,MAEnC,IAAK,MAAMpY,KAAQd,EAAO,CAExB,MAAMglB,EAAclkB,EAAK+P,QAAU,GAEnC,IAAK,MAAMtU,KAASyoB,EAClB2gB,EAAappC,EAAM0B,KAAK1B,OAAS,CAC/B6F,YAAa7F,EAAM6F,aAAa7F,MAChC4kB,kBAAmBokB,GAAqBhpC,GACxCwjB,QAASxjB,GAKf,OAAOopC,EAGT,SAASnB,EAAgBxkC,GACvB,MAAM8R,EAAa,GAEnB,IAAK,MAAMhR,KAAQd,EAAO,CAExB,MAAM4lC,EAAkB9kC,EAAKgR,YAAc,GAE3C,IAAK,MAAM7C,KAAQ22B,EAKjB9zB,EAAWnT,KAAKygB,EAAanQ,IAIjC,OAAO6C,EAGT,SAAS+yB,EAAgB7kC,GACvB,MAAMsS,EAAQ,GAEd,IAAK,MAAMxR,KAAQd,EAAO,CAExB,MAAM6lC,EAAY/kC,EAAKwR,OAAS,GAEhC,IAAK,MAAMrD,KAAQ42B,EAKjBvzB,EAAM3T,KAAKygB,EAAanQ,IAI5B,OAAOqD,EAGT,SAAS0vB,EAAUjiB,GACjB,MAAM9hB,EAAO8hB,EAAQ9hB,KAAK1B,MACpBupC,EAAiBtC,EAAkBvlC,IAAS,GAElD,OAAQ8hB,EAAQta,MACd,KAAKpD,EAAK6B,uBACR,CACE,MAAM8b,EAAoB8lB,EACpBC,EAAW,CAAChmB,KAAYC,GAC9B,OAAO,IAAI7B,kBAAkB,CAC3BlgB,KAAAA,EACAmE,YAAa2d,EAAQ3d,aAAa7F,MAClCuV,WAAY,IAAM0yB,EAAgBuB,GAClCh1B,OAAQ,IAAM2zB,EAAcqB,GAC5BhmB,QAAAA,EACAC,kBAAAA,IAIN,KAAK3d,EAAKgC,0BACR,CACE,MAAM2b,EAAoB8lB,EACpBC,EAAW,CAAChmB,KAAYC,GAC9B,OAAO,IAAI5B,qBAAqB,CAC9BngB,KAAAA,EACAmE,YAAa2d,EAAQ3d,aAAa7F,MAClCuV,WAAY,IAAM0yB,EAAgBuB,GAClCh1B,OAAQ,IAAM2zB,EAAcqB,GAC5BhmB,QAAAA,EACAC,kBAAAA,IAIN,KAAK3d,EAAKkC,qBACR,CACE,MAAMyb,EAAoB8lB,EACpBC,EAAW,CAAChmB,KAAYC,GAC9B,OAAO,IAAI1B,gBAAgB,CACzBrgB,KAAAA,EACAmE,YAAa2d,EAAQ3d,aAAa7F,MAClCsU,OAAQk0B,EAAkBgB,GAC1BhmB,QAAAA,EACAC,kBAAAA,IAIN,KAAK3d,EAAKiC,sBACR,CACE,MAAM0b,EAAoB8lB,EACpBC,EAAW,CAAChmB,KAAYC,GAC9B,OAAO,IAAI3B,iBAAiB,CAC1BpgB,KAAAA,EACAmE,YAAa2d,EAAQ3d,aAAa7F,MAClC+V,MAAO,IAAMuyB,EAAgBkB,GAC7BhmB,QAAAA,EACAC,kBAAAA,IAIN,KAAK3d,EAAK4B,uBACR,CACE,MAAM+b,EAAoB8lB,EAC1B,OAAO,IAAI5nB,kBAAkB,CAC3BjgB,KAAAA,EACAmE,YAAa2d,EAAQ3d,aAAa7F,MAClCqjB,eAAgB0kB,GAAkBvkB,GAClCA,QAAAA,EACAC,kBAAAA,IAIN,KAAK3d,EAAKoC,6BACR,CACE,MAAMub,EAAoB8lB,EACpBC,EAAW,CAAChmB,KAAYC,GAC9B,OAAO,IAAIzB,uBAAuB,CAChCtgB,KAAAA,EACAmE,YAAa2d,EAAQ3d,aAAa7F,MAClCwU,OAAQ,IAAMk0B,EAAmBc,GACjChmB,QAAAA,EACAC,kBAAAA,KAMC9C,GAAU,EAAG,oCAAsCjW,EAAQ8Y,KAGxE,MAAMgkB,GAAa/qB,EAAOyL,GAAqBmJ,OAAOjG,KAAqB1Y,GAAQA,EAAKhR,OAMxF,SAASsnC,GAAqBzkC,GAE5B,OADmBo/B,GAAmB/X,GAA4BrnB,IAC/CsnB,OAOrB,SAASkc,GAAkBxjC,GAEzB,OADoBo/B,GAAmB7X,GAA6BvnB,IAChDwnB,ICphBf,SAAS0d,GAAe9G,EAAalyB,GAC3B,MAAfkyB,GAAuBA,EAAYz5B,OAASpD,EAAKG,UAAYiG,EAAU,EAAG,qCAE7C,IAAzBuE,GAAS4b,cAAoD,IAA5B5b,GAASi5B,gBLqDzC,SAAwB/G,GAC7B,MAAM9S,EAASqT,GAAYP,GAE3B,GAAsB,IAAlB9S,EAAOlvB,OACT,MAAM,IAAI2C,MAAMusB,EAAOttB,KAAI+C,GAASA,EAAM9B,UAASN,KAAK,SKxDxDymC,CAAehH,GAGjB,MAQMxf,EAAS2jB,GARW,CACxBjhC,iBAAajD,EACbmT,MAAO,GACPhE,WAAY,GACZlO,gBAAYjB,EACZ6gB,kBAAmB,GACnB4I,aAAa,GAEoCsW,EAAalyB,GAEhE,GAAsB,MAAlB0S,EAAOK,QACT,IAAK,MAAM9Q,KAAQyQ,EAAOpN,MACxB,OAAQrD,EAAKhR,MAIX,IAAK,QACHyhB,EAAOoJ,MAAQ7Z,EACf,MAEF,IAAK,WACHyQ,EAAOsJ,SAAW/Z,EAClB,MAEF,IAAK,eACHyQ,EAAOwJ,aAAeja,EAM9B,MAAMX,WACJA,GACEoR,EAEJ,IAAK,MAAMymB,KAAgB5d,GACrBja,EAAWyoB,OAAM1Q,GAAaA,EAAUpoB,OAASkoC,EAAaloC,QAChEqQ,EAAW3P,KAAKwnC,GAIpB,OAAO,IAAI1d,cAAc/I,GCxDpB,SAAS0mB,GAAYhjB,GAC1B,OAUF,SAA6BA,EAAQijB,EAAiBC,GACpD,MAAMh4B,EAAa8U,EAAOgD,gBAAgBnnB,OAAOonC,GAC3C/zB,EAAQqG,EAAayK,EAAOwC,cAAc3mB,OAAOqnC,GACvD,MAAO,CAACC,GAAsBnjB,IAASwK,OAAOtf,EAAWxP,KAAIunB,GAiK/D,SAAwBA,GACtB,OAAOmgB,GAAiBngB,GAAa,cAAgBA,EAAUpoB,KAAOwoC,GAAUpgB,EAAUlU,OAASkU,EAAUC,aAAe,cAAgB,IAAM,OAASD,EAAU9kB,UAAU9B,KAAK,OAlK1GinC,CAAergB,KAAa/T,EAAMxT,KAAImQ,GAiE3G,SAAmBA,GACxB,GAAIyO,GAAazO,GACf,OA4BJ,SAAqBA,GACnB,OAAOu3B,GAAiBv3B,GAAQ,UAAUA,EAAKhR,OAmFjD,SAA6B0oC,GAC3B,GAA6B,MAAzBA,EAAO/mB,eACT,MAAO,GAGT,MACMgnB,EAASjiB,GADHgiB,EAAO/mB,eACc0E,IAEjC,OADAsiB,GAAU1pB,GAAU,EAAG,yEAChB,sBAAwBhB,EAAM0qB,GAAU,IA3FSC,CAAoB53B,GA7BnE63B,CAAY73B,GAGrB,GAAI0O,GAAa1O,GACf,OAiCJ,SAAqBA,GACnB,OAAOu3B,GAAiBv3B,GAAQ,QAAQA,EAAKhR,OAAS8oC,GAA2B93B,GAAQ+3B,GAAY/3B,GAlC5Fg4B,CAAYh4B,GAGrB,GAAI2O,GAAgB3O,GAClB,OAiCJ,SAAwBA,GACtB,OAAOu3B,GAAiBv3B,GAAQ,aAAaA,EAAKhR,OAAS8oC,GAA2B93B,GAAQ+3B,GAAY/3B,GAlCjGi4B,CAAej4B,GAGxB,GAAI4O,GAAY5O,GACd,OAiCJ,SAAoBA,GAClB,MAAMqD,EAAQrD,EAAK0S,WACbmF,EAAgBxU,EAAMpV,OAAS,MAAQoV,EAAM7S,KAAK,OAAS,GACjE,OAAO+mC,GAAiBv3B,GAAQ,SAAWA,EAAKhR,KAAO6oB,EApC9CqgB,CAAWl4B,GAGpB,GAAI6O,GAAW7O,GACb,OAmCJ,SAAmBA,GACjB,MAAM4B,EAAS5B,EAAKoT,YAAYvjB,KAAI,CAACvC,EAAOmC,IAAM8nC,GAAiBjqC,EAAO,MAAOmC,GAAK,KAAOnC,EAAM0B,KAAOmpC,GAAgB7qC,EAAM4kB,qBAChI,OAAOqlB,GAAiBv3B,GAAQ,QAAQA,EAAKhR,OAASopC,GAAWx2B,GArCxDy2B,CAAUr4B,GAInB,GAAI8O,GAAkB9O,GACpB,OAmCJ,SAA0BA,GACxB,MAAM8B,EAAS4H,EAAa1J,EAAKuR,aAAa1hB,KAAI,CAACyoC,EAAG7oC,IAAM8nC,GAAiBe,EAAG,MAAO7oC,GAAK,KAAO8oC,GAAgBD,KACnH,OAAOf,GAAiBv3B,GAAQ,SAASA,EAAKhR,OAASopC,GAAWt2B,GArCzD02B,CAAiBx4B,GAIjBiO,GAAU,EAAG,oBAAsBjW,EAAQgI,IA5FoEy4B,CAAUz4B,MAAQhQ,OAAO0J,SAASlJ,KAAK,QAAU,KAblKkoC,CAAoBvkB,GAAQwkB,IAAK,OhD0ILvhB,EgD1I2BuhB,GhD2IvDrf,GAAoBtL,MAAK,EAC9Bhf,KAAAA,KACIA,IAASooB,EAAUpoB,OAHpB,IAA8BooB,IgD1I+BwhB,IAMpE,SAASA,GAAc54B,GACrB,OAAQyV,GAAsBzV,KAAU2Y,GAAoB3Y,GAS9D,SAASs3B,GAAsBnjB,GAC7B,GAA0B,MAAtBA,EAAOhhB,aAuCb,SAA+BghB,GAC7B,MAAMyC,EAAYzC,EAAO0C,eAEzB,GAAID,GAAgC,UAAnBA,EAAU5nB,KACzB,OAAO,EAGT,MAAM8nB,EAAe3C,EAAO4C,kBAE5B,GAAID,GAAsC,aAAtBA,EAAa9nB,KAC/B,OAAO,EAGT,MAAMgoB,EAAmB7C,EAAO8C,sBAEhC,GAAID,GAA8C,iBAA1BA,EAAiBhoB,KACvC,OAAO,EAGT,OAAO,EA1D2B6pC,CAAsB1kB,GACtD,OAGF,MAAMxR,EAAiB,GACjBiU,EAAYzC,EAAO0C,eAErBD,GACFjU,EAAejT,KAAK,YAAYknB,EAAU5nB,QAG5C,MAAM8nB,EAAe3C,EAAO4C,kBAExBD,GACFnU,EAAejT,KAAK,eAAeonB,EAAa9nB,QAGlD,MAAMgoB,EAAmB7C,EAAO8C,sBAMhC,OAJID,GACFrU,EAAejT,KAAK,mBAAmBsnB,EAAiBhoB,QAGnDuoC,GAAiBpjB,GAAU,aAAaxR,EAAenS,KAAK,WAwErE,SAASsnC,GAA2B93B,GAClC,MAAM6C,EAAa7C,EAAKwR,gBACxB,OAAO3O,EAAW5U,OAAS,eAAiB4U,EAAWhT,KAAIJ,GAAKA,EAAET,OAAMwB,KAAK,OAAS,GA2BxF,SAASunC,GAAY/3B,GAEnB,OAAOo4B,GADQ1uB,EAAa1J,EAAKuR,aAAa1hB,KAAI,CAACyoC,EAAG7oC,IAAM8nC,GAAiBe,EAAG,MAAO7oC,GAAK,KAAO6oC,EAAEtpC,KAAOwoC,GAAUc,EAAEp1B,KAAM,MAAQ,KAAO3J,OAAO++B,EAAEt4B,MAAQm4B,GAAgBG,EAAEpmB,sBAIlL,SAASkmB,GAAWz/B,GAClB,OAAwB,IAAjBA,EAAM1K,OAAe,OAAS0K,EAAMnI,KAAK,MAAQ,MAAQ,GAGlE,SAASgnC,GAAUt0B,EAAM9H,EAAc,IACrC,OAAoB,IAAhB8H,EAAKjV,OACA,GAILiV,EAAK4kB,OAAMzV,IAAQA,EAAIlf,cAClB,IAAM+P,EAAKrT,IAAI0oC,IAAiB/nC,KAAK,MAAQ,IAG/C,MAAQ0S,EAAKrT,KAAI,CAACwiB,EAAK5iB,IAAM8nC,GAAiBllB,EAAK,KAAOjX,GAAc3L,GAAK,KAAO2L,EAAcm9B,GAAgBlmB,KAAM7hB,KAAK,MAAQ,KAAO4K,EAAc,IAGnK,SAASm9B,GAAgBlmB,GACvB,MAAMymB,EAAapjB,GAAarD,EAAInS,aAAcmS,EAAIrS,MACtD,IAAI+4B,EAAU1mB,EAAIrjB,KAAO,KAAOuK,OAAO8Y,EAAIrS,MAM3C,OAJI84B,IACFC,GAAW,MAAM9rB,EAAM6rB,MAGlBC,EAAUZ,GAAgB9lB,EAAIH,mBAOvC,SAASimB,GAAgBhf,GACvB,GAAc,MAAVA,EACF,MAAO,GAGT,MAAM6f,EAAYtjB,GAAayD,EAAQ9D,IAEvC,OAAI2jB,GAAa7f,IAAWF,GACnB,wBAA0BhM,EAAM+rB,GAAa,IAG/C,eAcT,SAASzB,GAAiB1V,EAAKzmB,EAAc,GAAI69B,GAAe,GAC9D,MAAM9lC,YACJA,GACE0uB,EAEJ,GAAmB,MAAf1uB,EACF,MAAO,GAMT,OADeiI,IAAgB69B,EAAe,KAAO79B,EAAcA,GAD/CD,EAAiBhI,EAAa,GADtBA,EAAYlF,OAAS,IAGrBiL,QAAQ,MAAO,KAAOkC,GAAe,KCxNnE,MAAM89B,GAA4B,CAAC1W,IAEtB2W,GAA2C,UAMrB3d,GACjC,MAAO,CACLxW,oBAAoBnT,IACbA,EAAK7C,MACRwsB,EAAQE,YACN,IAAI/qB,aACF,2IACAkB,KAIC,cAKmB2pB,GAC9B,MAAO,CACLpW,MAAMvT,GAEa,eADCA,EAAK6O,OAAS7O,EAAK6O,MAAMpT,QAEzCkuB,EAAQE,YACN,IAAI/qB,aACF,sGACAkB,UA3BPk4B,GAAe/5B,QAAQsgC,IAAU4I,GAA0BE,SAAS9I,YCO5D+I,qCAAqCzoC,MAChDC,YAAmByoC,GACjBloC,MAAMkoC,EAAiBzpC,KAAK+C,GAAUA,EAAM9B,UAASN,KAAK,SADzC2B,sBAAAmnC,EAGjBnnC,KAAKnD,KAAO,yCAWAohC,GAAkBjc,GAChC,MAAMgJ,EAAS5B,GAAepH,GAC9B,GAAsB,IAAlBgJ,EAAOlvB,OACT,MAAM,IAAIorC,6BAA6Blc,YAY3Boc,GAAgBvqC,GAC9B,OAAOA,EAAKwqC,WAAW,eCrDTC,GACdnsC,GAEA,OAAOA,MAAAA,WCwBOosC,GAAmBvrB,GACjC,OAAQA,EAAU3X,MAChB,IAAK,WACH,MAAO,CAAEA,KAAM2X,EAAU3X,KAAMlJ,MAAO6gB,EAAUnf,KAAK1B,OACvD,IAAK,YACH,MAAO,CACLkJ,KAAM2X,EAAU3X,KAChBlJ,MAAO6gB,EAAUvM,OAAO/R,IAAI6pC,KAEhC,IAAK,cACH,MAAO,CACLljC,KAAM2X,EAAU3X,KAChBlJ,MAAO6gB,EAAUrM,OAAOnQ,QAAO,CAACkH,EAAQ0V,KACtC1V,EAAO0V,EAAMvf,KAAK1B,OAASosC,GAAmBnrB,EAAMjhB,OAC7CuL,IACN,KAEP,QACE,OAAOsV,GCjBb,SAASwrB,GAAgB9nC,WACvB,2BAAOA,EAAKL,0BAAKhE,6BAAQwB,cASX4qC,GACdzlB,EACA0lB,GAGA,MAAMC,EAAkB,IAAI7mB,IAE5B,IAAK,MAAMgM,KAAkB4a,EAASp7B,YAChCwgB,EAAezoB,OAASpD,EAAKW,qBAEjC+lC,EAAgB5Q,IAAIjK,EAAejwB,KAAK1B,MAAO2xB,GAGjD,MAAM8a,EAAuC,GACvCC,EAAc,IAAI/mB,IAClBgnB,EAAkB,IAAI7f,IAE5B,IAAK,MAAM6E,KAAkB4a,EAASp7B,YAChCwgB,EAAezoB,OAASpD,EAAKI,sBAEjCumC,EAAWrqC,KAAKwqC,EAAiBjb,IAOnC,IAAK,MAAOjwB,EAAMmrC,KAAiBL,EAAgBhwB,UACjDkwB,EAAY9Q,IAAIl6B,EAAMorC,EAAgBD,IAGxC,MAAO,CACLJ,WAAAA,EACA9K,UAAWv+B,MAAMslB,KAAKgkB,EAAYp4B,UAClCq4B,gBAAiBvpC,MAAMslB,KAAKikB,EAAgBr4B,WAkB9C,SAASs4B,EACPG,GAEA,IAAKA,EAAoBrrC,KACvB,MAAM,IAAI2B,aAAa,6BAA8B0pC,GAGvD,MAAMC,EAAWX,GAAgBU,GAC3BrrC,EAAOqrC,EAAoBrrC,KAAK1B,MAChC8/B,EAAgBiN,EAAoBl7B,UAEpCiP,GAAaisB,EAAoBj7B,qBAAuB,IAAIvP,KAC/DgC,IACC,MAAM7C,EAAO6C,EAAKiO,SAAS9Q,KAAK1B,MAK1B0S,EAAOkf,GAAY/K,EAAQtiB,EAAKmO,MAItC,IAAKA,EACH,MAAM,IAAIrP,aACR,qCAAqCkB,EAAKmO,QAC1CnO,GAMJ,OAFAooC,EAAgB5e,IAAIlL,GAAanQ,IAE1B,CACLhR,KAAAA,EACAgR,KAAAA,MAKAxS,EAASyf,EAAMotB,GACfE,EC5HH,SAA8BpmB,EAAQhV,GAC3C,GAA4B,UAAxBA,EAAUA,UAAuB,CACnC,MAAMyX,EAAYzC,EAAO0C,eAEzB,IAAKD,EACH,MAAM,IAAIjmB,aAAa,uDAAwDwO,GAGjF,OAAOyX,EAGT,GAA4B,aAAxBzX,EAAUA,UAA0B,CACtC,MAAM2X,EAAe3C,EAAO4C,kBAE5B,IAAKD,EACH,MAAM,IAAInmB,aAAa,0CAA2CwO,GAGpE,OAAO2X,EAGT,GAA4B,iBAAxB3X,EAAUA,UAA8B,CAC1C,MAAM6X,EAAmB7C,EAAO8C,sBAEhC,IAAKD,EACH,MAAM,IAAIrmB,aAAa,8CAA+CwO,GAGxE,OAAO6X,EAGT,MAAM,IAAIrmB,aAAa,6DAA8DwO,GD6FlEq7B,CACfrmB,EACAkmB,GAGF,MAAO,CACLC,SAAAA,EACAtrC,KAAAA,EACAo+B,cAAAA,EACAmN,SAAAA,EACAnsB,UAAAA,EACA5gB,OAAAA,EACA8R,aAAcm7B,EACZJ,EAAoB/6B,aACpBi7B,IAKN,SAASH,EACPM,GAEA,MAAM1rC,EAAO0rC,EAAmB1rC,KAAK1B,MAE/BgtC,EAAWX,GAAgBe,GAC3BltC,EAASyf,EAAMytB,GAEft5B,EAAgB8d,GACpB/K,EACAumB,EAAmBt5B,eAGrB,MAAO,CACLpS,KAAAA,EACAsrC,SAAAA,EACA9sC,OAAAA,EACA4T,cAAAA,EACA9B,aAAcm7B,EACZC,EAAmBp7B,aACnB8B,IAKN,SAASq5B,EACPE,EACAliB,EACAmiB,EAAgC,IAAIxgB,KAEpC,MAAO,CACL3B,WAAAA,EACApY,WAAYs6B,EAAiBt6B,WAC1BxQ,KAAKgrC,GAOZ,SACEA,EACApiB,EACAmiB,SAEA,OAAQC,EAAcrkC,MACpB,KAAKpD,EAAKO,MAAO,CACf,MAAM3E,EAAO6rC,EAAc7rC,KAAK1B,MAC1BoT,YAAQm6B,EAAcn6B,4BAAOpT,MAE7BkzB,WHjGZrM,EACAsE,EACA5G,GAEA,OACEA,IAAcwG,GAAmBrpB,MACjCmlB,EAAO0C,iBAAmB4B,EAEnBJ,GAELxG,IAAcyG,GAAiBtpB,MAAQmlB,EAAO0C,iBAAmB4B,EAC5DH,GAGPzG,IAAc2G,GAAqBxpB,OAClC0f,GAAa+J,IACZ9J,GAAgB8J,IAChB7J,GAAY6J,IAEPD,GAEL9J,GAAa+J,IAAe9J,GAAgB8J,GACvCA,EAAWlH,YAAYM,QADhC,EG4EuBoO,CAAY9L,EAAQsE,EAAYzpB,GACjD,IAAKwxB,EACH,MAAM,IAAI7vB,aACR,uBAAuB3B,eAAkBuK,OAAOkf,MAChDoiB,GAIJ,MAAMve,EAAYkE,EAASxgB,KACrB86B,EAAqB3qB,GAAamM,GAExC2d,EAAgB5e,IAAIyf,GAEpB,MAAM3nC,YAAEA,EAAW+e,kBAAEA,GAAsBsO,EAkB3C,IAAIjS,EAAkB,CACpB/X,KAAM,QACNxH,KAAAA,EACA0R,MAAAA,EACAC,UAnBAk6B,EAAcl6B,WAAak6B,EAAcl6B,UAAU1S,OAAS,EACxD4sC,EAAcl6B,UAAU9Q,KAAKwiB,IAC3B,MAAMrjB,EAAOqjB,EAAIrjB,KAAK1B,MAChBszB,EAASJ,EAAStd,KAAKgY,MAC1B0F,GAAWA,EAAO5xB,OAASqjB,EAAIrjB,KAAK1B,QAEjCytC,EAAcna,GAAUA,EAAO5gB,WAAS9P,EAC9C,MAAO,CACLlB,KAAAA,EACA1B,MAAOosC,GAAmBrnB,EAAI/kB,OAC9B0S,KAAM+6B,WAGV7qC,EAOJ8P,KAAMsc,EACNnpB,aACGomC,GAAgBvqC,IAASmE,EAAcA,OAAcjD,EACxDgiB,kBAAmBA,QAAqBhiB,GAG1C,GAAI4f,GAAgBgrB,GAAqB,CACvC,MAAMH,EAAmBE,EAAcv7B,aAEvC,IAAKq7B,EACH,MAAM,IAAIhqC,aACR,oBAAoB3B,eAAkBuK,OACpCkf,6BAEFoiB,GAIJtsB,EAAMjP,aAAem7B,EACnBE,EACAG,GAGJ,OAAOvsB,EAET,KAAKnb,EAAKU,gBAAiB,CACzB,MAAMgrB,EAAW+b,EAAcz5B,cACzBA,EAAgB0d,EACjBI,GAAY/K,EAAQ2K,GACrBrG,EACJ,MAAO,CACLjiB,KAAM,iBACN8I,aAAcm7B,EACZI,EAAcv7B,aACd8B,IAIN,KAAKhO,EAAKS,gBAAiB,CACzB,MAAMmyB,EAAe6U,EAAc7rC,KAAK1B,MACxC,GAAIstC,EAAiBxf,IAAI4K,GAAe,OACxC4U,EAAiBvf,IAAI2K,GAErB,MAAMpD,EA1MZ,SAAqB5zB,GACnB,IAAI4zB,EAAWoX,EAAYjnC,IAAI/D,GAC/B,GAAI4zB,EAAU,OAAOA,EAErB,MAAMuX,EAAeL,EAAgB/mC,IAAI/D,GACzC,OAAKmrC,GAGLL,EAAgBzf,OAAOrrB,GAEvB4zB,EAAWwX,EAAgBD,GAC3BH,EAAY9Q,IAAIl6B,EAAM4zB,GACfA,QAPP,EAqMqBqD,CAAYD,GAC7B,IAAKpD,EACH,MAAM,IAAIjyB,aACR,qBAAqBq1B,MACrB6U,EAAc7rC,MAQlB,MAJ0C,CACxCwH,KAAM,iBACNosB,SAAAA,KAzGAoY,CAAiBH,EAAepiB,EAAYmiB,KAE7C5qC,OAAOypC,aH/HRrmC,EAAKO,MACGP,EAAKE,oZKqBnB6gB,EACA0lB,GAEA,OAAOD,GAAYzlB,EAAQ0lB,iDAlD3BoB,GAEA,IAAIC,EAAU/iC,KAAK2F,MAAMm9B,GAErBC,EAAQC,OACVD,EAAUA,EAAQC,MAGpB,MAAMhnB,EAASsd,GAAkByJ,GAIjC,OAFA9K,GAAkBjc,GAEXA,gCAGyB3mB,GAChC,MAAMqsC,EAAW/7B,EAAMtQ,aLlBMqsC,GAC7B,MAAM1c,EAASqT,GAAYqJ,GAC3B,GAAsB,IAAlB1c,EAAOlvB,OACT,MAAM,IAAIorC,6BAA6Blc,GKiBzC8Z,CAAe4C,GAEf,MAAM1lB,EAAS4iB,GAAe8C,EAAU,CAAE7C,gBAAgB,IAI1D,OAFA5G,GAAkBjc,GAEXA,6BAWsBinB,GAC7B,OC/DK,SAAmBA,GACxB,IAAI38B,EAAc,GAElB,IAAK,MAAM48B,KAAOD,EAChB38B,EAAcA,EAAYkgB,OAAO0c,EAAI58B,aAGvC,MAAO,CACLjI,KAAM,WACNiI,YAAAA,GDsDK68B,CAAUF,6BALW5tC,GAC5B,OAAOsQ,EAAMtQ,gCALkB2mB,GAC/B,OAAOgjB,GAAYhjB,gCAYnBA,EACA0lB,GAEA,OAAO7J,GAAS7b,EAAQ0lB,EAAUV"} \ No newline at end of file diff --git a/Sources/ApolloCodegenLib/Info.plist b/Sources/ApolloCodegenLib/Info.plist deleted file mode 100644 index 4f79224132..0000000000 --- a/Sources/ApolloCodegenLib/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2019 Apollo GraphQL. All rights reserved. - - diff --git a/Sources/ApolloCodegenLib/StaticString+Apollo.swift b/Sources/ApolloCodegenLib/StaticString+Apollo.swift deleted file mode 100644 index 3f227d47b6..0000000000 --- a/Sources/ApolloCodegenLib/StaticString+Apollo.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation -#if !COCOAPODS -import ApolloUtils -#endif - -extension StaticString: ApolloCompatible {} - -extension ApolloExtension where Base == StaticString { - var lastPathComponent: String { - return (toString as NSString).lastPathComponent - } - - var toString: String { - return base.withUTF8Buffer { - String(decoding: $0, as: UTF8.self) - } - } -} diff --git a/Sources/ApolloCodegenLib/URL+Apollo.swift b/Sources/ApolloCodegenLib/URL+Apollo.swift deleted file mode 100644 index cbe922af26..0000000000 --- a/Sources/ApolloCodegenLib/URL+Apollo.swift +++ /dev/null @@ -1,64 +0,0 @@ -import Foundation -#if !COCOAPODS -import ApolloUtils -#endif - -extension URL: ApolloCompatible {} - -public enum ApolloURLError: Error, LocalizedError { - case fileNameIsEmpty - - public var errorDescription: String? { - switch self { - case .fileNameIsEmpty: - return "The file name for this file URL was empty. Please pass a non-empty string." - } - } -} - -extension ApolloExtension where Base == URL { - - /// Determines if the URL passed in is a directory URL. - /// - /// NOTE: Only works if something at the URL already exists. - /// - /// - Returns: True if the URL is a directory URL, false if it isn't. - var isDirectoryURL: Bool { - guard - let resourceValues = try? base.resourceValues(forKeys: [.isDirectoryKey]), - let isDirectory = resourceValues.isDirectory else { - return false - } - - return isDirectory - } - - var isSwiftFileURL: Bool { - base.pathExtension == "swift" - } - - /// - Returns: the URL to the parent folder of the current URL. - public func parentFolderURL() -> URL { - base.deletingLastPathComponent() - } - - /// - Parameter folderName: The name of the child folder to append to the current URL - /// - Returns: The full URL including the appended child folder. - public func childFolderURL(folderName: String) -> URL { - base.appendingPathComponent(folderName, isDirectory: true) - } - - /// Adds the filename to the caller to get the full URL of a file - /// - /// - Parameters: - /// - fileName: The name of the child file, with an extension, for example `"API.swift"`. Note: For hidden files just pass `".filename"`. - /// - Returns: The full URL including the full file. - public func childFileURL(fileName: String) throws -> URL { - guard fileName.apollo.isNotEmpty else { - throw ApolloURLError.fileNameIsEmpty - } - - return base - .appendingPathComponent(fileName, isDirectory: false) - } -} diff --git a/Sources/ApolloCodegenLib/URLDownloader.swift b/Sources/ApolloCodegenLib/URLDownloader.swift deleted file mode 100644 index f0b351e2b5..0000000000 --- a/Sources/ApolloCodegenLib/URLDownloader.swift +++ /dev/null @@ -1,121 +0,0 @@ -import Foundation - -/// A protocol to abstract the underlying network provider. -protocol NetworkSession { - - /// Load data via the abstracted network provider - /// - /// - Parameters: - /// - urlRequest: A URL request object that provides the URL, cache policy, request type, body data or body stream, and so on. - /// - completionHandler: The completion handler to call when the load request is complete. - /// - Returns: The new session data task. This task will already have been started with a call to `resume`. - @discardableResult func loadData(with urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask? -} - -extension URLSession: NetworkSession { - func loadData(with urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask? { - let task = dataTask(with: urlRequest) { (data, response, error) in - completionHandler(data, response, error) - } - task.resume() - - return task - } -} - -/// A class to help download things from a given remote URL to a given local file URL -class URLDownloader { - let session: NetworkSession - - enum DownloadError: Error, LocalizedError { - case badResponse(code: Int, response: String?) - case emptyDataReceived - case noDataReceived - case downloadTimedOut(after: Double) - case responseNotHTTPResponse - - var errorDescription: String? { - switch self { - case .badResponse(let code, let response): - return "Received bad response from server (code \(code)): \(String(describing: response))" - case .emptyDataReceived: - return "Empty data was received from the server." - case .noDataReceived: - return "No data was received from the server." - case .downloadTimedOut(let seconds): - return "Download timed out after \(seconds) seconds." - case .responseNotHTTPResponse: - return "The response was not an HTTP Response, something's gone very wonky." - } - } - } - - /// Designated initializer. - /// - /// - Parameters: - /// - session: The NetworkSession conforming instance used for downloads, defaults to the shared URLSession singleton object. - init(session: NetworkSession = URLSession.shared) { - self.session = session - } - - /// Downloads the contents of a given URL synchronously to the given output URL - /// - Parameters: - /// - urlRequest: A URL request object that provides the URL, cache policy, request type, body data or body stream, and so on. - /// - outputURL: The file URL where the result will be written to. - /// - timeout: The timeout value for the download request duration. - /// - Throws: Any error which occurs during the download. - func downloadSynchronously(with urlRequest: URLRequest, to outputURL: URL, timeout: Double) throws { - let semaphore = DispatchSemaphore(value: 0) - var errorToThrow: Error? = DownloadError.downloadTimedOut(after: timeout) - - session.loadData(with: urlRequest) { data, response, error in - func finished(with finalError: Error?) { - errorToThrow = finalError - semaphore.signal() - } - - if let error = error { - finished(with: error) - return - } - - guard let httpResponse = response as? HTTPURLResponse else { - finished(with: DownloadError.responseNotHTTPResponse) - return - } - - guard httpResponse.statusCode == 200 else { - let dataAsString = String(bytes: data ?? Data(), encoding: .utf8) - finished(with: DownloadError.badResponse(code: httpResponse.statusCode, response: dataAsString)) - return - } - - guard let data = data else { - finished(with: DownloadError.noDataReceived) - return - } - - guard !data.isEmpty else { - finished(with: DownloadError.emptyDataReceived) - return - } - - do { - try FileManager.default.apollo.createContainingFolderIfNeeded(for: outputURL) - try data.write(to: outputURL) - } catch (let writeError) { - finished(with: writeError) - return - } - - // If we got here, it all worked and it's good to go! - finished(with: nil) - } - - _ = semaphore.wait(timeout: .now() + timeout) - - if let throwMe = errorToThrow { - throw throwMe - } // else, success! - } -} diff --git a/Sources/ApolloCodegenLib/UntypedGraphQLRequestBodyCreator.swift b/Sources/ApolloCodegenLib/UntypedGraphQLRequestBodyCreator.swift deleted file mode 100644 index 7c1de2a8af..0000000000 --- a/Sources/ApolloCodegenLib/UntypedGraphQLRequestBodyCreator.swift +++ /dev/null @@ -1,53 +0,0 @@ -import Foundation - -class UntypedGraphQLRequestBodyCreator { - - /// A non-type-safe request creator to facilitate sending requests not using code generation. - /// - /// - Parameters: - /// - operationDocument: The query/mutation/subscription document, as a string - /// - variables: [optional] Any variables to send with the operation - /// - operationName: The name of the operation being sent - /// - sendQueryDocument: If the query document should be sent - defaults to true. - /// - sendOperationIdentifiers: If operation identifers should be sent. Defaults to false - /// - operationIdentifier: [Optional] The operation identifier to use, defaults to nil - /// - autoPersistQuery: Whether the query should be auto-persisted, defaults to false. - /// - Returns: The body for the given request, ready to be added as the `httpBody`. - static func requestBody(for operationDocument: String, - variables: [String: Any]?, - operationName: String, - sendQueryDocument: Bool = true, - sendOperationIdentifiers: Bool = false, - operationIdentifier: String? = nil, - autoPersistQuery: Bool = false) -> [String: Any?] { - - var body: [String: Any?] = [ - "variables": variables, - "operationName": operationName, - ] - - if sendOperationIdentifiers { - guard let operationIdentifier = operationIdentifier else { - preconditionFailure("To send operation identifiers, Apollo types must be generated with operationIdentifiers") - } - - body["id"] = operationIdentifier - } - - if sendQueryDocument { - body["query"] = operationDocument - } - - if autoPersistQuery { - guard let operationIdentifier = operationIdentifier else { - preconditionFailure("To enable `autoPersistQueries`, Apollo types must be generated with operationIdentifiers") - } - - body["extensions"] = [ - "persistedQuery" : ["sha256Hash": operationIdentifier, "version": 1] - ] - } - - return body - } -} diff --git a/Sources/ApolloCodegenTestSupport/ApolloCodegenTestSupport.h b/Sources/ApolloCodegenTestSupport/ApolloCodegenTestSupport.h deleted file mode 100644 index 5856f2b0ab..0000000000 --- a/Sources/ApolloCodegenTestSupport/ApolloCodegenTestSupport.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ApolloCodegenTestSupport.h -// ApolloCodegenTestSupport -// -// Created by Anthony Miller on 4/20/21. -// Copyright © 2021 Apollo GraphQL. All rights reserved. -// - -#import - -//! Project version number for ApolloCodegenTestSupport. -FOUNDATION_EXPORT double ApolloCodegenTestSupportVersionNumber; - -//! Project version string for ApolloCodegenTestSupport. -FOUNDATION_EXPORT const unsigned char ApolloCodegenTestSupportVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Sources/ApolloCodegenTestSupport/CodegenTestHelper.swift b/Sources/ApolloCodegenTestSupport/CodegenTestHelper.swift deleted file mode 100644 index 2247705fef..0000000000 --- a/Sources/ApolloCodegenTestSupport/CodegenTestHelper.swift +++ /dev/null @@ -1,152 +0,0 @@ -// -// CodegenTestHelper.swift -// ApolloCodegenTests -// -// Created by Ellen Shapiro on 10/7/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import XCTest -@testable import ApolloCodegenLib - -public struct CodegenTestHelper { - - public static func dummyOptions() -> ApolloCodegenOptions { - let unusedURL = CodegenTestHelper.apolloFolderURL() - return ApolloCodegenOptions(outputFormat: .singleFile(atFileURL: unusedURL), - urlToSchemaFile: unusedURL) - } - - public static func dummyOptionsNoModifier() -> ApolloCodegenOptions { - let unusedURL = CodegenTestHelper.apolloFolderURL() - return ApolloCodegenOptions(modifier: .none, - outputFormat: .singleFile(atFileURL: unusedURL), - urlToSchemaFile: unusedURL) - } - - public static func handleFileLoadError(_ error: Error, - file: StaticString = #filePath, - line: UInt = #line) { - let nsError = error as NSError - if let underlying = nsError.userInfo["NSUnderlyingError"] as? NSError, - underlying.domain == NSPOSIXErrorDomain, - underlying.code == 4 { // The filesystem can't open the file, which for some reason is only happening on my laptop. - // Ellen's computer has lost its mind and intermittently won't load files - // from the file system with inexplicable process interrupted errors - // This is not technically a failure but we shouldn't fail the test on it. - // TODO: Mark test as skipped in Xcode 11.4 - print("🐶☕️🔥 This is fine") - } else { - // There was an actual problem. - XCTFail("Unexpected error loading file: \(error)", - file: file, - line: line) - } - } - - // Centralized timeout for adjustment when working on terrible wifi - public static var timeout: Double = 90.0 - - public static func sourceRootURL() -> URL { - FileFinder.findParentFolder() - .deletingLastPathComponent() // Tests - .deletingLastPathComponent() // apollo-ios - } - - public static func cliFolderURL() -> URL { - self.sourceRootURL() - .appendingPathComponent("Tests") - .appendingPathComponent("ApolloCodegenTests") - .appendingPathComponent("scripts directory") - } - - public static func apolloFolderURL() -> URL { - let scripts = self.cliFolderURL() - return ApolloFilePathHelper.apolloFolderURL(fromCLIFolder: scripts) - } - - public static func binaryFolderURL() -> URL { - let apollo = self.apolloFolderURL() - return ApolloFilePathHelper.binaryFolderURL(fromApollo: apollo) - } - - public static func shasumFileURL() -> URL { - let apollo = self.apolloFolderURL() - return ApolloFilePathHelper.shasumFileURL(fromApollo: apollo) - } - - public static func starWarsFolderURL() -> URL { - let source = self.sourceRootURL() - return source - .appendingPathComponent("Sources") - .appendingPathComponent("StarWarsAPI") - } - - public static func starWarsSchemaFileURL() -> URL { - let starWars = self.starWarsFolderURL() - return starWars - .appendingPathComponent("graphql") - .appendingPathComponent("schema.json") - } - - public static func outputFolderURL() -> URL { - let sourceRoot = self.sourceRootURL() - return sourceRoot - .appendingPathComponent("Tests") - .appendingPathComponent("ApolloCodegenTests") - .appendingPathComponent("Output") - } - - public static func schemaFolderURL() -> URL { - let sourceRoot = self.sourceRootURL() - return sourceRoot - .appendingPathComponent("Tests") - .appendingPathComponent("ApolloCodegenTests") - .appendingPathComponent("Schema") - } - - public static func deleteExistingOutputFolder(file: StaticString = #filePath, - line: UInt = #line) { - do { - let outputFolderURL = self.outputFolderURL() - try FileManager.default.apollo.deleteFolder(at: outputFolderURL) - } catch { - XCTFail("Error deleting output folder!", - file: file, - line: line) - } - } - - public static func downloadCLIIfNeeded(file: StaticString = #filePath, - line: UInt = #line) { - do { - let cliFolderURL = self.cliFolderURL() - try CLIDownloader.downloadIfNeeded(to: cliFolderURL, timeout: CodegenTestHelper.timeout) - } catch { - XCTFail("Error downloading CLI if needed: \(error)", - file: file, - line: line) - } - } - - public static func deleteExistingApolloFolder(file: StaticString = #filePath, - line: UInt = #line) { - do { - let apolloFolderURL = self.apolloFolderURL() - try FileManager.default.apollo.deleteFolder(at: apolloFolderURL) - } catch { - XCTFail("Error deleting Apollo folder: \(error)", - file: file, - line: line) - } - } - - public static func writeSHASUMOnly(_ shasum: String) throws { - let shasumFileURL = self.shasumFileURL() - let shasumParent = shasumFileURL.deletingLastPathComponent() - try FileManager.default.createDirectory(at: shasumParent, - withIntermediateDirectories: true) - FileManager.default.createFile(atPath: shasumFileURL.path, - contents: shasum.data(using: .utf8)) - } -} diff --git a/Sources/ApolloCodegenTestSupport/Info.plist b/Sources/ApolloCodegenTestSupport/Info.plist deleted file mode 100644 index 5791eec286..0000000000 --- a/Sources/ApolloCodegenTestSupport/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2021 Apollo GraphQL. All rights reserved. - - diff --git a/Sources/ApolloCodegenTestSupport/MockNetworkSession.swift b/Sources/ApolloCodegenTestSupport/MockNetworkSession.swift deleted file mode 100644 index bb9fb48b36..0000000000 --- a/Sources/ApolloCodegenTestSupport/MockNetworkSession.swift +++ /dev/null @@ -1,24 +0,0 @@ -@testable import ApolloCodegenLib - -public final class MockNetworkSession: NetworkSession { - let statusCode: Int - let data: Data? - let error: Error? - let abandon: Bool - - public init(statusCode: Int, data: Data? = nil, error: Error? = nil, abandon: Bool = false) { - self.statusCode = statusCode - self.data = data - self.error = error - self.abandon = abandon - } - - public func loadData(with urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask? { - guard !abandon else { return nil } - - let response = HTTPURLResponse(url: urlRequest.url!, statusCode: statusCode, httpVersion: nil, headerFields: nil) - completionHandler(data, response, error) - - return nil - } -} diff --git a/Sources/Apollo/ApolloClient.swift b/Sources/ApolloPGATOUR/ApolloClient.swift similarity index 85% rename from Sources/Apollo/ApolloClient.swift rename to Sources/ApolloPGATOUR/ApolloClient.swift index d3c551d235..f2f0df7235 100644 --- a/Sources/Apollo/ApolloClient.swift +++ b/Sources/ApolloPGATOUR/ApolloClient.swift @@ -1,15 +1,18 @@ import Foundation import Dispatch +#if !COCOAPODS +import ApolloAPI +#endif /// A cache policy that specifies whether results should be fetched from the server or loaded from the local cache. -public enum CachePolicy { +public enum CachePolicy: Hashable { /// Return data from the cache if available, else fetch results from the server. case returnCacheDataElseFetch /// Always fetch results from the server. case fetchIgnoringCacheData /// Always fetch results from the server, and don't store these in the cache. case fetchIgnoringCacheCompletely - /// Return data from the cache if available, else return nil. + /// Return data from the cache if available, else return an error. case returnCacheDataDontFetch /// Return data from the cache if available, and always fetch results from the server. case returnCacheDataAndFetch @@ -22,16 +25,16 @@ public enum CachePolicy { /// /// - Parameters: /// - result: The result of a performed operation. Will have a `GraphQLResult` with any parsed data and any GraphQL errors on `success`, and an `Error` on `failure`. -public typealias GraphQLResultHandler = (Result, Error>) -> Void +public typealias GraphQLResultHandler = (Result, Error>) -> Void /// The `ApolloClient` class implements the core API for Apollo by conforming to `ApolloClientProtocol`. public class ApolloClient { let networkTransport: NetworkTransport - public let store: ApolloStore // <- conformance to ApolloClientProtocol + public let store: ApolloStore - public enum ApolloClientError: Error, LocalizedError { + public enum ApolloClientError: Error, LocalizedError, Hashable { case noUploadTransport public var errorDescription: String? { @@ -69,15 +72,6 @@ public class ApolloClient { extension ApolloClient: ApolloClientProtocol { - public var cacheKeyForObject: CacheKeyForObject? { - get { - return self.store.cacheKeyForObject - } - set { - self.store.cacheKeyForObject = newValue - } - } - public func clearCache(callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) { self.store.clearCache(callbackQueue: callbackQueue, completion: completion) @@ -86,11 +80,13 @@ extension ApolloClient: ApolloClientProtocol { @discardableResult public func fetch(query: Query, cachePolicy: CachePolicy = .default, contextIdentifier: UUID? = nil, + context: RequestContext? = nil, queue: DispatchQueue = .main, resultHandler: GraphQLResultHandler? = nil) -> Cancellable { return self.networkTransport.send(operation: query, cachePolicy: cachePolicy, contextIdentifier: contextIdentifier, + context: context, callbackQueue: queue) { result in resultHandler?(result) } @@ -98,10 +94,12 @@ extension ApolloClient: ApolloClientProtocol { public func watch(query: Query, cachePolicy: CachePolicy = .default, + context: RequestContext? = nil, callbackQueue: DispatchQueue = .main, resultHandler: @escaping GraphQLResultHandler) -> GraphQLQueryWatcher { let watcher = GraphQLQueryWatcher(client: self, query: query, + context: context, callbackQueue: callbackQueue, resultHandler: resultHandler) watcher.fetch(cachePolicy: cachePolicy) @@ -111,12 +109,15 @@ extension ApolloClient: ApolloClientProtocol { @discardableResult public func perform(mutation: Mutation, publishResultToStore: Bool = true, + contextIdentifier: UUID? = nil, + context: RequestContext? = nil, queue: DispatchQueue = .main, resultHandler: GraphQLResultHandler? = nil) -> Cancellable { return self.networkTransport.send( operation: mutation, cachePolicy: publishResultToStore ? .default : .fetchIgnoringCacheCompletely, - contextIdentifier: nil, + contextIdentifier: contextIdentifier, + context: context, callbackQueue: queue, completionHandler: { result in resultHandler?(result) @@ -127,6 +128,7 @@ extension ApolloClient: ApolloClientProtocol { @discardableResult public func upload(operation: Operation, files: [GraphQLFile], + context: RequestContext? = nil, queue: DispatchQueue = .main, resultHandler: GraphQLResultHandler? = nil) -> Cancellable { guard let uploadingTransport = self.networkTransport as? UploadingNetworkTransport else { @@ -139,18 +141,20 @@ extension ApolloClient: ApolloClientProtocol { return uploadingTransport.upload(operation: operation, files: files, + context: context, callbackQueue: queue) { result in resultHandler?(result) } } - @discardableResult public func subscribe(subscription: Subscription, + context: RequestContext? = nil, queue: DispatchQueue = .main, resultHandler: @escaping GraphQLResultHandler) -> Cancellable { return self.networkTransport.send(operation: subscription, cachePolicy: .default, contextIdentifier: nil, + context: context, callbackQueue: queue, completionHandler: resultHandler) } diff --git a/Sources/Apollo/ApolloClientProtocol.swift b/Sources/ApolloPGATOUR/ApolloClientProtocol.swift similarity index 61% rename from Sources/Apollo/ApolloClientProtocol.swift rename to Sources/ApolloPGATOUR/ApolloClientProtocol.swift index 706c4b5b4e..deb877ec3d 100644 --- a/Sources/Apollo/ApolloClientProtocol.swift +++ b/Sources/ApolloPGATOUR/ApolloClientProtocol.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// The `ApolloClientProtocol` provides the core API for Apollo. This API provides methods to fetch and watch queries, and to perform mutations. public protocol ApolloClientProtocol: AnyObject { @@ -6,9 +9,6 @@ public protocol ApolloClientProtocol: AnyObject { /// A store used as a local cache. var store: ApolloStore { get } - /// A function that returns a cache key for a particular result object. If it returns `nil`, a default cache key based on the field path will be used. - var cacheKeyForObject: CacheKeyForObject? { get set } - /// Clears the underlying cache. /// Be aware: In more complex setups, the same underlying cache can be used across multiple instances, so if you call this on one instance, it'll clear that cache across all instances which share that cache. /// @@ -24,11 +24,13 @@ public protocol ApolloClientProtocol: AnyObject { /// - cachePolicy: A cache policy that specifies when results should be fetched from the server and when data should be loaded from the local cache. /// - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. /// - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - resultHandler: [optional] A closure that is called when query results are available or when an error occurs. /// - Returns: An object that can be used to cancel an in progress fetch. func fetch(query: Query, cachePolicy: CachePolicy, contextIdentifier: UUID?, + context: RequestContext?, queue: DispatchQueue, resultHandler: GraphQLResultHandler?) -> Cancellable @@ -37,11 +39,13 @@ public protocol ApolloClientProtocol: AnyObject { /// - Parameters: /// - query: The query to fetch. /// - cachePolicy: A cache policy that specifies when results should be fetched from the server or from the local cache. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - callbackQueue: A dispatch queue on which the result handler will be called. Should default to the main queue. /// - resultHandler: [optional] A closure that is called when query results are available or when an error occurs. /// - Returns: A query watcher object that can be used to control the watching behavior. func watch(query: Query, cachePolicy: CachePolicy, + context: RequestContext?, callbackQueue: DispatchQueue, resultHandler: @escaping GraphQLResultHandler) -> GraphQLQueryWatcher @@ -50,11 +54,15 @@ public protocol ApolloClientProtocol: AnyObject { /// - Parameters: /// - mutation: The mutation to perform. /// - publishResultToStore: If `true`, this will publish the result returned from the operation to the cache store. Default is `true`. + /// - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. /// - resultHandler: An optional closure that is called when mutation results are available or when an error occurs. /// - Returns: An object that can be used to cancel an in progress mutation. func perform(mutation: Mutation, publishResultToStore: Bool, + contextIdentifier: UUID?, + context: RequestContext?, queue: DispatchQueue, resultHandler: GraphQLResultHandler?) -> Cancellable @@ -63,11 +71,13 @@ public protocol ApolloClientProtocol: AnyObject { /// - Parameters: /// - operation: The operation to send /// - files: An array of `GraphQLFile` objects to send. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. /// - completionHandler: The completion handler to execute when the request completes or errors. Note that an error will be returned If your `networkTransport` does not also conform to `UploadingNetworkTransport`. /// - Returns: An object that can be used to cancel an in progress request. func upload(operation: Operation, files: [GraphQLFile], + context: RequestContext?, queue: DispatchQueue, resultHandler: GraphQLResultHandler?) -> Cancellable @@ -75,11 +85,70 @@ public protocol ApolloClientProtocol: AnyObject { /// /// - Parameters: /// - subscription: The subscription to subscribe to. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - fetchHTTPMethod: The HTTP Method to be used. /// - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. /// - resultHandler: An optional closure that is called when mutation results are available or when an error occurs. /// - Returns: An object that can be used to cancel an in progress subscription. func subscribe(subscription: Subscription, + context: RequestContext?, queue: DispatchQueue, resultHandler: @escaping GraphQLResultHandler) -> Cancellable } + +// MARK: - Backwards Compatibilty Extension + +public extension ApolloClientProtocol { + + /// Fetches a query from the server or from the local cache, depending on the current contents of the cache and the specified cache policy. + /// + /// - Parameters: + /// - query: The query to fetch. + /// - cachePolicy: A cache policy that specifies when results should be fetched from the server and when data should be loaded from the local cache. + /// - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. + /// - resultHandler: [optional] A closure that is called when query results are available or when an error occurs. + /// - Returns: An object that can be used to cancel an in progress fetch. + func fetch( + query: Query, + cachePolicy: CachePolicy, + context: RequestContext?, + queue: DispatchQueue, + resultHandler: GraphQLResultHandler? + ) -> Cancellable { + self.fetch( + query: query, + cachePolicy: cachePolicy, + contextIdentifier: nil, + context: context, + queue: queue, + resultHandler: resultHandler + ) + } + + /// Performs a mutation by sending it to the server. + /// + /// - Parameters: + /// - mutation: The mutation to perform. + /// - publishResultToStore: If `true`, this will publish the result returned from the operation to the cache store. Default is `true`. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. + /// - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. + /// - resultHandler: An optional closure that is called when mutation results are available or when an error occurs. + /// - Returns: An object that can be used to cancel an in progress mutation. + func perform( + mutation: Mutation, + publishResultToStore: Bool, + context: RequestContext?, + queue: DispatchQueue, + resultHandler: GraphQLResultHandler? + ) -> Cancellable { + self.perform( + mutation: mutation, + publishResultToStore: publishResultToStore, + contextIdentifier: nil, + context: context, + queue: queue, + resultHandler: resultHandler + ) + } +} diff --git a/Sources/Apollo/ApolloErrorInterceptor.swift b/Sources/ApolloPGATOUR/ApolloErrorInterceptor.swift similarity index 96% rename from Sources/Apollo/ApolloErrorInterceptor.swift rename to Sources/ApolloPGATOUR/ApolloErrorInterceptor.swift index eee485b2a2..cb7cdc3644 100644 --- a/Sources/Apollo/ApolloErrorInterceptor.swift +++ b/Sources/ApolloPGATOUR/ApolloErrorInterceptor.swift @@ -1,4 +1,6 @@ -import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// An error interceptor called to allow further examination of error data when an error occurs in the chain. public protocol ApolloErrorInterceptor { diff --git a/Sources/Apollo/ApolloInterceptor.swift b/Sources/ApolloPGATOUR/ApolloInterceptor.swift similarity index 63% rename from Sources/Apollo/ApolloInterceptor.swift rename to Sources/ApolloPGATOUR/ApolloInterceptor.swift index b89c4b4da9..81b36c6762 100644 --- a/Sources/Apollo/ApolloInterceptor.swift +++ b/Sources/ApolloPGATOUR/ApolloInterceptor.swift @@ -1,5 +1,16 @@ +#if !COCOAPODS +import ApolloAPI +#endif + /// A protocol to set up a chainable unit of networking work. public protocol ApolloInterceptor { + + /// Used to uniquely identify this interceptor from other interceptors in a request chain. + /// + /// Each operation request has it's own interceptor request chain so the interceptors do not + /// need to be uniquely identifiable between each and every request, only unique between the + /// list of interceptors in a single request. + var id: String { get } /// Called when this interceptor should do its work. /// diff --git a/Sources/ApolloPGATOUR/ApolloStore.swift b/Sources/ApolloPGATOUR/ApolloStore.swift new file mode 100644 index 0000000000..a960b9c215 --- /dev/null +++ b/Sources/ApolloPGATOUR/ApolloStore.swift @@ -0,0 +1,375 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +public typealias DidChangeKeysFunc = (Set, UUID?) -> Void + +/// The `ApolloStoreSubscriber` provides a means to observe changes to items in the ApolloStore. +/// This protocol is available for advanced use cases only. Most users will prefer using `ApolloClient.watch(query:)`. +public protocol ApolloStoreSubscriber: AnyObject { + + /// A callback that can be received by subscribers when keys are changed within the database + /// + /// - Parameters: + /// - store: The store which made the changes + /// - changedKeys: The list of changed keys + /// - contextIdentifier: [optional] A unique identifier for the request that kicked off this change, to assist in de-duping cache hits for watchers. + func store(_ store: ApolloStore, + didChangeKeys changedKeys: Set, + contextIdentifier: UUID?) +} + +/// The `ApolloStore` class acts as a local cache for normalized GraphQL results. +public class ApolloStore { + private let cache: NormalizedCache + private let queue: DispatchQueue + + internal var subscribers: [ApolloStoreSubscriber] = [] + + /// Designated initializer + /// - Parameters: + /// - cache: An instance of `normalizedCache` to use to cache results. + /// Defaults to an `InMemoryNormalizedCache`. + public init(cache: NormalizedCache = InMemoryNormalizedCache()) { + self.cache = cache + self.queue = DispatchQueue(label: "com.apollographql.ApolloStore", attributes: .concurrent) + } + + fileprivate func didChangeKeys(_ changedKeys: Set, identifier: UUID?) { + for subscriber in self.subscribers { + subscriber.store(self, didChangeKeys: changedKeys, contextIdentifier: identifier) + } + } + + /// Clears the instance of the cache. Note that a cache can be shared across multiple `ApolloClient` objects, so clearing that underlying cache will clear it for all clients. + /// + /// - Parameters: + /// - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. + /// - completion: [optional] A completion block to be called after records are merged into the cache. + public func clearCache(callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) { + queue.async(flags: .barrier) { + let result = Result { try self.cache.clear() } + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: result + ) + } + } + + /// Merges a `RecordSet` into the normalized cache. + /// - Parameters: + /// - records: The records to be merged into the cache. + /// - identifier: [optional] A unique identifier for the request that kicked off this change, + /// to assist in de-duping cache hits for watchers. + /// - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. + /// - completion: [optional] A completion block to be called after records are merged into the cache. + public func publish(records: RecordSet, identifier: UUID? = nil, callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) { + queue.async(flags: .barrier) { + do { + let changedKeys = try self.cache.merge(records: records) + self.didChangeKeys(changedKeys, identifier: identifier) + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: .success(()) + ) + } catch { + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: .failure(error) + ) + } + } + } + + /// Subscribes to notifications of ApolloStore content changes + /// + /// - Parameters: + /// - subscriber: A subscriber to receive content change notificatons. To avoid a retain cycle, + /// ensure you call `unsubscribe` on this subscriber before it goes out of scope. + public func subscribe(_ subscriber: ApolloStoreSubscriber) { + queue.async(flags: .barrier) { + self.subscribers.append(subscriber) + } + } + + /// Unsubscribes from notifications of ApolloStore content changes + /// + /// - Parameters: + /// - subscriber: A subscribe that has previously been added via `subscribe`. To avoid retain cycles, + /// call `unsubscribe` on all active subscribers before they go out of scope. + public func unsubscribe(_ subscriber: ApolloStoreSubscriber) { + queue.async(flags: .barrier) { + self.subscribers = self.subscribers.filter({ $0 !== subscriber }) + } + } + + /// Performs an operation within a read transaction + /// + /// - Parameters: + /// - body: The body of the operation to perform. + /// - callbackQueue: [optional] The callback queue to use to perform the completion block on. Will perform on the current queue if not provided. Defaults to nil. + /// - completion: [optional] The completion block to perform when the read transaction completes. Defaults to nil. + public func withinReadTransaction( + _ body: @escaping (ReadTransaction) throws -> T, + callbackQueue: DispatchQueue? = nil, + completion: ((Result) -> Void)? = nil + ) { + self.queue.async { + do { + let returnValue = try body(ReadTransaction(store: self)) + + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: .success(returnValue) + ) + } catch { + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: .failure(error) + ) + } + } + } + + /// Performs an operation within a read-write transaction + /// + /// - Parameters: + /// - body: The body of the operation to perform + /// - callbackQueue: [optional] a callback queue to perform the action on. Will perform on the current queue if not provided. Defaults to nil. + /// - completion: [optional] a completion block to fire when the read-write transaction completes. Defaults to nil. + public func withinReadWriteTransaction( + _ body: @escaping (ReadWriteTransaction) throws -> T, + callbackQueue: DispatchQueue? = nil, + completion: ((Result) -> Void)? = nil + ) { + self.queue.async(flags: .barrier) { + do { + let returnValue = try body(ReadWriteTransaction(store: self)) + + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: .success(returnValue) + ) + } catch { + DispatchQueue.returnResultAsyncIfNeeded( + on: callbackQueue, + action: completion, + result: .failure(error) + ) + } + } + } + + /// Loads the results for the given query from the cache. + /// + /// - Parameters: + /// - query: The query to load results for + /// - resultHandler: The completion handler to execute on success or error + public func load( + _ operation: Operation, + callbackQueue: DispatchQueue? = nil, + resultHandler: @escaping GraphQLResultHandler + ) { + withinReadTransaction({ transaction in + let (data, dependentKeys) = try transaction.readObject( + ofType: Operation.Data.self, + withKey: CacheReference.rootCacheReference(for: Operation.operationType).key, + variables: operation.__variables, + accumulator: zip(GraphQLSelectionSetMapper(), + GraphQLDependencyTracker()) + ) + + return GraphQLResult( + data: data, + extensions: nil, + errors: nil, + source:.cache, + dependentKeys: dependentKeys + ) + }, callbackQueue: callbackQueue, completion: resultHandler) + } + + public enum Error: Swift.Error { + case notWithinReadTransaction + } + + public class ReadTransaction { + fileprivate let cache: NormalizedCache + + fileprivate lazy var loader: DataLoader = DataLoader(self.cache.loadRecords) + fileprivate lazy var executor = GraphQLExecutor( + executionSource: CacheDataExecutionSource(transaction: self) + ) + + fileprivate init(store: ApolloStore) { + self.cache = store.cache + } + + public func read(query: Query) throws -> Query.Data { + return try readObject( + ofType: Query.Data.self, + withKey: CacheReference.rootCacheReference(for: Query.operationType).key, + variables: query.__variables + ) + } + + public func readObject( + ofType type: SelectionSet.Type, + withKey key: CacheKey, + variables: GraphQLOperation.Variables? = nil + ) throws -> SelectionSet { + return try self.readObject( + ofType: type, + withKey: key, + variables: variables, + accumulator: GraphQLSelectionSetMapper() + ) + } + + func readObject( + ofType type: SelectionSet.Type, + withKey key: CacheKey, + variables: GraphQLOperation.Variables? = nil, + accumulator: Accumulator + ) throws -> Accumulator.FinalResult { + let object = try loadObject(forKey: key).get() + + return try executor.execute( + selectionSet: type, + on: object, + withRootCacheReference: CacheReference(key), + variables: variables, + accumulator: accumulator + ) + } + + final func loadObject(forKey key: CacheKey) -> PossiblyDeferred { + self.loader[key].map { record in + guard let record = record else { throw JSONDecodingError.missingValue } + return record + } + } + } + + public final class ReadWriteTransaction: ReadTransaction { + + fileprivate var updateChangedKeysFunc: DidChangeKeysFunc? + + override init(store: ApolloStore) { + self.updateChangedKeysFunc = store.didChangeKeys + super.init(store: store) + } + + public func update( + _ cacheMutation: CacheMutation, + _ body: (inout CacheMutation.Data) throws -> Void + ) throws { + try updateObject( + ofType: CacheMutation.Data.self, + withKey: CacheReference.rootCacheReference(for: CacheMutation.operationType).key, + variables: cacheMutation.__variables, + body + ) + } + + public func updateObject( + ofType type: SelectionSet.Type, + withKey key: CacheKey, + variables: GraphQLOperation.Variables? = nil, + _ body: (inout SelectionSet) throws -> Void + ) throws { + var object = try readObject( + ofType: type, + withKey: key, + variables: variables, + accumulator: GraphQLSelectionSetMapper( + handleMissingValues: .allowForOptionalFields + ) + ) + + try body(&object) + try write(selectionSet: object, withKey: key, variables: variables) + } + + public func write( + data: CacheMutation.Data, + for cacheMutation: CacheMutation + ) throws { + try write(selectionSet: data, + withKey: CacheReference.rootCacheReference(for: CacheMutation.operationType).key, + variables: cacheMutation.__variables) + } + + public func write( + data: Operation.Data, + for operation: Operation + ) throws { + try write(selectionSet: data, + withKey: CacheReference.rootCacheReference(for: Operation.operationType).key, + variables: operation.__variables) + } + + public func write( + selectionSet: SelectionSet, + withKey key: CacheKey, + variables: GraphQLOperation.Variables? = nil + ) throws { + let normalizer = ResultNormalizerFactory.selectionSetDataNormalizer() + + let executor = GraphQLExecutor(executionSource: SelectionSetModelExecutionSource()) + + let records = try executor.execute( + selectionSet: SelectionSet.self, + on: selectionSet.__data, + withRootCacheReference: CacheReference(key), + variables: variables, + accumulator: normalizer + ) + + let changedKeys = try self.cache.merge(records: records) + + // Remove cached records, so subsequent reads + // within the same transaction will reload the updated value. + loader.removeAll() + + if let didChangeKeysFunc = self.updateChangedKeysFunc { + didChangeKeysFunc(changedKeys, nil) + } + } + + /// Removes the object for the specified cache key. Does not cascade + /// or allow removal of only certain fields. Does nothing if an object + /// does not exist for the given key. + /// + /// - Parameters: + /// - key: The cache key to remove the object for + public func removeObject(for key: CacheKey) throws { + try self.cache.removeRecord(for: key) + } + + /// Removes records with keys that match the specified pattern. This method will only + /// remove whole records, it does not perform cascading deletes. This means only the + /// records with matched keys will be removed, and not any references to them. Key + /// matching is case-insensitive. + /// + /// If you attempt to pass a cache path for a single field, this method will do nothing + /// since it won't be able to locate a record to remove based on that path. + /// + /// - Note: This method can be very slow depending on the number of records in the cache. + /// It is recommended that this method be called in a background queue. + /// + /// - Parameters: + /// - pattern: The pattern that will be applied to find matching keys. + public func removeObjects(matching pattern: CacheKey) throws { + try self.cache.removeRecords(matching: pattern) + } + + } +} diff --git a/Sources/ApolloPGATOUR/Atomic.swift b/Sources/ApolloPGATOUR/Atomic.swift new file mode 100644 index 0000000000..1d3c419b54 --- /dev/null +++ b/Sources/ApolloPGATOUR/Atomic.swift @@ -0,0 +1,53 @@ +import Foundation + +/// Wrapper for a value protected by an `NSLock` +@propertyWrapper +public class Atomic { + private let lock = NSLock() + private var _value: T + + /// Designated initializer + /// + /// - Parameter value: The value to begin with. + public init(wrappedValue: T) { + _value = wrappedValue + } + + /// The current value. Read-only. To update the underlying value, use ``mutate(block:)``. + /// + /// Allowing the ``wrappedValue`` to be set using a setter can cause concurrency issues when + /// mutating the value of a wrapped value type such as an `Array`. This is due to the copying of + /// value types as described in [this article](https://www.donnywals.com/why-your-atomic-property-wrapper-doesnt-work-for-collection-types/). + public var wrappedValue: T { + get { + lock.lock() + defer { lock.unlock() } + return _value + } + } + + public var projectedValue: Atomic { self } + + /// Mutates the underlying value within a lock. + /// + /// - Parameter block: The block executed to mutate the value. + /// - Returns: The value returned by the block. + public func mutate(block: (inout T) -> U) -> U { + lock.lock() + defer { lock.unlock() } + return block(&_value) + } +} + +public extension Atomic where T : Numeric { + + /// Increments the wrapped `Int` atomically, adding +1 to the value. + @discardableResult + func increment() -> T { + lock.lock() + defer { lock.unlock() } + + _value += 1 + return _value + } +} diff --git a/Sources/ApolloPGATOUR/AutomaticPersistedQueryInterceptor.swift b/Sources/ApolloPGATOUR/AutomaticPersistedQueryInterceptor.swift new file mode 100644 index 0000000000..d42bd72bd2 --- /dev/null +++ b/Sources/ApolloPGATOUR/AutomaticPersistedQueryInterceptor.swift @@ -0,0 +1,111 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +public struct AutomaticPersistedQueryInterceptor: ApolloInterceptor { + + public enum APQError: LocalizedError, Equatable { + case noParsedResponse + case persistedQueryNotFoundForPersistedOnlyQuery(operationName: String) + case persistedQueryRetryFailed(operationName: String) + + public var errorDescription: String? { + switch self { + case .noParsedResponse: + return "The Automatic Persisted Query Interceptor was called before a response was received. Double-check the order of your interceptors." + case .persistedQueryRetryFailed(let operationName): + return "Persisted query retry failed for operation \"\(operationName)\"." + + case .persistedQueryNotFoundForPersistedOnlyQuery(let operationName): + return "The Persisted Query for operation \"\(operationName)\" was not found. The operation is a `.persistedOnly` operation and cannot be automatically persisted if it is not recognized by the server." + + } + } + } + + public var id: String = UUID().uuidString + + /// Designated initializer + public init() {} + + public func interceptAsync( + chain: RequestChain, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void) { + + guard let jsonRequest = request as? JSONRequest, + jsonRequest.autoPersistQueries else { + // Not a request that handles APQs, continue along + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + return + } + + guard let result = response?.parsedResponse else { + // This is in the wrong order - this needs to be parsed before we can check it. + chain.handleErrorAsync( + APQError.noParsedResponse, + request: request, + response: response, + completion: completion + ) + return + } + + guard let errors = result.errors else { + // No errors were returned so no retry is necessary, continue along. + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + return + } + + let errorMessages = errors.compactMap { $0.message } + guard errorMessages.contains("PersistedQueryNotFound") else { + // The errors were not APQ errors, continue along. + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + return + } + + guard !jsonRequest.isPersistedQueryRetry else { + // We already retried this and it didn't work. + chain.handleErrorAsync( + APQError.persistedQueryRetryFailed(operationName: Operation.operationName), + request: jsonRequest, + response: response, + completion: completion + ) + + return + } + + if Operation.operationDocument.definition == nil { + chain.handleErrorAsync( + APQError.persistedQueryNotFoundForPersistedOnlyQuery(operationName: Operation.operationName), + request: jsonRequest, + response: response, + completion: completion + ) + + return + } + + // We need to retry this query with the full body. + jsonRequest.isPersistedQueryRetry = true + chain.retry(request: jsonRequest, completion: completion) + } +} diff --git a/Sources/Apollo/Bundle+Helpers.swift b/Sources/ApolloPGATOUR/Bundle+Helpers.swift similarity index 77% rename from Sources/Apollo/Bundle+Helpers.swift rename to Sources/ApolloPGATOUR/Bundle+Helpers.swift index 5e280a8979..c8d86f8b97 100644 --- a/Sources/Apollo/Bundle+Helpers.swift +++ b/Sources/ApolloPGATOUR/Bundle+Helpers.swift @@ -1,18 +1,13 @@ import Foundation -#if !COCOAPODS -import ApolloUtils -#endif -extension Bundle: ApolloCompatible {} - -extension ApolloExtension where Base == Bundle { +extension Bundle { /// Type-safe getter for info dictionary key objects /// /// - Parameter key: The key to try to grab an object for /// - Returns: The object of the desired type, or nil if it is not present or of the incorrect type. - func bundleValue(forKey key: String) -> T? { - return base.object(forInfoDictionaryKey: key) as? T + private func bundleValue(forKey key: String) -> T? { + return object(forInfoDictionaryKey: key) as? T } /// The bundle identifier of this bundle, or nil if not present. diff --git a/Sources/ApolloPGATOUR/CacheReadInterceptor.swift b/Sources/ApolloPGATOUR/CacheReadInterceptor.swift new file mode 100644 index 0000000000..111a1df455 --- /dev/null +++ b/Sources/ApolloPGATOUR/CacheReadInterceptor.swift @@ -0,0 +1,129 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +/// An interceptor that reads data from the cache for queries, following the `HTTPRequest`'s `cachePolicy`. +public struct CacheReadInterceptor: ApolloInterceptor { + + private let store: ApolloStore + + public var id: String = UUID().uuidString + + /// Designated initializer + /// + /// - Parameter store: The store to use when reading from the cache. + public init(store: ApolloStore) { + self.store = store + } + + public func interceptAsync( + chain: RequestChain, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void) { + + switch Operation.operationType { + case .mutation, + .subscription: + // Mutations and subscriptions don't need to hit the cache. + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + + case .query: + switch request.cachePolicy { + case .fetchIgnoringCacheCompletely, + .fetchIgnoringCacheData: + // Don't bother with the cache, just keep going + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + + case .returnCacheDataAndFetch: + self.fetchFromCache(for: request, chain: chain) { cacheFetchResult in + switch cacheFetchResult { + case .failure: + // Don't return a cache miss error, just keep going + break + case .success(let graphQLResult): + chain.returnValueAsync( + for: request, + value: graphQLResult, + completion: completion + ) + } + + // In either case, keep going asynchronously + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + } + case .returnCacheDataElseFetch: + self.fetchFromCache(for: request, chain: chain) { cacheFetchResult in + switch cacheFetchResult { + case .failure: + // Cache miss, proceed to network without returning error + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + + case .success(let graphQLResult): + // Cache hit! We're done. + chain.returnValueAsync( + for: request, + value: graphQLResult, + completion: completion + ) + } + } + case .returnCacheDataDontFetch: + self.fetchFromCache(for: request, chain: chain) { cacheFetchResult in + switch cacheFetchResult { + case .failure(let error): + // Cache miss - don't hit the network, just return the error. + chain.handleErrorAsync( + error, + request: request, + response: response, + completion: completion + ) + + case .success(let result): + chain.returnValueAsync( + for: request, + value: result, + completion: completion + ) + } + } + } + } + } + + private func fetchFromCache( + for request: HTTPRequest, + chain: RequestChain, + completion: @escaping (Result, Error>) -> Void) { + + self.store.load(request.operation) { loadResult in + guard !chain.isCancelled else { + return + } + + completion(loadResult) + } + } +} diff --git a/Sources/Apollo/CacheWriteInterceptor.swift b/Sources/ApolloPGATOUR/CacheWriteInterceptor.swift similarity index 64% rename from Sources/Apollo/CacheWriteInterceptor.swift rename to Sources/ApolloPGATOUR/CacheWriteInterceptor.swift index cb101ead72..350e8845b1 100644 --- a/Sources/Apollo/CacheWriteInterceptor.swift +++ b/Sources/ApolloPGATOUR/CacheWriteInterceptor.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// An interceptor which writes data to the cache, following the `HTTPRequest`'s `cachePolicy`. public struct CacheWriteInterceptor: ApolloInterceptor { @@ -15,6 +18,7 @@ public struct CacheWriteInterceptor: ApolloInterceptor { } public let store: ApolloStore + public var id: String = UUID().uuidString /// Designated initializer /// @@ -31,26 +35,31 @@ public struct CacheWriteInterceptor: ApolloInterceptor { guard request.cachePolicy != .fetchIgnoringCacheCompletely else { // If we're ignoring the cache completely, we're not writing to it. - chain.proceedAsync(request: request, - response: response, - completion: completion) + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) return } guard let createdResponse = response, let legacyResponse = createdResponse.legacyResponse else { - chain.handleErrorAsync(CacheWriteError.noResponseToParse, - request: request, - response: response, - completion: completion) + chain.handleErrorAsync( + CacheWriteError.noResponseToParse, + request: request, + response: response, + completion: completion + ) return } do { - let (_, records) = try legacyResponse.parseResult(cacheKeyForObject: self.store.cacheKeyForObject) + let (_, records) = try legacyResponse.parseResult() - guard chain.isNotCancelled else { + guard !chain.isCancelled else { return } @@ -58,14 +67,20 @@ public struct CacheWriteInterceptor: ApolloInterceptor { self.store.publish(records: records, identifier: request.contextIdentifier) } - chain.proceedAsync(request: request, - response: createdResponse, - completion: completion) + chain.proceedAsync( + request: request, + response: createdResponse, + interceptor: self, + completion: completion + ) + } catch { - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) + chain.handleErrorAsync( + error, + request: request, + response: response, + completion: completion + ) } } } diff --git a/Sources/Apollo/Cancellable.swift b/Sources/ApolloPGATOUR/Cancellable.swift similarity index 100% rename from Sources/Apollo/Cancellable.swift rename to Sources/ApolloPGATOUR/Cancellable.swift diff --git a/Sources/ApolloPGATOUR/Collection+Helpers.swift b/Sources/ApolloPGATOUR/Collection+Helpers.swift new file mode 100644 index 0000000000..b1f8f2b0e0 --- /dev/null +++ b/Sources/ApolloPGATOUR/Collection+Helpers.swift @@ -0,0 +1,28 @@ +// MARK: - Unzipping +// MARK: Arrays of tuples to tuples of arrays + +public func unzip(_ array: [(Element1?, Element2?)]) -> ([Element1], [Element2]) { + var array1: [Element1] = [] + var array2: [Element2] = [] + + for elements in array { + if let element1 = elements.0 { array1.append(element1) } + if let element2 = elements.1 { array2.append(element2) } + } + + return (array1, array2) +} + +public func unzip(_ array: [(Element1?, Element2?, Element3?)]) -> ([Element1], [Element2], [Element3]) { + var array1: [Element1] = [] + var array2: [Element2] = [] + var array3: [Element3] = [] + + for elements in array { + if let element1 = elements.0 { array1.append(element1) } + if let element2 = elements.1 { array2.append(element2) } + if let element3 = elements.2 { array3.append(element3) } + } + + return (array1, array2, array3) +} diff --git a/Sources/ApolloPGATOUR/Constants.swift b/Sources/ApolloPGATOUR/Constants.swift new file mode 100644 index 0000000000..c46655cb91 --- /dev/null +++ b/Sources/ApolloPGATOUR/Constants.swift @@ -0,0 +1,5 @@ +import Foundation + +public enum Constants { + public static let ApolloVersion: String = "1.9.3" +} diff --git a/Sources/Apollo/DataLoader.swift b/Sources/ApolloPGATOUR/DataLoader.swift similarity index 98% rename from Sources/Apollo/DataLoader.swift rename to Sources/ApolloPGATOUR/DataLoader.swift index 7992d06ba8..fa959c22fe 100644 --- a/Sources/Apollo/DataLoader.swift +++ b/Sources/ApolloPGATOUR/DataLoader.swift @@ -1,5 +1,3 @@ -import Foundation - final class DataLoader { public typealias BatchLoad = (Set) throws -> [Key: Value] private var batchLoad: BatchLoad diff --git a/Sources/Apollo/DefaultInterceptorProvider.swift b/Sources/ApolloPGATOUR/DefaultInterceptorProvider.swift similarity index 87% rename from Sources/Apollo/DefaultInterceptorProvider.swift rename to Sources/ApolloPGATOUR/DefaultInterceptorProvider.swift index 1392b93a85..bef366f9a8 100644 --- a/Sources/Apollo/DefaultInterceptorProvider.swift +++ b/Sources/ApolloPGATOUR/DefaultInterceptorProvider.swift @@ -1,4 +1,6 @@ -import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// The default interceptor provider for typescript-generated code open class DefaultInterceptorProvider: InterceptorProvider { @@ -27,13 +29,16 @@ open class DefaultInterceptorProvider: InterceptorProvider { } } - open func interceptors(for operation: Operation) -> [ApolloInterceptor] { + open func interceptors( + for operation: Operation + ) -> [any ApolloInterceptor] { return [ MaxRetryInterceptor(), CacheReadInterceptor(store: self.store), NetworkFetchInterceptor(client: self.client), ResponseCodeInterceptor(), - JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject), + MultipartResponseParsingInterceptor(), + JSONResponseParsingInterceptor(), AutomaticPersistedQueryInterceptor(), CacheWriteInterceptor(store: self.store), ] diff --git a/Sources/Apollo/Dictionary+Helpers.swift b/Sources/ApolloPGATOUR/Dictionary+Helpers.swift similarity index 100% rename from Sources/Apollo/Dictionary+Helpers.swift rename to Sources/ApolloPGATOUR/Dictionary+Helpers.swift diff --git a/Sources/Apollo/DispatchQueue+Optional.swift b/Sources/ApolloPGATOUR/DispatchQueue+Optional.swift similarity index 69% rename from Sources/Apollo/DispatchQueue+Optional.swift rename to Sources/ApolloPGATOUR/DispatchQueue+Optional.swift index 4de2e46672..4836b81f86 100644 --- a/Sources/Apollo/DispatchQueue+Optional.swift +++ b/Sources/ApolloPGATOUR/DispatchQueue+Optional.swift @@ -1,11 +1,6 @@ -import Foundation -#if !COCOAPODS -import ApolloUtils -#endif +import Dispatch -extension DispatchQueue: ApolloCompatible {} - -public extension ApolloExtension where Base == DispatchQueue { +extension DispatchQueue { static func performAsyncIfNeeded(on callbackQueue: DispatchQueue?, action: @escaping () -> Void) { if let callbackQueue = callbackQueue { @@ -20,8 +15,8 @@ public extension ApolloExtension where Base == DispatchQueue { } static func returnResultAsyncIfNeeded(on callbackQueue: DispatchQueue?, - action: ((Result) -> Void)?, - result: Result) { + action: ((Result) -> Void)?, + result: Result) { if let action = action { self.performAsyncIfNeeded(on: callbackQueue) { action(result) diff --git a/Sources/ApolloPGATOUR/Documentation.docc/Documentation.md b/Sources/ApolloPGATOUR/Documentation.docc/Documentation.md new file mode 100644 index 0000000000..6d8821fdb0 --- /dev/null +++ b/Sources/ApolloPGATOUR/Documentation.docc/Documentation.md @@ -0,0 +1,7 @@ +# ``Apollo`` + +A Strongly typed, Swift-first, GraphQL client. + +## Overview + +The core Apollo client library. This library includes the networking client, normalized cache, and GraphQL executor. diff --git a/Sources/ApolloPGATOUR/Documentation.docc/Index.md b/Sources/ApolloPGATOUR/Documentation.docc/Index.md new file mode 100644 index 0000000000..47be210880 --- /dev/null +++ b/Sources/ApolloPGATOUR/Documentation.docc/Index.md @@ -0,0 +1,45 @@ +# Apollo iOS + +@Metadata { + @TechnologyRoot +} + +API Reference Documentation for Apollo iOS. + +## Overview + +Our API reference is automatically generated directly from the inline comments in our code. If you're contributing to Apollo, all you have to do is add inline documentation comments, conforming to [DocC formatting guidelines](https://developer.apple.com/documentation/xcode/writing-symbol-documentation-in-your-source-files), and they will appear here. + +See something missing in the documentation? Add inline documentation comments to the code, and open a pull request! + +To run the documentation generator, cd into the SwiftScripts folder and run + +```bash +swift run DocumentationGenerator +``` + +## Libraries + +**[Apollo](/documentation/apollo)** + +The core Apollo client library. + +**[ApolloAPI](/documentation/apolloapi)** + +The internal models shared by the [``Apollo``](/documentation/apollo) client and the models generated by [``ApolloCodegenLib``](/documentation/apollocodegenlib) + +**[ApolloCodegenLib](/documentation/apollocodegenlib)** + +The code generation engine used to generate model objects for an application from a GraphQL schema and operation set. + +**[ApolloSQLite](/documentation/apollosqlite)** + +A [`NormalizedCache`](/documentation/apollo/normalizedcache) implementation backed by a `SQLite` database. + +**[ApolloWebSocket](/documentation/apollowebsocket)** + +A web socket network transport implementation that provides support for [`GraphQLSubscription`](/documentation/apolloapi/graphqlsubscription) operations over a web socket connection. + +**[ApolloPagination](/documentation/apollopagination)** + +A library that provides support for fetching and watching paginated queries with [``Apollo``](/documentation/apollo). diff --git a/Sources/ApolloPGATOUR/ExecutionSources/CacheDataExecutionSource.swift b/Sources/ApolloPGATOUR/ExecutionSources/CacheDataExecutionSource.swift new file mode 100644 index 0000000000..9aa665e53a --- /dev/null +++ b/Sources/ApolloPGATOUR/ExecutionSources/CacheDataExecutionSource.swift @@ -0,0 +1,90 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// A `GraphQLExecutionSource` configured to execute upon the data stored in a ``NormalizedCache``. +/// +/// Each object exposed by the cache is represented as a `Record`. +struct CacheDataExecutionSource: GraphQLExecutionSource { + typealias RawObjectData = Record + typealias FieldCollector = CacheDataFieldSelectionCollector + + /// A `weak` reference to the transaction the cache data is being read from during execution. + /// This transaction is used to resolve references to other objects in the cache during field + /// value resolution. + /// + /// This property is `weak` to ensure there is not a retain cycle between the transaction and the + /// execution pipeline. If the transaction has been deallocated, execution cannot continue + /// against the cache data. + weak var transaction: ApolloStore.ReadTransaction? + + init(transaction: ApolloStore.ReadTransaction) { + self.transaction = transaction + } + + func resolveField( + with info: FieldExecutionInfo, + on object: Record + ) -> PossiblyDeferred { + PossiblyDeferred { + let value = try object[info.cacheKeyForField()] + + switch value { + case let reference as CacheReference: + return deferredResolve(reference: reference).map { $0 as AnyHashable } + + case let referenceList as [CacheReference]: + return referenceList + .enumerated() + .deferredFlatMap { index, element in + self.deferredResolve(reference: element) + .mapError { error in + if !(error is GraphQLExecutionError) { + return GraphQLExecutionError( + path: info.responsePath.appending(String(index)), + underlying: error + ) + } else { + return error + } + } + }.map { $0._asAnyHashable } + + default: + return .immediate(.success(value)) + } + } + } + + private func deferredResolve(reference: CacheReference) -> PossiblyDeferred { + guard let transaction else { + return .immediate(.failure(ApolloStore.Error.notWithinReadTransaction)) + } + + return transaction.loadObject(forKey: reference.key) + } + + func computeCacheKey(for object: Record, in schema: SchemaMetadata.Type) -> CacheKey? { + return object.key + } + + /// A wrapper around the `DefaultFieldSelectionCollector` that maps the `Record` object to it's + /// `fields` representing the object's data. + struct CacheDataFieldSelectionCollector: FieldSelectionCollector { + static func collectFields( + from selections: [Selection], + into groupedFields: inout FieldSelectionGrouping, + for object: Record, + info: ObjectExecutionInfo + ) throws { + return try DefaultFieldSelectionCollector.collectFields( + from: selections, + into: &groupedFields, + for: object.fields, + info: info + ) + } + } +} + + diff --git a/Sources/ApolloPGATOUR/ExecutionSources/NetworkResponseExecutionSource.swift b/Sources/ApolloPGATOUR/ExecutionSources/NetworkResponseExecutionSource.swift new file mode 100644 index 0000000000..d2154bbb33 --- /dev/null +++ b/Sources/ApolloPGATOUR/ExecutionSources/NetworkResponseExecutionSource.swift @@ -0,0 +1,49 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// A `GraphQLExecutionSource` configured to execute upon the JSON data from the network response +/// for a GraphQL operation. +struct NetworkResponseExecutionSource: GraphQLExecutionSource, CacheKeyComputingExecutionSource { + typealias RawObjectData = JSONObject + typealias FieldCollector = DefaultFieldSelectionCollector + + func resolveField( + with info: FieldExecutionInfo, + on object: JSONObject + ) -> PossiblyDeferred { + .immediate(.success(object[info.responseKeyForField])) + } + + func opaqueObjectDataWrapper(for rawData: JSONObject) -> ObjectData { + ObjectData(_transformer: DataTransformer(), _rawData: rawData) + } + + struct DataTransformer: _ObjectData_Transformer { + func transform(_ value: AnyHashable) -> (any ScalarType)? { + switch value { + case let scalar as ScalarType: + return scalar + case let customScalar as CustomScalarType: + return customScalar._jsonValue as? ScalarType + default: return nil + } + } + + func transform(_ value: AnyHashable) -> ObjectData? { + switch value { + case let object as JSONObject: + return ObjectData(_transformer: self, _rawData: object) + default: return nil + } + } + + func transform(_ value: AnyHashable) -> ListData? { + switch value { + case let list as [AnyHashable]: + return ListData(_transformer: self, _rawData: list) + default: return nil + } + } + } +} diff --git a/Sources/ApolloPGATOUR/ExecutionSources/SelectionSetModelExecutionSource.swift b/Sources/ApolloPGATOUR/ExecutionSources/SelectionSetModelExecutionSource.swift new file mode 100644 index 0000000000..6a72f4e882 --- /dev/null +++ b/Sources/ApolloPGATOUR/ExecutionSources/SelectionSetModelExecutionSource.swift @@ -0,0 +1,49 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// A `GraphQLExecutionSource` designed for use when the data source is a generated model's +/// `SelectionSet` data. +struct SelectionSetModelExecutionSource: GraphQLExecutionSource, CacheKeyComputingExecutionSource { + typealias RawObjectData = DataDict + typealias FieldCollector = CustomCacheDataWritingFieldSelectionCollector + + func resolveField( + with info: FieldExecutionInfo, + on object: DataDict + ) -> PossiblyDeferred { + .immediate(.success(object._data[info.responseKeyForField])) + } + + func opaqueObjectDataWrapper(for rawData: DataDict) -> ObjectData { + ObjectData(_transformer: DataTransformer(), _rawData: rawData._data) + } + + struct DataTransformer: _ObjectData_Transformer { + func transform(_ value: AnyHashable) -> (any ScalarType)? { + switch value { + case let scalar as ScalarType: + return scalar + case let customScalar as CustomScalarType: + return customScalar._jsonValue as? ScalarType + default: return nil + } + } + + func transform(_ value: AnyHashable) -> ObjectData? { + switch value { + case let object as DataDict: + return ObjectData(_transformer: self, _rawData: object._data) + default: return nil + } + } + + func transform(_ value: AnyHashable) -> ListData? { + switch value { + case let list as [AnyHashable]: + return ListData(_transformer: self, _rawData: list) + default: return nil + } + } + } +} diff --git a/Sources/ApolloPGATOUR/FieldSelectionCollector.swift b/Sources/ApolloPGATOUR/FieldSelectionCollector.swift new file mode 100644 index 0000000000..47e82e2b32 --- /dev/null +++ b/Sources/ApolloPGATOUR/FieldSelectionCollector.swift @@ -0,0 +1,179 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +struct FieldSelectionGrouping: Sequence { + private var fieldInfoList: [String: FieldExecutionInfo] = [:] + fileprivate(set) var fulfilledFragments: Set = [] + + init(info: ObjectExecutionInfo) { + self.fulfilledFragments = info.fulfilledFragments + } + + var count: Int { fieldInfoList.count } + + mutating func append(field: Selection.Field, withInfo info: ObjectExecutionInfo) { + let fieldKey = field.responseKey + if let fieldInfo = fieldInfoList[fieldKey] { + fieldInfo.mergedFields.append(field) + fieldInfoList[fieldKey] = fieldInfo + } else { + fieldInfoList[fieldKey] = FieldExecutionInfo(field: field, parentInfo: info) + } + } + + mutating func addFulfilledFragment(_ type: T.Type) { + fulfilledFragments.insert(ObjectIdentifier(type)) + } + + func makeIterator() -> Dictionary.Iterator { + fieldInfoList.makeIterator() + } +} + +/// A protocol for a type that defines how to collect and group the selections for an object +/// during GraphQLExecution. +/// +/// A `FieldSelectionController` is responsible for determining which selections should be executed +/// and which fragments are being fulfilled during execution. It does this by adding them to the +/// provided `FieldSelectionGrouping`. +protocol FieldSelectionCollector { + + associatedtype ObjectData + + /// Groups fields that share the same response key for simultaneous resolution. + /// + /// Before execution, the selection set is converted to a grouped field set. + /// Each entry in the grouped field set is a list of fields that share a response key. + /// This ensures all fields with the same response key (alias or field name) included via + /// referenced fragments are executed at the same time. + static func collectFields( + from selections: [Selection], + into groupedFields: inout FieldSelectionGrouping, + for object: ObjectData, + info: ObjectExecutionInfo + ) throws + +} + +struct DefaultFieldSelectionCollector: FieldSelectionCollector { + static func collectFields( + from selections: [Selection], + into groupedFields: inout FieldSelectionGrouping, + for object: JSONObject, + info: ObjectExecutionInfo + ) throws { + for selection in selections { + switch selection { + case let .field(field): + groupedFields.append(field: field, withInfo: info) + + case let .conditional(conditions, conditionalSelections): + if conditions.evaluate(with: info.variables) { + try collectFields(from: conditionalSelections, + into: &groupedFields, + for: object, + info: info) + } + + case .deferred(_, _, _): + assertionFailure("Defer execution must be implemented (#3145).") + case let .fragment(fragment): + groupedFields.addFulfilledFragment(fragment) + try collectFields(from: fragment.__selections, + into: &groupedFields, + for: object, + info: info) + + // TODO: _ is fine for now but will need to be handled in #3145 + case let .inlineFragment(typeCase): + if let runtimeType = info.runtimeObjectType(for: object), + typeCase.__parentType.canBeConverted(from: runtimeType) { + groupedFields.addFulfilledFragment(typeCase) + try collectFields(from: typeCase.__selections, + into: &groupedFields, + for: object, + info: info) + } + } + } + } +} + +/// This field collector is intended for usage when writing custom selection set data to the cache. +/// It is used by the cache writing APIs in ``ApolloStore/ReadWriteTransaction``. +/// +/// This ``FieldSelectionCollector`` attempts to write all of the given object data to the cache. +/// It collects fields that are wrapped in inclusion conditions if data for the field exists, +/// ignoring the inclusion condition and variables. This ensures that object data for these fields +/// will be written to the cache. +struct CustomCacheDataWritingFieldSelectionCollector: FieldSelectionCollector { + static func collectFields( + from selections: [Selection], + into groupedFields: inout FieldSelectionGrouping, + for object: DataDict, + info: ObjectExecutionInfo + ) throws { + groupedFields.fulfilledFragments = object._fulfilledFragments + try collectFields( + from: selections, + into: &groupedFields, + for: object, + info: info, + asConditionalFields: false + ) + } + + static func collectFields( + from selections: [Selection], + into groupedFields: inout FieldSelectionGrouping, + for object: DataDict, + info: ObjectExecutionInfo, + asConditionalFields: Bool + ) throws { + for selection in selections { + switch selection { + case let .field(field): + if asConditionalFields && !field.type.isNullable { + guard let value = object._data[field.responseKey], !(value is NSNull) else { + continue + } + } + groupedFields.append(field: field, withInfo: info) + + case let .conditional(_, conditionalSelections): + try collectFields(from: conditionalSelections, + into: &groupedFields, + for: object, + info: info, + asConditionalFields: true) + case .deferred(_, _, _): + assertionFailure("Defer execution must be implemented (#3145).") + case let .fragment(fragment): + if groupedFields.fulfilledFragments.contains(type: fragment) { + try collectFields(from: fragment.__selections, + into: &groupedFields, + for: object, + info: info, + asConditionalFields: false) + } + + case let .inlineFragment(typeCase): + if groupedFields.fulfilledFragments.contains(type: typeCase) { + try collectFields(from: typeCase.__selections, + into: &groupedFields, + for: object, + info: info, + asConditionalFields: false) + } + } + } + } +} + +fileprivate extension Set { + func contains(type: Any.Type) -> Bool { + contains(ObjectIdentifier(type.self)) + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLDependencyTracker.swift b/Sources/ApolloPGATOUR/GraphQLDependencyTracker.swift new file mode 100644 index 0000000000..814cac1866 --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLDependencyTracker.swift @@ -0,0 +1,45 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +final class GraphQLDependencyTracker: GraphQLResultAccumulator { + + let requiresCacheKeyComputation: Bool = true + + private var dependentKeys: Set = Set() + + func accept(scalar: JSONValue, info: FieldExecutionInfo) { + dependentKeys.insert(info.cachePath.joined) + } + + func accept(customScalar: JSONValue, info: FieldExecutionInfo) { + dependentKeys.insert(info.cachePath.joined) + } + + func acceptNullValue(info: FieldExecutionInfo) { + dependentKeys.insert(info.cachePath.joined) + } + + func acceptMissingValue(info: FieldExecutionInfo) throws -> () { + dependentKeys.insert(info.cachePath.joined) + } + + func accept(list: [Void], info: FieldExecutionInfo) { + dependentKeys.insert(info.cachePath.joined) + } + + func accept(childObject: Void, info: FieldExecutionInfo) { + } + + func accept(fieldEntry: Void, info: FieldExecutionInfo) -> Void? { + dependentKeys.insert(info.cachePath.joined) + return () + } + + func accept(fieldEntries: [Void], info: ObjectExecutionInfo) { + } + + func finish(rootValue: Void, info: ObjectExecutionInfo) -> Set { + return dependentKeys + } +} diff --git a/Sources/Apollo/GraphQLError.swift b/Sources/ApolloPGATOUR/GraphQLError.swift similarity index 61% rename from Sources/Apollo/GraphQLError.swift rename to Sources/ApolloPGATOUR/GraphQLError.swift index bcaf5eb49a..6c99dea419 100644 --- a/Sources/Apollo/GraphQLError.swift +++ b/Sources/ApolloPGATOUR/GraphQLError.swift @@ -1,9 +1,12 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// Represents an error encountered during the execution of a GraphQL operation. /// /// - SeeAlso: [The Response Format section in the GraphQL specification](https://facebook.github.io/graphql/#sec-Response-Format) -public struct GraphQLError: Error { +public struct GraphQLError: Error, Hashable { private let object: JSONObject public init(_ object: JSONObject) { @@ -29,6 +32,11 @@ public struct GraphQLError: Error { return (self["locations"] as? [JSONObject])?.compactMap(Location.init) } + /// A path to the field that triggered the error, represented by an array of Path Entries. + public var path: [PathEntry]? { + return (self["path"] as? [JSONValue])?.compactMap(PathEntry.init) + } + /// A dictionary which services can use however they see fit to provide additional information in errors to clients. public var extensions: [String : Any]? { return self["extensions"] as? [String : Any] @@ -47,6 +55,24 @@ public struct GraphQLError: Error { self.column = column } } + + /// Represents a path in a GraphQL query. + public enum PathEntry: Equatable { + /// A String value for a field in a GraphQL query + case field(String) + /// An Int value for an index in a GraphQL List + case index(Int) + + init?(_ value: JSONValue) { + if let string = value as? String { + self = .field(string) + } else if let int = value as? Int { + self = .index(int) + } else { + return nil + } + } + } } extension GraphQLError: CustomStringConvertible { @@ -60,3 +86,14 @@ extension GraphQLError: LocalizedError { return self.description } } + +extension GraphQLError { + func asJSONDictionary() -> [String: Any] { + var dict: [String: Any] = [:] + if let message = self["message"] { dict["message"] = message } + if let locations = self["locations"] { dict["locations"] = locations } + if let path = self["path"] { dict["path"] = path } + if let extensions = self["extensions"] { dict["extensions"] = extensions } + return dict + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLExecutionSource.swift b/Sources/ApolloPGATOUR/GraphQLExecutionSource.swift new file mode 100644 index 0000000000..5d613e8faf --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLExecutionSource.swift @@ -0,0 +1,58 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// A protocol representing a data source for GraphQL data to be executed upon by a +/// `GraphQLExecutor`. +/// +/// Based on the source of execution data, the way we handle portions of the execution pipeline will +/// be different. Each implementation of this protocol provides the necessary implementations for +/// executing upon data from a specific source. +protocol GraphQLExecutionSource { + /// The type that represents each object in data from the source. + associatedtype RawObjectData + + /// The type of `FieldSelectionCollector` used for the selection grouping step of + /// GraphQL execution. + associatedtype FieldCollector: FieldSelectionCollector + + /// Resolves the value for given field on a data object from the source. + /// + /// Because data may be loaded from a database, these loads are batched for performance reasons. + /// By returning a `PossiblyDeferred` wrapper, we allow `ApolloStore` to use a `DataLoader` that + /// will defer loading the next batch of records from the cache until they are needed. + /// + /// - Returns: The value for the field represented by the `info` on the `object`. + /// For a field with a scalar value, this should be a raw JSON value. + /// For fields whose type is an object, this should be of the source's `ObjectData` type or + /// a `CacheReference` that can be resolved by the source. + func resolveField( + with info: FieldExecutionInfo, + on object: RawObjectData + ) -> PossiblyDeferred + + /// Returns the cache key for an object to be used during GraphQL execution. + /// - Parameters: + /// - object: The data for the object from the source. + /// - schema: The schema that the type the object data represents belongs to. + /// - Returns: A cache key for normalizing the object in the cache. If `nil` is returned the + /// object is assumed to be stored in the cache with no normalization. The executor will + /// construct a cache key based on the object's path in its enclosing operation. + func computeCacheKey(for object: RawObjectData, in schema: SchemaMetadata.Type) -> CacheKey? +} + +/// A type of `GraphQLExecutionSource` that uses the user defined cache key computation +/// defined in the ``SchemaConfiguration``. +protocol CacheKeyComputingExecutionSource: GraphQLExecutionSource { + /// A function that should return an `ObjectData` wrapper that performs and custom + /// transformations required to transform the raw object data from the source into a consistent + /// format to be exposed to the user's ``SchemaConfiguration/cacheKeyInfo(for:object:)`` function. + func opaqueObjectDataWrapper(for: RawObjectData) -> ObjectData +} + +extension CacheKeyComputingExecutionSource { + func computeCacheKey(for object: RawObjectData, in schema: SchemaMetadata.Type) -> CacheKey? { + let dataWrapper = opaqueObjectDataWrapper(for: object) + return schema.cacheKey(for: dataWrapper) + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLExecutor.swift b/Sources/ApolloPGATOUR/GraphQLExecutor.swift new file mode 100644 index 0000000000..706daa73c1 --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLExecutor.swift @@ -0,0 +1,408 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +class ObjectExecutionInfo { + let rootType: any RootSelectionSet.Type + let variables: GraphQLOperation.Variables? + let schema: SchemaMetadata.Type + private(set) var responsePath: ResponsePath = [] + private(set) var cachePath: ResponsePath = [] + fileprivate(set) var fulfilledFragments: Set + + fileprivate init( + rootType: any RootSelectionSet.Type, + variables: GraphQLOperation.Variables?, + schema: SchemaMetadata.Type, + responsePath: ResponsePath, + cachePath: ResponsePath + ) { + self.rootType = rootType + self.variables = variables + self.schema = schema + self.responsePath = responsePath + self.cachePath = cachePath + self.fulfilledFragments = [ObjectIdentifier(rootType)] + } + + fileprivate init( + rootType: any RootSelectionSet.Type, + variables: GraphQLOperation.Variables?, + schema: SchemaMetadata.Type, + withRootCacheReference root: CacheReference? = nil + ) { + self.rootType = rootType + self.variables = variables + self.schema = schema + if let root = root { + cachePath = [root.key] + } + self.fulfilledFragments = [ObjectIdentifier(rootType)] + } + + func runtimeObjectType( + for json: JSONObject + ) -> Object? { + guard let __typename = json["__typename"] as? String else { + guard let objectType = rootType.__parentType as? Object else { + return nil + } + return schema.objectType(forTypename: objectType.typename) + } + return schema.objectType(forTypename: __typename) + } +} + +/// Stores the information for executing a field and all duplicate fields on the same selection set. +/// +/// GraphQL validation makes sure all fields sharing the same response key have the same +/// arguments and are of the same type, so we only need to resolve one field. +class FieldExecutionInfo { + let field: Selection.Field + let parentInfo: ObjectExecutionInfo + + var mergedFields: [Selection.Field] + + var responsePath: ResponsePath + let responseKeyForField: String + + var cachePath: ResponsePath = [] + private var _cacheKeyForField: String? + + init( + field: Selection.Field, + parentInfo: ObjectExecutionInfo + ) { + self.field = field + self.parentInfo = parentInfo + mergedFields = [field] + + let responseKey = field.responseKey + responsePath = parentInfo.responsePath.appending(responseKey) + responseKeyForField = responseKey + } + + fileprivate func computeCacheKeyAndPath() throws { + cachePath = try parentInfo.cachePath.appending(cacheKeyForField()) + } + + func cacheKeyForField() throws -> String { + guard let _cacheKeyForField else { + let cacheKey = try field.cacheKey(with: parentInfo.variables) + _cacheKeyForField = cacheKey + return cacheKey + } + return _cacheKeyForField + } + + /// Computes the `ObjectExecutionInfo` and selections that should be used for + /// executing the child object. + /// + /// - Note: There will only be child selections if the fields for this field info are + /// object type fields (objects; lists of objects; or non-null wrapped objects). + /// For scalar fields, the child selections will be an empty array. + fileprivate func computeChildExecutionData( + withRootType rootType: any RootSelectionSet.Type, + cacheKey: CacheKey? + ) -> (ObjectExecutionInfo, [Selection]) { + // If the object has it's own cache key, reset the cache path to the key, + // rather than using the inherited cache path from the parent field. + let cachePath: ResponsePath = { + if let cacheKey { return [cacheKey] } + else { return self.cachePath } + }() + + let childExecutionInfo = ObjectExecutionInfo( + rootType: rootType, + variables: parentInfo.variables, + schema: parentInfo.schema, + responsePath: responsePath, + cachePath: cachePath + ) + var childSelections: [Selection] = [] + + mergedFields.forEach { field in + guard case let .object(selectionSet) = field.type.namedType else { + return + } + childExecutionInfo.fulfilledFragments.insert(ObjectIdentifier(selectionSet.self)) + childSelections.append(contentsOf: selectionSet.__selections) + } + + return (childExecutionInfo, childSelections) + } + + func copy() -> FieldExecutionInfo { + FieldExecutionInfo(self) + } + + private init(_ info: FieldExecutionInfo) { + self.field = info.field + self.parentInfo = info.parentInfo + self.mergedFields = info.mergedFields + self.responsePath = info.responsePath + self.responseKeyForField = info.responseKeyForField + self.cachePath = info.cachePath + self._cacheKeyForField = info._cacheKeyForField + } + +} + +/// An error which has occurred during GraphQL execution. +public struct GraphQLExecutionError: Error, LocalizedError { + let path: ResponsePath + + public var pathString: String { path.description } + + /// The error that occurred during parsing. + public let underlying: Error + + /// A description of the error which includes the path where the error occurred. + public var errorDescription: String? { + return "Error at path \"\(path))\": \(underlying)" + } +} + +/// A GraphQL executor is responsible for executing a selection set and generating a result. It is initialized with a resolver closure that gets called repeatedly to resolve field values. +/// +/// An executor is used both to parse a response received from the server, and to read from the normalized cache. It can also be configured with an accumulator that receives events during execution, and these execution events are used by `GraphQLResultNormalizer` to normalize a response into a flat set of records and by `GraphQLDependencyTracker` keep track of dependent keys. +/// +/// The methods in this class closely follow the +/// [execution algorithm described in the GraphQL specification] +/// (http://spec.graphql.org/draft/#sec-Execution) +final class GraphQLExecutor { + + private let executionSource: Source + + init(executionSource: Source) { + self.executionSource = executionSource + } + + // MARK: - Execution + + func execute< + Accumulator: GraphQLResultAccumulator, + SelectionSet: RootSelectionSet + >( + selectionSet: SelectionSet.Type, + on data: Source.RawObjectData, + withRootCacheReference root: CacheReference? = nil, + variables: GraphQLOperation.Variables? = nil, + accumulator: Accumulator + ) throws -> Accumulator.FinalResult { + let info = ObjectExecutionInfo( + rootType: SelectionSet.self, + variables: variables, + schema: SelectionSet.Schema.self, + withRootCacheReference: root + ) + + let rootValue = execute( + selections: selectionSet.__selections, + on: data, + info: info, + accumulator: accumulator + ) + + return try accumulator.finish(rootValue: try rootValue.get(), info: info) + } + + private func execute( + selections: [Selection], + on object: Source.RawObjectData, + info: ObjectExecutionInfo, + accumulator: Accumulator + ) -> PossiblyDeferred { + do { + let groupedFields = try groupFields(selections, on: object, info: info) + info.fulfilledFragments = groupedFields.fulfilledFragments + + var fieldEntries: [PossiblyDeferred] = [] + fieldEntries.reserveCapacity(groupedFields.count) + + for (_, fields) in groupedFields { + let fieldEntry = execute(fields: fields, + on: object, + accumulator: accumulator) + fieldEntries.append(fieldEntry) + } + + return compactLazilyEvaluateAll(fieldEntries).map { + try accumulator.accept(fieldEntries: $0, info: info) + } + + } catch { + return .immediate(.failure(error)) + } + } + + /// Groups fields that share the same response key for simultaneous resolution. + /// + /// Before execution, the selection set is converted to a grouped field set. + /// Each entry in the grouped field set is a list of fields that share a response key. + /// This ensures all fields with the same response key (alias or field name) included via + /// referenced fragments are executed at the same time. + private func groupFields( + _ selections: [Selection], + on object: Source.RawObjectData, + info: ObjectExecutionInfo + ) throws -> FieldSelectionGrouping { + var grouping = FieldSelectionGrouping(info: info) + + try Source.FieldCollector.collectFields( + from: selections, + into: &grouping, + for: object, + info: info + ) + return grouping + } + + /// Each field requested in the grouped field set that is defined on the selected objectType will + /// result in an entry in the response map. Field execution first coerces any provided argument + /// values, then resolves a value for the field, and finally, completes that value, either by + /// recursively executing another selection set or coercing a scalar value. + private func execute( + fields fieldInfo: FieldExecutionInfo, + on object: Source.RawObjectData, + accumulator: Accumulator + ) -> PossiblyDeferred { + if accumulator.requiresCacheKeyComputation { + do { + try fieldInfo.computeCacheKeyAndPath() + } catch { + return .immediate(.failure(error)) + } + } + + return executionSource.resolveField(with: fieldInfo, on: object) + .flatMap { + return self.complete(fields: fieldInfo, + withValue: $0, + accumulator: accumulator) + }.map { + try accumulator.accept(fieldEntry: $0, info: fieldInfo) + }.mapError { error in + if !(error is GraphQLExecutionError) { + return GraphQLExecutionError(path: fieldInfo.responsePath, underlying: error) + } else { + return error + } + } + } + + private func complete( + fields fieldInfo: FieldExecutionInfo, + withValue value: JSONValue?, + accumulator: Accumulator + ) -> PossiblyDeferred { + complete(fields: fieldInfo, + withValue: value, + asType: fieldInfo.field.type, + accumulator: accumulator) + } + + /// After resolving the value for a field, it is completed by ensuring it adheres to the expected + /// return type. If the return type is another Object type, then the field execution process + /// continues recursively. + private func complete( + fields fieldInfo: FieldExecutionInfo, + withValue value: JSONValue?, + asType returnType: Selection.Field.OutputType, + accumulator: Accumulator + ) -> PossiblyDeferred { + guard let value else { + return PossiblyDeferred { try accumulator.acceptMissingValue(info: fieldInfo) } + } + + if value is NSNull && returnType.isNullable { + return PossiblyDeferred { try accumulator.acceptNullValue(info: fieldInfo) } + } + + switch returnType { + case .nonNull where value is NSNull: + return .immediate(.failure(JSONDecodingError.nullValue)) + + case let .nonNull(innerType): + return complete(fields: fieldInfo, + withValue: value, + asType: innerType, + accumulator: accumulator) + + case .scalar: + return PossiblyDeferred { try accumulator.accept(scalar: value, info: fieldInfo) } + + case .customScalar: + return PossiblyDeferred { try accumulator.accept(customScalar: value, info: fieldInfo) } + + case .list(let innerType): + guard let array = value as? [JSONValue] else { + return PossiblyDeferred { throw JSONDecodingError.wrongType } + } + + let completedArray = array + .enumerated() + .map { index, element -> PossiblyDeferred in + let elementFieldInfo = fieldInfo.copy() + + let indexSegment = String(index) + elementFieldInfo.responsePath.append(indexSegment) + + if accumulator.requiresCacheKeyComputation { + elementFieldInfo.cachePath.append(indexSegment) + } + + return self + .complete( + fields: elementFieldInfo, + withValue: element, + asType: innerType, + accumulator: accumulator + ) + .mapError { error in + if !(error is GraphQLExecutionError) { + return GraphQLExecutionError(path: elementFieldInfo.responsePath, underlying: error) + } else { + return error + } + } + } + + return lazilyEvaluateAll(completedArray).map { + try accumulator.accept(list: $0, info: fieldInfo) + } + case let .object(rootSelectionSetType): + guard let object = value as? Source.RawObjectData else { + return PossiblyDeferred { throw JSONDecodingError.wrongType } + } + + return executeChildSelections( + forObjectTypeFields: fieldInfo, + withRootType: rootSelectionSetType, + onChildObject: object, + accumulator: accumulator + ) + } + } + + private func executeChildSelections( + forObjectTypeFields fieldInfo: FieldExecutionInfo, + withRootType rootSelectionSetType: any RootSelectionSet.Type, + onChildObject object: Source.RawObjectData, + accumulator: Accumulator + ) -> PossiblyDeferred { + let (childExecutionInfo, selections) = fieldInfo.computeChildExecutionData( + withRootType: rootSelectionSetType, + cacheKey: executionSource.computeCacheKey(for: object, in: fieldInfo.parentInfo.schema) + ) + + return execute( + selections: selections, + on: object, + info: childExecutionInfo, + accumulator: accumulator + ) + .map { try accumulator.accept(childObject: $0, info: fieldInfo) } + } +} diff --git a/Sources/Apollo/GraphQLFile.swift b/Sources/ApolloPGATOUR/GraphQLFile.swift similarity index 98% rename from Sources/Apollo/GraphQLFile.swift rename to Sources/ApolloPGATOUR/GraphQLFile.swift index 7fe7823128..999ddf18b7 100644 --- a/Sources/Apollo/GraphQLFile.swift +++ b/Sources/ApolloPGATOUR/GraphQLFile.swift @@ -1,7 +1,7 @@ import Foundation /// A file which can be uploaded to a GraphQL server -public struct GraphQLFile { +public struct GraphQLFile: Hashable { public let fieldName: String public let originalName: String public let mimeType: String diff --git a/Sources/Apollo/GraphQLGETTransformer.swift b/Sources/ApolloPGATOUR/GraphQLGETTransformer.swift similarity index 61% rename from Sources/Apollo/GraphQLGETTransformer.swift rename to Sources/ApolloPGATOUR/GraphQLGETTransformer.swift index 5108f1effd..ca9abe7f0e 100644 --- a/Sources/Apollo/GraphQLGETTransformer.swift +++ b/Sources/ApolloPGATOUR/GraphQLGETTransformer.swift @@ -1,19 +1,19 @@ import Foundation #if !COCOAPODS -import ApolloUtils +import ApolloAPI #endif public struct GraphQLGETTransformer { - let body: GraphQLMap + let body: JSONEncodableDictionary let url: URL - /// A helper for transforming a GraphQLMap that can be sent with a `POST` request into a URL with query parameters for a `GET` request. + /// A helper for transforming a `JSONEncodableDictionary` that can be sent with a `POST` request into a URL with query parameters for a `GET` request. /// /// - Parameters: - /// - body: The GraphQLMap to transform from the body of a `POST` request + /// - body: The `JSONEncodableDictionary` to transform from the body of a `POST` request /// - url: The base url to append the query to. - public init(body: GraphQLMap, url: URL) { + public init(body: JSONEncodableDictionary, url: URL) { self.body = body self.url = url } @@ -30,8 +30,8 @@ public struct GraphQLGETTransformer { do { _ = try self.body.sorted(by: {$0.key < $1.key}).compactMap({ arg in - if let value = arg.value as? GraphQLMap { - let data = try JSONSerialization.sortedData(withJSONObject: value.jsonValue) + if let value = arg.value as? JSONEncodableDictionary { + let data = try JSONSerialization.sortedData(withJSONObject: value._jsonValue) if let string = String(data: data, encoding: .utf8) { queryItems.append(URLQueryItem(name: arg.key, value: string)) } @@ -45,7 +45,7 @@ public struct GraphQLGETTransformer { return nil } - if queryItems.apollo.isNotEmpty { + if !queryItems.isEmpty { components.queryItems = queryItems } @@ -55,3 +55,17 @@ public struct GraphQLGETTransformer { return components.url } } + +// MARK: - Hashable Conformance + +extension GraphQLGETTransformer: Hashable { + public static func == (lhs: GraphQLGETTransformer, rhs: GraphQLGETTransformer) -> Bool { + lhs.body._jsonValue == rhs.body._jsonValue && + lhs.url == rhs.url + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(body._jsonValue) + hasher.combine(url) + } +} diff --git a/Sources/Apollo/GraphQLHTTPMethod.swift b/Sources/ApolloPGATOUR/GraphQLHTTPMethod.swift similarity index 56% rename from Sources/Apollo/GraphQLHTTPMethod.swift rename to Sources/ApolloPGATOUR/GraphQLHTTPMethod.swift index bcdcf5f2e7..cdd96bc13b 100644 --- a/Sources/Apollo/GraphQLHTTPMethod.swift +++ b/Sources/ApolloPGATOUR/GraphQLHTTPMethod.swift @@ -1,7 +1,5 @@ -import Foundation - /// Supported HTTP methods for Apollo -enum GraphQLHTTPMethod: String { +enum GraphQLHTTPMethod: String, Hashable { case GET case POST } diff --git a/Sources/Apollo/GraphQLHTTPRequestError.swift b/Sources/ApolloPGATOUR/GraphQLHTTPRequestError.swift similarity index 87% rename from Sources/Apollo/GraphQLHTTPRequestError.swift rename to Sources/ApolloPGATOUR/GraphQLHTTPRequestError.swift index 23200a4d99..6a37b2b75d 100644 --- a/Sources/Apollo/GraphQLHTTPRequestError.swift +++ b/Sources/ApolloPGATOUR/GraphQLHTTPRequestError.swift @@ -1,7 +1,7 @@ import Foundation /// An error which has occurred during the serialization of a request. -public enum GraphQLHTTPRequestError: Error, LocalizedError { +public enum GraphQLHTTPRequestError: Error, LocalizedError, Hashable { case serializedBodyMessageError case serializedQueryParamsMessageError diff --git a/Sources/Apollo/GraphQLQueryWatcher.swift b/Sources/ApolloPGATOUR/GraphQLQueryWatcher.swift similarity index 79% rename from Sources/Apollo/GraphQLQueryWatcher.swift rename to Sources/ApolloPGATOUR/GraphQLQueryWatcher.swift index a1c3af0d0f..cc9eb3bca9 100644 --- a/Sources/Apollo/GraphQLQueryWatcher.swift +++ b/Sources/ApolloPGATOUR/GraphQLQueryWatcher.swift @@ -1,6 +1,6 @@ import Foundation #if !COCOAPODS -import ApolloUtils +import ApolloAPI #endif /// A `GraphQLQueryWatcher` is responsible for watching the store, and calling the result handler with a new result whenever any of the data the previous result depends on changes. @@ -14,6 +14,7 @@ public final class GraphQLQueryWatcher: Cancellable, Apollo private let callbackQueue: DispatchQueue private let contextIdentifier = UUID() + private let context: RequestContext? private class WeakFetchTaskContainer { weak var cancellable: Cancellable? @@ -24,25 +25,29 @@ public final class GraphQLQueryWatcher: Cancellable, Apollo self.cachePolicy = cachePolicy } } - private var fetching: Atomic = Atomic(.init(nil, nil)) - private var dependentKeys: Atomic?> = Atomic(nil) + @Atomic private var fetching: WeakFetchTaskContainer = .init(nil, nil) + + @Atomic private var dependentKeys: Set? = nil /// Designated initializer /// /// - Parameters: /// - client: The client protocol to pass in. /// - query: The query to watch. + /// - context: [optional] A context that is being passed through the request chain. Defaults to `nil`. /// - callbackQueue: The queue for the result handler. Defaults to the main queue. /// - resultHandler: The result handler to call with changes. public init(client: ApolloClientProtocol, query: Query, + context: RequestContext? = nil, callbackQueue: DispatchQueue = .main, resultHandler: @escaping GraphQLResultHandler) { self.client = client self.query = query self.resultHandler = resultHandler self.callbackQueue = callbackQueue + self.context = context client.store.subscribe(self) } @@ -53,16 +58,16 @@ public final class GraphQLQueryWatcher: Cancellable, Apollo } func fetch(cachePolicy: CachePolicy) { - fetching.mutate { + $fetching.mutate { // Cancel anything already in flight before starting a new fetch $0.cancellable?.cancel() $0.cachePolicy = cachePolicy - $0.cancellable = client?.fetch(query: query, cachePolicy: cachePolicy, contextIdentifier: self.contextIdentifier, queue: callbackQueue) { [weak self] result in + $0.cancellable = client?.fetch(query: query, cachePolicy: cachePolicy, contextIdentifier: self.contextIdentifier, context: self.context, queue: callbackQueue) { [weak self] result in guard let self = self else { return } switch result { case .success(let graphQLResult): - self.dependentKeys.mutate { + self.$dependentKeys.mutate { $0 = graphQLResult.dependentKeys } case .failure: @@ -76,13 +81,13 @@ public final class GraphQLQueryWatcher: Cancellable, Apollo /// Cancel any in progress fetching operations and unsubscribe from the store. public func cancel() { - fetching.value.cancellable?.cancel() + fetching.cancellable?.cancel() client?.store.unsubscribe(self) } - func store(_ store: ApolloStore, - didChangeKeys changedKeys: Set, - contextIdentifier: UUID?) { + public func store(_ store: ApolloStore, + didChangeKeys changedKeys: Set, + contextIdentifier: UUID?) { if let incomingIdentifier = contextIdentifier, incomingIdentifier == self.contextIdentifier { @@ -92,14 +97,14 @@ public final class GraphQLQueryWatcher: Cancellable, Apollo return } - guard let dependentKeys = self.dependentKeys.value else { + guard let dependentKeys = self.dependentKeys else { // This query has nil dependent keys, so nothing that changed will affect it. return } if !dependentKeys.isDisjoint(with: changedKeys) { // First, attempt to reload the query from the cache directly, in order not to interrupt any in-flight server-side fetch. - store.load(query: self.query) { [weak self] result in + store.load(self.query) { [weak self] result in guard let self = self else { return } switch result { @@ -109,13 +114,13 @@ public final class GraphQLQueryWatcher: Cancellable, Apollo return } - self.dependentKeys.mutate { + self.$dependentKeys.mutate { $0 = graphQLResult.dependentKeys } self.resultHandler(result) } case .failure: - if self.fetching.value.cachePolicy != .returnCacheDataDontFetch { + if self.fetching.cachePolicy != .returnCacheDataDontFetch { // If the cache fetch is not successful, for instance if the data is missing, refresh from the server. self.fetch(cachePolicy: .fetchIgnoringCacheData) } diff --git a/Sources/ApolloPGATOUR/GraphQLResponse.swift b/Sources/ApolloPGATOUR/GraphQLResponse.swift new file mode 100644 index 0000000000..0cf4ba9286 --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLResponse.swift @@ -0,0 +1,99 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// Represents a GraphQL response received from a server. +public final class GraphQLResponse { + + public let body: JSONObject + + private let rootKey: CacheReference + private let variables: GraphQLOperation.Variables? + + public init(operation: Operation, body: JSONObject) where Operation.Data == Data { + self.body = body + rootKey = CacheReference.rootCacheReference(for: Operation.operationType) + variables = operation.__variables + } + + /// Parses a response into a `GraphQLResult` and a `RecordSet`. + /// The result can be sent to a completion block for a request. + /// The `RecordSet` can be merged into a local cache. + /// - Returns: A `GraphQLResult` and a `RecordSet`. + public func parseResult() throws -> (GraphQLResult, RecordSet?) { + let accumulator = zip( + GraphQLSelectionSetMapper(), + ResultNormalizerFactory.networkResponseDataNormalizer(), + GraphQLDependencyTracker() + ) + + let executionResult = try execute(with: accumulator) + let result = makeResult(data: executionResult?.0, dependentKeys: executionResult?.2) + return (result, executionResult?.1) + } + + private func execute( + with accumulator: Accumulator + ) throws -> Accumulator.FinalResult? { + guard let dataEntry = body["data"] as? JSONObject else { + return nil + } + + let executor = GraphQLExecutor(executionSource: NetworkResponseExecutionSource()) + + return try executor.execute(selectionSet: Data.self, + on: dataEntry, + withRootCacheReference: rootKey, + variables: variables, + accumulator: accumulator) + } + + private func makeResult(data: Data?, dependentKeys: Set?) -> GraphQLResult { + let errors = self.parseErrors() + let extensions = body["extensions"] as? JSONObject + + return GraphQLResult(data: data, + extensions: extensions, + errors: errors, + source: .server, + dependentKeys: dependentKeys) + } + + private func parseErrors() -> [GraphQLError]? { + guard let errorsEntry = self.body["errors"] as? [JSONObject] else { + return nil + } + + return errorsEntry.map(GraphQLError.init) + } + + /// Parses a response into a `GraphQLResult` for use without the cache. This parsing does not + /// create dependent keys or a `RecordSet` for the cache. + /// + /// This is faster than `parseResult()` and should be used when cache the response is not needed. + public func parseResultFast() throws -> GraphQLResult { + let accumulator = GraphQLSelectionSetMapper() + let data = try execute(with: accumulator) + return makeResult(data: data, dependentKeys: nil) + } +} + +// MARK: - Equatable Conformance + +extension GraphQLResponse: Equatable where Data: Equatable { + public static func == (lhs: GraphQLResponse, rhs: GraphQLResponse) -> Bool { + lhs.body == rhs.body && + lhs.rootKey == rhs.rootKey && + lhs.variables?._jsonEncodableObject._jsonValue == rhs.variables?._jsonEncodableObject._jsonValue + } +} + +// MARK: - Hashable Conformance + +extension GraphQLResponse: Hashable where Data: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(body) + hasher.combine(rootKey) + hasher.combine(variables?._jsonEncodableObject._jsonValue) + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLResult.swift b/Sources/ApolloPGATOUR/GraphQLResult.swift new file mode 100644 index 0000000000..f1f2b0280b --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLResult.swift @@ -0,0 +1,78 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// Represents the result of a GraphQL operation. +public struct GraphQLResult { + + /// The typed result data, or `nil` if an error was encountered that prevented a valid response. + public let data: Data? + /// A list of errors, or `nil` if the operation completed without encountering any errors. + public let errors: [GraphQLError]? + /// A dictionary which services can use however they see fit to provide additional information to clients. + public let extensions: [String: AnyHashable]? + + /// Represents source of data + public enum Source: Hashable { + case cache + case server + } + /// Source of data + public let source: Source + + let dependentKeys: Set? + + public init(data: Data?, + extensions: [String: AnyHashable]?, + errors: [GraphQLError]?, + source: Source, + dependentKeys: Set?) { + self.data = data + self.extensions = extensions + self.errors = errors + self.source = source + self.dependentKeys = dependentKeys + } +} + +// MARK: - Equatable/Hashable Conformance +extension GraphQLResult: Equatable where Data: Equatable { + public static func == (lhs: GraphQLResult, rhs: GraphQLResult) -> Bool { + lhs.data == rhs.data && + lhs.errors == rhs.errors && + lhs.extensions == rhs.extensions && + lhs.source == rhs.source && + lhs.dependentKeys == rhs.dependentKeys + } +} + +extension GraphQLResult: Hashable where Data: Hashable {} + +extension GraphQLResult { + + /// Converts a ``GraphQLResult`` into a basic JSON dictionary for use. + /// + /// - Returns: A `[String: Any]` JSON dictionary representing the ``GraphQLResult``. + public func asJSONDictionary() -> [String: Any] { + var dict: [String: Any] = [:] + if let data { dict["data"] = convert(value: data.__data) } + if let errors { dict["errors"] = errors.map { $0.asJSONDictionary() } } + if let extensions { dict["extensions"] = extensions } + return dict + } + + private func convert(value: Any) -> Any { + var val: Any = value + if let value = value as? DataDict { + val = value._data + } else if let value = value as? CustomScalarType { + val = value._jsonValue + } + if let dict = val as? [String: Any] { + return dict.mapValues(convert) + } else if let arr = val as? [Any] { + return arr.map(convert) + } + return val + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLResultAccumulator.swift b/Sources/ApolloPGATOUR/GraphQLResultAccumulator.swift new file mode 100644 index 0000000000..2ea7934570 --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLResultAccumulator.swift @@ -0,0 +1,179 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +protocol GraphQLResultAccumulator: AnyObject { + associatedtype PartialResult + associatedtype FieldEntry + associatedtype ObjectResult + associatedtype FinalResult + + var requiresCacheKeyComputation: Bool { get } + + func accept(scalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult + func accept(customScalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult + func acceptNullValue(info: FieldExecutionInfo) throws -> PartialResult + func acceptMissingValue(info: FieldExecutionInfo) throws -> PartialResult + func accept(list: [PartialResult], info: FieldExecutionInfo) throws -> PartialResult + func accept(childObject: ObjectResult, info: FieldExecutionInfo) throws -> PartialResult + + func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry? + func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult + + func finish(rootValue: ObjectResult, info: ObjectExecutionInfo) throws -> FinalResult +} + +func zip(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2) -> Zip2Accumulator { + return Zip2Accumulator(accumulator1, accumulator2) +} + +func zip(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2, _ accumulator3: Accumulator3) -> Zip3Accumulator { + return Zip3Accumulator(accumulator1, accumulator2, accumulator3) +} + +final class Zip2Accumulator: GraphQLResultAccumulator { + typealias PartialResult = (Accumulator1.PartialResult, Accumulator2.PartialResult) + typealias FieldEntry = (Accumulator1.FieldEntry?, Accumulator2.FieldEntry?) + typealias ObjectResult = (Accumulator1.ObjectResult, Accumulator2.ObjectResult) + typealias FinalResult = (Accumulator1.FinalResult, Accumulator2.FinalResult) + + private let accumulator1: Accumulator1 + private let accumulator2: Accumulator2 + let requiresCacheKeyComputation: Bool + + fileprivate init(_ accumulator1: Accumulator1, _ accumulator2: Accumulator2) { + self.accumulator1 = accumulator1 + self.accumulator2 = accumulator2 + + self.requiresCacheKeyComputation = + accumulator1.requiresCacheKeyComputation || + accumulator2.requiresCacheKeyComputation + } + + func accept(scalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.accept(scalar: scalar, info: info), + try accumulator2.accept(scalar: scalar, info: info)) + } + + func accept(customScalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.accept(customScalar: customScalar, info: info), + try accumulator2.accept(customScalar: customScalar, info: info)) + } + + func acceptNullValue(info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.acceptNullValue(info: info), + try accumulator2.acceptNullValue(info: info)) + } + + func acceptMissingValue(info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.acceptMissingValue(info: info), + try accumulator2.acceptMissingValue(info: info)) + } + + func accept(list: [PartialResult], info: FieldExecutionInfo) throws -> PartialResult { + let (list1, list2) = unzip(list) + return (try accumulator1.accept(list: list1, info: info), + try accumulator2.accept(list: list2, info: info)) + } + + func accept(childObject: ObjectResult, info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.accept(childObject: childObject.0, info: info), + try accumulator2.accept(childObject: childObject.1, info: info)) + } + + func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry? { + return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info), + try accumulator2.accept(fieldEntry: fieldEntry.1, info: info)) + } + + func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult { + let (fieldEntries1, fieldEntries2) = unzip(fieldEntries) + return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info), + try accumulator2.accept(fieldEntries: fieldEntries2, info: info)) + } + + func finish(rootValue: ObjectResult, info: ObjectExecutionInfo) throws -> FinalResult { + return (try accumulator1.finish(rootValue: rootValue.0, info: info), + try accumulator2.finish(rootValue: rootValue.1, info: info)) + } +} + +final class Zip3Accumulator: GraphQLResultAccumulator { + typealias PartialResult = (Accumulator1.PartialResult, Accumulator2.PartialResult, Accumulator3.PartialResult) + typealias FieldEntry = (Accumulator1.FieldEntry?, Accumulator2.FieldEntry?, Accumulator3.FieldEntry?) + typealias ObjectResult = (Accumulator1.ObjectResult, Accumulator2.ObjectResult, Accumulator3.ObjectResult) + typealias FinalResult = (Accumulator1.FinalResult, Accumulator2.FinalResult, Accumulator3.FinalResult) + + private let accumulator1: Accumulator1 + private let accumulator2: Accumulator2 + private let accumulator3: Accumulator3 + let requiresCacheKeyComputation: Bool + + fileprivate init(_ accumulator1: Accumulator1, + _ accumulator2: Accumulator2, + _ accumulator3: Accumulator3) { + self.accumulator1 = accumulator1 + self.accumulator2 = accumulator2 + self.accumulator3 = accumulator3 + self.requiresCacheKeyComputation = + accumulator1.requiresCacheKeyComputation || + accumulator2.requiresCacheKeyComputation || + accumulator3.requiresCacheKeyComputation + } + + func accept(scalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.accept(scalar: scalar, info: info), + try accumulator2.accept(scalar: scalar, info: info), + try accumulator3.accept(scalar: scalar, info: info)) + } + + func accept(customScalar: JSONValue, info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.accept(customScalar: customScalar, info: info), + try accumulator2.accept(customScalar: customScalar, info: info), + try accumulator3.accept(customScalar: customScalar, info: info)) + } + + func acceptNullValue(info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.acceptNullValue(info: info), + try accumulator2.acceptNullValue(info: info), + try accumulator3.acceptNullValue(info: info)) + } + + func acceptMissingValue(info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.acceptMissingValue(info: info), + try accumulator2.acceptMissingValue(info: info), + try accumulator3.acceptMissingValue(info: info)) + } + + func accept(list: [PartialResult], info: FieldExecutionInfo) throws -> PartialResult { + let (list1, list2, list3) = unzip(list) + return (try accumulator1.accept(list: list1, info: info), + try accumulator2.accept(list: list2, info: info), + try accumulator3.accept(list: list3, info: info)) + } + + func accept(childObject: ObjectResult, info: FieldExecutionInfo) throws -> PartialResult { + return (try accumulator1.accept(childObject: childObject.0, info: info), + try accumulator2.accept(childObject: childObject.1, info: info), + try accumulator3.accept(childObject: childObject.2, info: info)) + } + + func accept(fieldEntry: PartialResult, info: FieldExecutionInfo) throws -> FieldEntry? { + return (try accumulator1.accept(fieldEntry: fieldEntry.0, info: info), + try accumulator2.accept(fieldEntry: fieldEntry.1, info: info), + try accumulator3.accept(fieldEntry: fieldEntry.2, info: info)) + } + + func accept(fieldEntries: [FieldEntry], info: ObjectExecutionInfo) throws -> ObjectResult { + let (fieldEntries1, fieldEntries2, fieldEntries3) = unzip(fieldEntries) + return (try accumulator1.accept(fieldEntries: fieldEntries1, info: info), + try accumulator2.accept(fieldEntries: fieldEntries2, info: info), + try accumulator3.accept(fieldEntries: fieldEntries3, info: info)) + } + + func finish(rootValue: ObjectResult, info: ObjectExecutionInfo) throws -> FinalResult { + return (try accumulator1.finish(rootValue: rootValue.0, info: info), + try accumulator2.finish(rootValue: rootValue.1, info: info), + try accumulator3.finish(rootValue: rootValue.2, info: info)) + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLResultNormalizer.swift b/Sources/ApolloPGATOUR/GraphQLResultNormalizer.swift new file mode 100644 index 0000000000..e37b3d3069 --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLResultNormalizer.swift @@ -0,0 +1,80 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +enum ResultNormalizerFactory { + + static func selectionSetDataNormalizer() -> SelectionSetDataResultNormalizer { + SelectionSetDataResultNormalizer() + } + + static func networkResponseDataNormalizer() -> RawJSONResultNormalizer { + RawJSONResultNormalizer() + } +} + +class BaseGraphQLResultNormalizer: GraphQLResultAccumulator { + + let requiresCacheKeyComputation: Bool = true + + private var records: RecordSet = [:] + + fileprivate init() {} + + final func accept(scalar: JSONValue, info: FieldExecutionInfo) -> JSONValue? { + return scalar + } + + func accept(customScalar: JSONValue, info: FieldExecutionInfo) -> JSONValue? { + return customScalar + } + + final func acceptNullValue(info: FieldExecutionInfo) -> JSONValue? { + return NSNull() + } + + final func acceptMissingValue(info: FieldExecutionInfo) -> JSONValue? { + return nil + } + + final func accept(list: [JSONValue?], info: FieldExecutionInfo) -> JSONValue? { + return list + } + + final func accept(childObject: CacheReference, info: FieldExecutionInfo) -> JSONValue? { + return childObject + } + + final func accept(fieldEntry: JSONValue?, info: FieldExecutionInfo) throws -> (key: String, value: JSONValue)? { + guard let fieldEntry else { return nil } + return (try info.cacheKeyForField(), fieldEntry) + } + + final func accept( + fieldEntries: [(key: String, value: JSONValue)], + info: ObjectExecutionInfo + ) throws -> CacheReference { + let cachePath = info.cachePath.joined + + let object = JSONObject(fieldEntries, uniquingKeysWith: { (_, last) in last }) + records.merge(record: Record(key: cachePath, object)) + + return CacheReference(cachePath) + } + + final func finish(rootValue: CacheReference, info: ObjectExecutionInfo) throws -> RecordSet { + return records + } +} + +final class RawJSONResultNormalizer: BaseGraphQLResultNormalizer {} + +final class SelectionSetDataResultNormalizer: BaseGraphQLResultNormalizer { + override final func accept(customScalar: JSONValue, info: FieldExecutionInfo) -> JSONValue? { + if let customScalar = customScalar as? JSONEncodable { + return customScalar._jsonValue + } + return customScalar + } +} diff --git a/Sources/ApolloPGATOUR/GraphQLSelectionSetMapper.swift b/Sources/ApolloPGATOUR/GraphQLSelectionSetMapper.swift new file mode 100644 index 0000000000..03d98e100e --- /dev/null +++ b/Sources/ApolloPGATOUR/GraphQLSelectionSetMapper.swift @@ -0,0 +1,88 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +/// An accumulator that converts executed data to the correct values to create a `SelectionSet`. +final class GraphQLSelectionSetMapper: GraphQLResultAccumulator { + + let requiresCacheKeyComputation: Bool = false + + let handleMissingValues: HandleMissingValues + + enum HandleMissingValues { + case disallow + case allowForOptionalFields + /// Using this option will result in an unsafe `SelectionSet` that will crash + /// when a required field that has missing data is accessed. + case allowForAllFields + } + + init( + handleMissingValues: HandleMissingValues = .disallow + ) { + self.handleMissingValues = handleMissingValues + } + + func accept(scalar: AnyHashable, info: FieldExecutionInfo) throws -> AnyHashable? { + switch info.field.type.namedType { + case let .scalar(decodable as any JSONDecodable.Type): + // This will convert a JSON value to the expected value type. + return try decodable.init(_jsonValue: scalar)._asAnyHashable + default: + preconditionFailure() + } + } + + func accept(customScalar: AnyHashable, info: FieldExecutionInfo) throws -> AnyHashable? { + switch info.field.type.namedType { + case let .customScalar(decodable as any JSONDecodable.Type): + // This will convert a JSON value to the expected value type, + // which could be a custom scalar or an enum. + return try decodable.init(_jsonValue: customScalar)._asAnyHashable + default: + preconditionFailure() + } + } + + func acceptNullValue(info: FieldExecutionInfo) -> AnyHashable? { + return DataDict._NullValue + } + + func acceptMissingValue(info: FieldExecutionInfo) throws -> AnyHashable? { + switch handleMissingValues { + case .allowForOptionalFields where info.field.type.isNullable: fallthrough + case .allowForAllFields: + return nil + + default: + throw JSONDecodingError.missingValue + } + } + + func accept(list: [AnyHashable?], info: FieldExecutionInfo) -> AnyHashable? { + return list + } + + func accept(childObject: DataDict, info: FieldExecutionInfo) throws -> AnyHashable? { + return childObject + } + + func accept(fieldEntry: AnyHashable?, info: FieldExecutionInfo) -> (key: String, value: AnyHashable)? { + guard let fieldEntry = fieldEntry else { return nil } + return (info.responseKeyForField, fieldEntry) + } + + func accept( + fieldEntries: [(key: String, value: AnyHashable)], + info: ObjectExecutionInfo + ) throws -> DataDict { + return DataDict( + data: .init(fieldEntries, uniquingKeysWith: { (_, last) in last }), + fulfilledFragments: info.fulfilledFragments + ) + } + + func finish(rootValue: DataDict, info: ObjectExecutionInfo) -> T { + return T.init(_dataDict: rootValue) + } +} diff --git a/Sources/Apollo/HTTPRequest.swift b/Sources/ApolloPGATOUR/HTTPRequest.swift similarity index 79% rename from Sources/Apollo/HTTPRequest.swift rename to Sources/ApolloPGATOUR/HTTPRequest.swift index be3aff63b3..99b1f35d70 100644 --- a/Sources/Apollo/HTTPRequest.swift +++ b/Sources/ApolloPGATOUR/HTTPRequest.swift @@ -1,7 +1,10 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// Encapsulation of all information about a request before it hits the network -open class HTTPRequest { +open class HTTPRequest: Hashable { /// The endpoint to make a GraphQL request to open var graphQLEndpoint: URL @@ -17,6 +20,9 @@ open class HTTPRequest { /// [optional] A unique identifier for this request, to help with deduping cache hits for watchers. public let contextIdentifier: UUID? + + /// [optional] A context that is being passed through the request chain. + public let context: RequestContext? /// Designated Initializer /// @@ -29,6 +35,7 @@ open class HTTPRequest { /// - clientVersion: The version of the client to send with the `"apollographql-client-version"` header /// - additionalHeaders: Any additional headers you wish to add by default to this request. /// - cachePolicy: The `CachePolicy` to use for this request. Defaults to the `.default` policy + /// - context: [optional] A context that is being passed through the request chain. Defaults to `nil`. public init(graphQLEndpoint: URL, operation: Operation, contextIdentifier: UUID? = nil, @@ -36,12 +43,14 @@ open class HTTPRequest { clientName: String, clientVersion: String, additionalHeaders: [String: String], - cachePolicy: CachePolicy = .default) { + cachePolicy: CachePolicy = .default, + context: RequestContext? = nil) { self.graphQLEndpoint = graphQLEndpoint self.operation = operation self.contextIdentifier = contextIdentifier self.additionalHeaders = additionalHeaders self.cachePolicy = cachePolicy + self.context = context self.addHeader(name: "Content-Type", value: contentType) // Note: in addition to this being a generally useful header to send, Apollo @@ -53,9 +62,9 @@ open class HTTPRequest { // CSRF prevention enabled. See // https://www.apollographql.com/docs/apollo-server/security/cors/#preventing-cross-site-request-forgery-csrf // for details. - self.addHeader(name: "X-APOLLO-OPERATION-NAME", value: self.operation.operationName) - self.addHeader(name: "X-APOLLO-OPERATION-TYPE", value: String(describing: operation.operationType)) - if let operationID = self.operation.operationIdentifier { + self.addHeader(name: "X-APOLLO-OPERATION-NAME", value: Operation.operationName) + self.addHeader(name: "X-APOLLO-OPERATION-TYPE", value: String(describing: Operation.operationType)) + if let operationID = Operation.operationIdentifier { self.addHeader(name: "X-APOLLO-OPERATION-ID", value: operationID) } @@ -84,16 +93,23 @@ open class HTTPRequest { return request } -} -extension HTTPRequest: Equatable { - + // MARK: - Hashable Conformance + + public func hash(into hasher: inout Hasher) { + hasher.combine(graphQLEndpoint) + hasher.combine(operation) + hasher.combine(additionalHeaders) + hasher.combine(cachePolicy) + hasher.combine(contextIdentifier) + } + public static func == (lhs: HTTPRequest, rhs: HTTPRequest) -> Bool { - lhs.graphQLEndpoint == rhs.graphQLEndpoint - && lhs.contextIdentifier == rhs.contextIdentifier - && lhs.additionalHeaders == rhs.additionalHeaders - && lhs.cachePolicy == rhs.cachePolicy - && lhs.operation.queryDocument == rhs.operation.queryDocument + lhs.graphQLEndpoint == rhs.graphQLEndpoint && + lhs.operation == rhs.operation && + lhs.additionalHeaders == rhs.additionalHeaders && + lhs.cachePolicy == rhs.cachePolicy && + lhs.contextIdentifier == rhs.contextIdentifier } } diff --git a/Sources/Apollo/HTTPResponse.swift b/Sources/ApolloPGATOUR/HTTPResponse.swift similarity index 67% rename from Sources/Apollo/HTTPResponse.swift rename to Sources/ApolloPGATOUR/HTTPResponse.swift index 727e0ae1a3..42c82f08e0 100644 --- a/Sources/Apollo/HTTPResponse.swift +++ b/Sources/ApolloPGATOUR/HTTPResponse.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// Data about a response received by an HTTP request. public class HTTPResponse { @@ -30,3 +33,25 @@ public class HTTPResponse { self.parsedResponse = parsedResponse } } + +// MARK: - Equatable Conformance + +extension HTTPResponse: Equatable where Operation.Data: Equatable { + public static func == (lhs: HTTPResponse, rhs: HTTPResponse) -> Bool { + lhs.httpResponse == rhs.httpResponse && + lhs.rawData == rhs.rawData && + lhs.parsedResponse == rhs.parsedResponse && + lhs.legacyResponse == rhs.legacyResponse + } +} + +// MARK: - Hashable Conformance + +extension HTTPResponse: Hashable where Operation.Data: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(httpResponse) + hasher.combine(rawData) + hasher.combine(parsedResponse) + hasher.combine(legacyResponse) + } +} diff --git a/Sources/ApolloPGATOUR/HTTPURLResponse+Helpers.swift b/Sources/ApolloPGATOUR/HTTPURLResponse+Helpers.swift new file mode 100644 index 0000000000..05f298ad45 --- /dev/null +++ b/Sources/ApolloPGATOUR/HTTPURLResponse+Helpers.swift @@ -0,0 +1,71 @@ +import Foundation + +// MARK: Status extensions +extension HTTPURLResponse { + var isSuccessful: Bool { + return (200..<300).contains(statusCode) + } +} + +// MARK: Multipart extensions +extension HTTPURLResponse { + /// Returns true if the `Content-Type` HTTP header contains the `multipart/mixed` MIME type. + var isMultipart: Bool { + return (allHeaderFields["Content-Type"] as? String)?.contains("multipart/mixed") ?? false + } + + struct MultipartHeaderComponents { + let media: String? + let boundary: String? + let `protocol`: String? + + init(media: String? = nil, boundary: String? = nil, protocol: String? = nil) { + self.media = media + self.boundary = boundary + self.protocol = `protocol` + } + } + + /// Components of the `Content-Type` header specifically related to the `multipart` media type. + var multipartHeaderComponents: MultipartHeaderComponents { + guard let contentType = allHeaderFields["Content-Type"] as? String else { + return MultipartHeaderComponents() + } + + var media: String? = nil + var boundary: String? = nil + var `protocol`: String? = nil + + for component in contentType.components(separatedBy: ";") { + let directive = component.trimmingCharacters(in: .whitespaces) + + if directive.starts(with: "multipart/") { + media = directive.components(separatedBy: "/").last + continue + } + + if directive.starts(with: "boundary=") { + if let markerEndIndex = directive.firstIndex(of: "=") { + var startIndex = directive.index(markerEndIndex, offsetBy: 1) + if directive[startIndex] == "\"" { + startIndex = directive.index(after: startIndex) + } + var endIndex = directive.index(before: directive.endIndex) + if directive[endIndex] == "\"" { + endIndex = directive.index(before: endIndex) + } + + boundary = String(directive[startIndex...endIndex]) + } + continue + } + + if directive.contains("Spec=") { + `protocol` = directive + continue + } + } + + return MultipartHeaderComponents(media: media, boundary: boundary, protocol: `protocol`) + } +} diff --git a/Sources/Apollo/InMemoryNormalizedCache.swift b/Sources/ApolloPGATOUR/InMemoryNormalizedCache.swift similarity index 97% rename from Sources/Apollo/InMemoryNormalizedCache.swift rename to Sources/ApolloPGATOUR/InMemoryNormalizedCache.swift index be9d828490..438b0f8c86 100644 --- a/Sources/Apollo/InMemoryNormalizedCache.swift +++ b/Sources/ApolloPGATOUR/InMemoryNormalizedCache.swift @@ -1,5 +1,3 @@ -import Foundation - public final class InMemoryNormalizedCache: NormalizedCache { private var records: RecordSet diff --git a/Sources/ApolloPGATOUR/InputValue+Evaluation.swift b/Sources/ApolloPGATOUR/InputValue+Evaluation.swift new file mode 100644 index 0000000000..8f74b3d3b4 --- /dev/null +++ b/Sources/ApolloPGATOUR/InputValue+Evaluation.swift @@ -0,0 +1,85 @@ +#if !COCOAPODS +import ApolloAPI +#endif +import Foundation + +/// A global function that formats the the cache key for a field on an object. +/// +/// `CacheKeyForField` represents the *key for a single field on an object* in a ``NormalizedCache``. +/// **This is not the cache key that represents an individual entity in the cache.** +/// +/// - Parameters: +/// - fieldName: The name of the field to return a cache key for. +/// - arguments: The list of arguments used to compute the cache key. +/// - Returns: A formatted `String` to be used as the key for the field on an object in a +/// ``NormalizedCache``. +func CacheKeyForField(named fieldName: String, arguments: JSONObject) -> String { + let argumentsKey = orderIndependentKey(for: arguments) + return argumentsKey.isEmpty ? fieldName : "\(fieldName)(\(argumentsKey))" +} + +fileprivate func orderIndependentKey(for object: JSONObject) -> String { + return object.sorted { $0.key < $1.key }.map { + switch $0.value { + case let object as JSONObject: + return "[\($0.key):\(orderIndependentKey(for: object))]" + case let array as [JSONObject]: + return "\($0.key):[\(array.map { orderIndependentKey(for: $0) }.joined(separator: ","))]" + case let array as [JSONValue]: + return "\($0.key):[\(array.map { String(describing: $0.base) }.joined(separator: ", "))]" + case is NSNull: + return "\($0.key):null" + default: + return "\($0.key):\($0.value.base)" + } + }.joined(separator: ",") +} + +extension Selection.Field { + public func cacheKey(with variables: GraphQLOperation.Variables?) throws -> String { + if let arguments = arguments { + let argumentValues = try InputValue.evaluate(arguments, with: variables) + return CacheKeyForField(named: name, arguments: argumentValues) + } else { + return name + } + } +} + +extension InputValue { + private func evaluate(with variables: GraphQLOperation.Variables?) throws -> JSONValue? { + switch self { + case let .variable(name): + guard let value = variables?[name] else { + throw GraphQLError("Variable \"\(name)\" was not provided.") + } + return value._jsonEncodableValue?._jsonValue + + case let .scalar(value): + return value._jsonValue + + case let .list(array): + return try InputValue.evaluate(array, with: variables) + + case let .object(dictionary): + return try InputValue.evaluate(dictionary, with: variables) + + case .null: + return NSNull() + } + } + + fileprivate static func evaluate( + _ values: [InputValue], + with variables: GraphQLOperation.Variables? + ) throws -> [JSONValue] { + try values.compactMap { try $0.evaluate(with: variables) } + } + + fileprivate static func evaluate( + _ values: [String: InputValue], + with variables: GraphQLOperation.Variables? + ) throws -> JSONObject { + try values.compactMapValues { try $0.evaluate(with: variables) } + } +} diff --git a/Sources/Apollo/InterceptorProvider.swift b/Sources/ApolloPGATOUR/InterceptorProvider.swift similarity index 92% rename from Sources/Apollo/InterceptorProvider.swift rename to Sources/ApolloPGATOUR/InterceptorProvider.swift index fefbc5913b..c2ec81ff88 100644 --- a/Sources/Apollo/InterceptorProvider.swift +++ b/Sources/ApolloPGATOUR/InterceptorProvider.swift @@ -1,4 +1,6 @@ -import Foundation +#if !COCOAPODS +import ApolloAPI +#endif // MARK: - Basic protocol @@ -8,7 +10,7 @@ public protocol InterceptorProvider { /// Creates a new array of interceptors when called /// /// - Parameter operation: The operation to provide interceptors for - func interceptors(for operation: Operation) -> [ApolloInterceptor] + func interceptors(for operation: Operation) -> [any ApolloInterceptor] /// Provides an additional error interceptor for any additional handling of errors /// before returning to the UI, such as logging. diff --git a/Sources/Apollo/RequestChain.swift b/Sources/ApolloPGATOUR/InterceptorRequestChain.swift similarity index 57% rename from Sources/Apollo/RequestChain.swift rename to Sources/ApolloPGATOUR/InterceptorRequestChain.swift index 37cbd1ac4d..df6315e78f 100644 --- a/Sources/Apollo/RequestChain.swift +++ b/Sources/ApolloPGATOUR/InterceptorRequestChain.swift @@ -1,50 +1,57 @@ import Foundation #if !COCOAPODS -import ApolloUtils +import ApolloAPI #endif /// A chain that allows a single network request to be created and executed. -public class RequestChain: Cancellable { - +final public class InterceptorRequestChain: Cancellable, RequestChain { + public enum ChainError: Error, LocalizedError { case invalidIndex(chain: RequestChain, index: Int) case noInterceptors - + case unknownInterceptor(id: String) + public var errorDescription: String? { switch self { case .noInterceptors: return "No interceptors were provided to this chain. This is a developer error." case .invalidIndex(_, let index): return "`proceedAsync` was called for index \(index), which is out of bounds of the receiver for this chain. Double-check the order of your interceptors." + case let .unknownInterceptor(id): + return "`proceedAsync` was called by unknown interceptor \(id)." } } } - - private let interceptors: [ApolloInterceptor] + + private let interceptors: [any ApolloInterceptor] + private let callbackQueue: DispatchQueue + + private var interceptorIndexes: [String: Int] = [:] private var currentIndex: Int - private var callbackQueue: DispatchQueue - private var isCancelled = Atomic(false) - - /// Checks the underlying value of `isCancelled`. Set up like this for better readability in `guard` statements - public var isNotCancelled: Bool { - !self.isCancelled.value - } - + + @Atomic public var isCancelled: Bool = false /// Something which allows additional error handling to occur when some kind of error has happened. public var additionalErrorHandler: ApolloErrorInterceptor? - + /// Creates a chain with the given interceptor array. /// /// - Parameters: /// - interceptors: The array of interceptors to use. - /// - callbackQueue: The `DispatchQueue` to call back on when an error or result occurs. Defaults to `.main`. - public init(interceptors: [ApolloInterceptor], - callbackQueue: DispatchQueue = .main) { + /// - callbackQueue: The `DispatchQueue` to call back on when an error or result occurs. + /// Defaults to `.main`. + public init( + interceptors: [any ApolloInterceptor], + callbackQueue: DispatchQueue = .main + ) { self.interceptors = interceptors self.callbackQueue = callbackQueue self.currentIndex = 0 + + for (index, interceptor) in interceptors.enumerated() { + self.interceptorIndexes[interceptor.id] = index + } } - + /// Kicks off the request from the beginning of the interceptor array. /// /// - Parameters: @@ -52,21 +59,48 @@ public class RequestChain: Cancellable { /// - completion: The completion closure to call when the request has completed. public func kickoff( request: HTTPRequest, - completion: @escaping (Result, Error>) -> Void) { + completion: @escaping (Result, Error>) -> Void + ) { assert(self.currentIndex == 0, "The interceptor index should be zero when calling this method") guard let firstInterceptor = self.interceptors.first else { - handleErrorAsync(ChainError.noInterceptors, - request: request, - response: nil, - completion: completion) + handleErrorAsync( + ChainError.noInterceptors, + request: request, + response: nil, + completion: completion + ) return } - - firstInterceptor.interceptAsync(chain: self, - request: request, - response: nil, - completion: completion) + + firstInterceptor.interceptAsync( + chain: self, + request: request, + response: nil, + completion: completion + ) + } + + /// Proceeds to the next interceptor in the array. + /// + /// - Parameters: + /// - request: The in-progress request object + /// - response: [optional] The in-progress response object, if received yet + /// - completion: The completion closure to call when data has been processed and should be + /// returned to the UI. + public func proceedAsync( + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) { + let nextIndex = self.currentIndex + 1 + + proceedAsync( + interceptorIndex: nextIndex, + request: request, + response: response, + completion: completion + ) } /// Proceeds to the next interceptor in the array. @@ -74,50 +108,88 @@ public class RequestChain: Cancellable { /// - Parameters: /// - request: The in-progress request object /// - response: [optional] The in-progress response object, if received yet - /// - completion: The completion closure to call when data has been processed and should be returned to the UI. + /// - interceptor: The interceptor that has completed processing and is ready to pass control + /// on to the next interceptor in the chain. + /// - completion: The completion closure to call when data has been processed and should be + /// returned to the UI. public func proceedAsync( request: HTTPRequest, response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - guard self.isNotCancelled else { + interceptor: any ApolloInterceptor, + completion: @escaping (Result, Error>) -> Void + ) { + guard let currentIndex = interceptorIndexes[interceptor.id] else { + self.handleErrorAsync( + ChainError.unknownInterceptor(id: interceptor.id), + request: request, + response: response, + completion: completion + ) + return + } + + let nextIndex = currentIndex + 1 + + proceedAsync( + interceptorIndex: nextIndex, + request: request, + response: response, + completion: completion + ) + } + + private func proceedAsync( + interceptorIndex: Int, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) { + guard !self.isCancelled else { // Do not proceed, this chain has been cancelled. return } - - let nextIndex = self.currentIndex + 1 - if self.interceptors.indices.contains(nextIndex) { - self.currentIndex = nextIndex - let interceptor = self.interceptors[self.currentIndex] - - interceptor.interceptAsync(chain: self, - request: request, - response: response, - completion: completion) + + if self.interceptors.indices.contains(interceptorIndex) { + self.currentIndex = interceptorIndex + let interceptor = self.interceptors[interceptorIndex] + + interceptor.interceptAsync( + chain: self, + request: request, + response: response, + completion: completion + ) + } else { if let result = response?.parsedResponse { // We got to the end of the chain with a parsed response. Yay! Return it. - self.returnValueAsync(for: request, - value: result, - completion: completion) + self.returnValueAsync( + for: request, + value: result, + completion: completion + ) + } else { // We got to the end of the chain and no parsed response is there, there needs to be more processing. - self.handleErrorAsync(ChainError.invalidIndex(chain: self, index: nextIndex), - request: request, - response: response, - completion: completion) + self.handleErrorAsync( + ChainError.invalidIndex(chain: self, index: interceptorIndex), + request: request, + response: response, + completion: completion + ) } } } - + /// Cancels the entire chain of interceptors. public func cancel() { - guard self.isNotCancelled else { + guard !self.isCancelled else { // Do not proceed, this chain has been cancelled. return } - - self.isCancelled.mutate { $0 = true } - + + self.$isCancelled.mutate { $0 = true } + // If an interceptor adheres to `Cancellable`, it should have its in-flight work cancelled as well. for interceptor in self.interceptors { if let cancellableInterceptor = interceptor as? Cancellable { @@ -125,7 +197,7 @@ public class RequestChain: Cancellable { } } } - + /// Restarts the request starting from the first interceptor. /// /// - Parameters: @@ -133,18 +205,19 @@ public class RequestChain: Cancellable { /// - completion: The completion closure to call when the request has completed. public func retry( request: HTTPRequest, - completion: @escaping (Result, Error>) -> Void) { - - guard self.isNotCancelled else { + completion: @escaping (Result, Error>) -> Void + ) { + guard !self.isCancelled else { // Don't retry something that's been cancelled. return } - + self.currentIndex = 0 self.kickoff(request: request, completion: completion) } - - /// Handles the error by returning it on the appropriate queue, or by applying an additional error interceptor if one has been provided. + + /// Handles the error by returning it on the appropriate queue, or by applying an additional + /// error interceptor if one has been provided. /// /// - Parameters: /// - error: The error to handle @@ -155,8 +228,9 @@ public class RequestChain: Cancellable { _ error: Error, request: HTTPRequest, response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - guard self.isNotCancelled else { + completion: @escaping (Result, Error>) -> Void + ) { + guard !self.isCancelled else { return } @@ -169,13 +243,18 @@ public class RequestChain: Cancellable { // Capture callback queue so it doesn't get reaped when `self` is dealloced let callbackQueue = self.callbackQueue - additionalHandler.handleErrorAsync(error: error, chain: self, request: request, response: response) { result in + additionalHandler.handleErrorAsync( + error: error, + chain: self, + request: request, + response: response + ) { result in callbackQueue.async { completion(result) } } } - + /// Handles a resulting value by returning it on the appropriate queue. /// /// - Parameters: @@ -185,12 +264,12 @@ public class RequestChain: Cancellable { public func returnValueAsync( for request: HTTPRequest, value: GraphQLResult, - completion: @escaping (Result, Error>) -> Void) { - - guard self.isNotCancelled else { + completion: @escaping (Result, Error>) -> Void + ) { + guard !self.isCancelled else { return } - + self.callbackQueue.async { completion(.success(value)) } diff --git a/Sources/Apollo/JSONRequest.swift b/Sources/ApolloPGATOUR/JSONRequest.swift similarity index 64% rename from Sources/Apollo/JSONRequest.swift rename to Sources/ApolloPGATOUR/JSONRequest.swift index d59319664f..9c54529a72 100644 --- a/Sources/Apollo/JSONRequest.swift +++ b/Sources/ApolloPGATOUR/JSONRequest.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// A request which sends JSON related to a GraphQL operation. open class JSONRequest: HTTPRequest { @@ -14,8 +17,8 @@ open class JSONRequest: HTTPRequest { } } - private var _body: GraphQLMap? - public var body: GraphQLMap { + private var _body: JSONEncodableDictionary? + public var body: JSONEncodableDictionary { if _body == nil { _body = createBody() } @@ -34,46 +37,49 @@ open class JSONRequest: HTTPRequest { /// - clientVersion: The version of the client to send with the `"apollographql-client-version"` header /// - additionalHeaders: Any additional headers you wish to add by default to this request /// - cachePolicy: The `CachePolicy` to use for this request. + /// - context: [optional] A context that is being passed through the request chain. Defaults to `nil`. /// - autoPersistQueries: `true` if Auto-Persisted Queries should be used. Defaults to `false`. /// - useGETForQueries: `true` if Queries should use `GET` instead of `POST` for HTTP requests. Defaults to `false`. /// - useGETForPersistedQueryRetry: `true` if when an Auto-Persisted query is retried, it should use `GET` instead of `POST` to send the query. Defaults to `false`. /// - requestBodyCreator: An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation. - public init(operation: Operation, - graphQLEndpoint: URL, - contextIdentifier: UUID? = nil, - clientName: String, - clientVersion: String, - additionalHeaders: [String: String] = [:], - cachePolicy: CachePolicy = .default, - autoPersistQueries: Bool = false, - useGETForQueries: Bool = false, - useGETForPersistedQueryRetry: Bool = false, - requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator()) { + public init( + operation: Operation, + graphQLEndpoint: URL, + contextIdentifier: UUID? = nil, + clientName: String, + clientVersion: String, + additionalHeaders: [String: String] = [:], + cachePolicy: CachePolicy = .default, + context: RequestContext? = nil, + autoPersistQueries: Bool = false, + useGETForQueries: Bool = false, + useGETForPersistedQueryRetry: Bool = false, + requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator() + ) { self.autoPersistQueries = autoPersistQueries self.useGETForQueries = useGETForQueries self.useGETForPersistedQueryRetry = useGETForPersistedQueryRetry self.requestBodyCreator = requestBodyCreator - - super.init(graphQLEndpoint: graphQLEndpoint, - operation: operation, - contextIdentifier: contextIdentifier, - contentType: "application/json", - clientName: clientName, - clientVersion: clientVersion, - additionalHeaders: additionalHeaders, - cachePolicy: cachePolicy) - } - - open var sendOperationIdentifier: Bool { - self.operation.operationIdentifier != nil + + super.init( + graphQLEndpoint: graphQLEndpoint, + operation: operation, + contextIdentifier: contextIdentifier, + contentType: "application/json", + clientName: clientName, + clientVersion: clientVersion, + additionalHeaders: additionalHeaders, + cachePolicy: cachePolicy, + context: context + ) } - + open override func toURLRequest() throws -> URLRequest { var request = try super.toURLRequest() let useGetMethod: Bool let body = self.body - switch operation.operationType { + switch Operation.operationType { case .query: if isPersistedQueryRetry { useGetMethod = self.useGETForPersistedQueryRetry @@ -110,10 +116,10 @@ open class JSONRequest: HTTPRequest { return request } - private func createBody() -> GraphQLMap { + private func createBody() -> JSONEncodableDictionary { let sendQueryDocument: Bool let autoPersistQueries: Bool - switch operation.operationType { + switch Operation.operationType { case .query: if isPersistedQueryRetry { sendQueryDocument = true @@ -135,11 +141,35 @@ open class JSONRequest: HTTPRequest { autoPersistQueries = false } - let body = self.requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: self.sendOperationIdentifier, - sendQueryDocument: sendQueryDocument, - autoPersistQuery: autoPersistQueries) + let body = self.requestBodyCreator.requestBody( + for: operation, + sendQueryDocument: sendQueryDocument, + autoPersistQuery: autoPersistQueries + ) return body } + + // MARK: - Equtable/Hashable Conformance + + public static func == (lhs: JSONRequest, rhs: JSONRequest) -> Bool { + lhs as HTTPRequest == rhs as HTTPRequest && + type(of: lhs.requestBodyCreator) == type(of: rhs.requestBodyCreator) && + lhs.autoPersistQueries == rhs.autoPersistQueries && + lhs.useGETForQueries == rhs.useGETForQueries && + lhs.useGETForPersistedQueryRetry == rhs.useGETForPersistedQueryRetry && + lhs.isPersistedQueryRetry == rhs.isPersistedQueryRetry && + lhs.body._jsonObject == rhs.body._jsonObject + } + + public override func hash(into hasher: inout Hasher) { + super.hash(into: &hasher) + hasher.combine("\(type(of: requestBodyCreator))") + hasher.combine(autoPersistQueries) + hasher.combine(useGETForQueries) + hasher.combine(useGETForPersistedQueryRetry) + hasher.combine(isPersistedQueryRetry) + hasher.combine(body._jsonObject) + } + } diff --git a/Sources/Apollo/JSONResponseParsingInterceptor.swift b/Sources/ApolloPGATOUR/JSONResponseParsingInterceptor.swift similarity index 69% rename from Sources/Apollo/JSONResponseParsingInterceptor.swift rename to Sources/ApolloPGATOUR/JSONResponseParsingInterceptor.swift index ff84fcad52..6e35ce917c 100644 --- a/Sources/Apollo/JSONResponseParsingInterceptor.swift +++ b/Sources/ApolloPGATOUR/JSONResponseParsingInterceptor.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// An interceptor which parses JSON response data into a `GraphQLResult` and attaches it to the `HTTPResponse`. public struct JSONResponseParsingInterceptor: ApolloInterceptor { @@ -25,14 +28,11 @@ public struct JSONResponseParsingInterceptor: ApolloInterceptor { } } } - - public let cacheKeyForObject: CacheKeyForObject? - /// Designated Initializer - public init(cacheKeyForObject: CacheKeyForObject? = nil) { - self.cacheKeyForObject = cacheKeyForObject - } - + public var id: String = UUID().uuidString + + public init() { } + public func interceptAsync( chain: RequestChain, request: HTTPRequest, @@ -40,16 +40,19 @@ public struct JSONResponseParsingInterceptor: ApolloInterceptor { completion: @escaping (Result, Error>) -> Void ) { guard let createdResponse = response else { - chain.handleErrorAsync(JSONResponseParsingError.noResponseToParse, - request: request, - response: response, - completion: completion) + chain.handleErrorAsync( + JSONResponseParsingError.noResponseToParse, + request: request, + response: response, + completion: completion + ) return } do { - guard let body = try? JSONSerializationFormat - .deserialize(data: createdResponse.rawData) as? JSONObject else { + guard + let body = try? JSONSerializationFormat.deserialize(data: createdResponse.rawData) as? JSONObject + else { throw JSONResponseParsingError.couldNotParseToJSON(data: createdResponse.rawData) } @@ -59,15 +62,20 @@ public struct JSONResponseParsingInterceptor: ApolloInterceptor { let result = try parseResult(from: graphQLResponse, cachePolicy: request.cachePolicy) createdResponse.parsedResponse = result - chain.proceedAsync(request: request, - response: createdResponse, - completion: completion) + chain.proceedAsync( + request: request, + response: createdResponse, + interceptor: self, + completion: completion + ) } catch { - chain.handleErrorAsync(error, - request: request, - response: createdResponse, - completion: completion) + chain.handleErrorAsync( + error, + request: request, + response: createdResponse, + completion: completion + ) } } @@ -80,7 +88,7 @@ public struct JSONResponseParsingInterceptor: ApolloInterceptor { // There is no cache, so we don't need to get any info on dependencies. Use fast parsing. return try response.parseResultFast() default: - let (parsedResult, _) = try response.parseResult(cacheKeyForObject: self.cacheKeyForObject) + let (parsedResult, _) = try response.parseResult() return parsedResult } } diff --git a/Sources/Apollo/JSONSerialization+Sorting.swift b/Sources/ApolloPGATOUR/JSONSerialization+Sorting.swift similarity index 100% rename from Sources/Apollo/JSONSerialization+Sorting.swift rename to Sources/ApolloPGATOUR/JSONSerialization+Sorting.swift diff --git a/Sources/Apollo/JSONSerializationFormat.swift b/Sources/ApolloPGATOUR/JSONSerializationFormat.swift similarity index 61% rename from Sources/Apollo/JSONSerializationFormat.swift rename to Sources/ApolloPGATOUR/JSONSerializationFormat.swift index 0c2789517e..7f62161ef1 100644 --- a/Sources/Apollo/JSONSerializationFormat.swift +++ b/Sources/ApolloPGATOUR/JSONSerializationFormat.swift @@ -1,11 +1,18 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif public final class JSONSerializationFormat { public class func serialize(value: JSONEncodable) throws -> Data { - return try JSONSerialization.sortedData(withJSONObject: value.jsonValue) + return try JSONSerialization.sortedData(withJSONObject: value._jsonValue) + } + + public class func serialize(value: JSONObject) throws -> Data { + return try JSONSerialization.sortedData(withJSONObject: value) } public class func deserialize(data: Data) throws -> JSONValue { - return try JSONSerialization.jsonObject(with: data, options: []) + return try JSONSerialization.jsonObject(with: data, options: []) as! AnyHashable } } diff --git a/Sources/Apollo/MaxRetryInterceptor.swift b/Sources/ApolloPGATOUR/MaxRetryInterceptor.swift similarity index 70% rename from Sources/Apollo/MaxRetryInterceptor.swift rename to Sources/ApolloPGATOUR/MaxRetryInterceptor.swift index 986690c201..ed25961abb 100644 --- a/Sources/Apollo/MaxRetryInterceptor.swift +++ b/Sources/ApolloPGATOUR/MaxRetryInterceptor.swift @@ -1,10 +1,15 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// An interceptor to enforce a maximum number of retries of any `HTTPRequest` public class MaxRetryInterceptor: ApolloInterceptor { private let maxRetries: Int private var hitCount = 0 + + public var id: String = UUID().uuidString public enum RetryError: Error, LocalizedError { case hitMaxRetryCount(count: Int, operationName: String) @@ -30,18 +35,27 @@ public class MaxRetryInterceptor: ApolloInterceptor { response: HTTPResponse?, completion: @escaping (Result, Error>) -> Void) { guard self.hitCount <= self.maxRetries else { - let error = RetryError.hitMaxRetryCount(count: self.maxRetries, - operationName: request.operation.operationName) - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) + let error = RetryError.hitMaxRetryCount( + count: self.maxRetries, + operationName: Operation.operationName + ) + + chain.handleErrorAsync( + error, + request: request, + response: response, + completion: completion + ) + return } self.hitCount += 1 - chain.proceedAsync(request: request, - response: response, - completion: completion) + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) } } diff --git a/Sources/Apollo/MultipartFormData.swift b/Sources/ApolloPGATOUR/MultipartFormData.swift similarity index 93% rename from Sources/Apollo/MultipartFormData.swift rename to Sources/ApolloPGATOUR/MultipartFormData.swift index f358c5c72f..f790ae205a 100644 --- a/Sources/Apollo/MultipartFormData.swift +++ b/Sources/ApolloPGATOUR/MultipartFormData.swift @@ -1,7 +1,7 @@ import Foundation /// A helper for building out multi-part form data for upload -public class MultipartFormData { +public final class MultipartFormData { enum FormDataError: Error, LocalizedError { case encodingStringToDataFailed(_ string: String) @@ -145,10 +145,24 @@ public class MultipartFormData { } } +// MARK: - Hashable Conformance + +extension MultipartFormData: Hashable { + public static func == (lhs: MultipartFormData, rhs: MultipartFormData) -> Bool { + lhs.boundary == rhs.boundary && + lhs.bodyParts == rhs.bodyParts + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(boundary) + hasher.combine(bodyParts) + } +} + /// MARK: - BodyPart /// A structure representing a single part of multi-part form data. -fileprivate struct BodyPart { +fileprivate struct BodyPart: Hashable { let name: String let inputStream: InputStream let contentLength: UInt64 diff --git a/Sources/ApolloPGATOUR/MultipartResponseDeferParser.swift b/Sources/ApolloPGATOUR/MultipartResponseDeferParser.swift new file mode 100644 index 0000000000..f39a9e05e7 --- /dev/null +++ b/Sources/ApolloPGATOUR/MultipartResponseDeferParser.swift @@ -0,0 +1,17 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +struct MultipartResponseDeferParser: MultipartResponseSpecificationParser { + static let protocolSpec: String = "deferSpec=20220824" + + static func parse( + data: Data, + boundary: String, + dataHandler: ((Data) -> Void), + errorHandler: ((Error) -> Void) + ) { + // TODO: Will be implemented in #3146 + } +} diff --git a/Sources/ApolloPGATOUR/MultipartResponseParsingInterceptor.swift b/Sources/ApolloPGATOUR/MultipartResponseParsingInterceptor.swift new file mode 100644 index 0000000000..0c20e274b6 --- /dev/null +++ b/Sources/ApolloPGATOUR/MultipartResponseParsingInterceptor.swift @@ -0,0 +1,121 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +/// Parses multipart response data into chunks and forwards each on to the next interceptor. +public struct MultipartResponseParsingInterceptor: ApolloInterceptor { + + public enum ParsingError: Error, LocalizedError, Equatable { + case noResponseToParse + case cannotParseResponse + + public var errorDescription: String? { + switch self { + case .noResponseToParse: + return "There is no response to parse. Check the order of your interceptors." + case .cannotParseResponse: + return "The response data could not be parsed." + } + } + } + + private static let responseParsers: [String: MultipartResponseSpecificationParser.Type] = [ + MultipartResponseSubscriptionParser.protocolSpec: MultipartResponseSubscriptionParser.self + ] + + public var id: String = UUID().uuidString + + public init() { } + + public func interceptAsync( + chain: RequestChain, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation { + + guard let response else { + chain.handleErrorAsync( + ParsingError.noResponseToParse, + request: request, + response: response, + completion: completion + ) + return + } + + if !response.httpResponse.isMultipart { + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + return + } + + let multipartComponents = response.httpResponse.multipartHeaderComponents + + guard + let boundary = multipartComponents.boundary, + let `protocol` = multipartComponents.protocol, + let parser = Self.responseParsers[`protocol`] + else { + chain.handleErrorAsync( + ParsingError.cannotParseResponse, + request: request, + response: response, + completion: completion + ) + return + } + + let dataHandler: ((Data) -> Void) = { data in + let response = HTTPResponse( + response: response.httpResponse, + rawData: data, + parsedResponse: nil + ) + + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) + } + + let errorHandler: ((Error) -> Void) = { parserError in + chain.handleErrorAsync( + parserError, + request: request, + response: response, + completion: completion + ) + } + + parser.parse( + data: response.rawData, + boundary: boundary, + dataHandler: dataHandler, + errorHandler: errorHandler + ) + } +} + +/// A protocol that multipart response parsers must conform to in order to be added to the list of +/// available response specification parsers. +protocol MultipartResponseSpecificationParser { + /// The specification string matching what is expected to be received in the `Content-Type` header + /// in an HTTP response. + static var protocolSpec: String { get } + + /// Function that will be called to process the response data. + static func parse( + data: Data, + boundary: String, + dataHandler: ((Data) -> Void), + errorHandler: ((Error) -> Void) + ) +} diff --git a/Sources/ApolloPGATOUR/MultipartResponseSubscriptionParser.swift b/Sources/ApolloPGATOUR/MultipartResponseSubscriptionParser.swift new file mode 100644 index 0000000000..dec316522f --- /dev/null +++ b/Sources/ApolloPGATOUR/MultipartResponseSubscriptionParser.swift @@ -0,0 +1,129 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +struct MultipartResponseSubscriptionParser: MultipartResponseSpecificationParser { + public enum ParsingError: Swift.Error, LocalizedError, Equatable { + case cannotParseResponseData + case unsupportedContentType(type: String) + case cannotParseChunkData + case irrecoverableError(message: String?) + case cannotParsePayloadData + + public var errorDescription: String? { + switch self { + case .cannotParseResponseData: + return "The response data could not be parsed." + case let .unsupportedContentType(type): + return "Unsupported content type: application/json is required but got \(type)." + case .cannotParseChunkData: + return "The chunk data could not be parsed." + case let .irrecoverableError(message): + return "An irrecoverable error occured: \(message ?? "unknown")." + case .cannotParsePayloadData: + return "The payload data could not be parsed." + } + } + } + + private enum ChunkedDataLine { + case heartbeat + case contentHeader(type: String) + case json(object: JSONObject) + case unknown + } + + static let protocolSpec: String = "subscriptionSpec=1.0" + + private static let dataLineSeparator: StaticString = "\r\n\r\n" + private static let contentTypeHeader: StaticString = "content-type:" + private static let heartbeat: StaticString = "{}" + + static func parse( + data: Data, + boundary: String, + dataHandler: ((Data) -> Void), + errorHandler: ((Error) -> Void) + ) { + guard let dataString = String(data: data, encoding: .utf8) else { + errorHandler(ParsingError.cannotParseResponseData) + return + } + + for chunk in dataString.components(separatedBy: "--\(boundary)") { + if chunk.isEmpty || chunk.isBoundaryPrefix { continue } + + for dataLine in chunk.components(separatedBy: Self.dataLineSeparator.description) { + switch (parse(dataLine: dataLine.trimmingCharacters(in: .newlines))) { + case .heartbeat: + // Periodically sent by the router - noop + continue + + case let .contentHeader(type): + guard type == "application/json" else { + errorHandler(ParsingError.unsupportedContentType(type: type)) + return + } + + case let .json(object): + if let errors = object["errors"] as? [JSONObject] { + let message = errors.first?["message"] as? String + + errorHandler(ParsingError.irrecoverableError(message: message)) + return + } + + guard let payload = object["payload"] else { + errorHandler(ParsingError.cannotParsePayloadData) + return + } + + if payload is NSNull { + // `payload` can be null such as in the case of a transport error + continue + } + + guard + let payload = payload as? JSONObject, + let data: Data = try? JSONSerializationFormat.serialize(value: payload) + else { + errorHandler(ParsingError.cannotParsePayloadData) + return + } + + dataHandler(data) + + case .unknown: + errorHandler(ParsingError.cannotParseChunkData) + } + } + } + } + + /// Parses the data line of a multipart response chunk + private static func parse(dataLine: String) -> ChunkedDataLine { + if dataLine == Self.heartbeat.description { + return .heartbeat + } + + if dataLine.starts(with: Self.contentTypeHeader.description) { + return .contentHeader(type: (dataLine.components(separatedBy: ":").last ?? dataLine) + .trimmingCharacters(in: .whitespaces) + ) + } + + if + let data = dataLine.data(using: .utf8), + let jsonObject = try? JSONSerializationFormat.deserialize(data: data) as? JSONObject + { + return .json(object: jsonObject) + } + + return .unknown + } +} + +fileprivate extension String { + var isBoundaryPrefix: Bool { self == "--" } +} diff --git a/Sources/Apollo/NetworkFetchInterceptor.swift b/Sources/ApolloPGATOUR/NetworkFetchInterceptor.swift similarity index 54% rename from Sources/Apollo/NetworkFetchInterceptor.swift rename to Sources/ApolloPGATOUR/NetworkFetchInterceptor.swift index 59f792414d..a477cf6e2b 100644 --- a/Sources/Apollo/NetworkFetchInterceptor.swift +++ b/Sources/ApolloPGATOUR/NetworkFetchInterceptor.swift @@ -1,12 +1,14 @@ import Foundation #if !COCOAPODS -import ApolloUtils +import ApolloAPI #endif /// An interceptor which actually fetches data from the network. public class NetworkFetchInterceptor: ApolloInterceptor, Cancellable { let client: URLSessionClient - private var currentTask: Atomic = Atomic(nil) + @Atomic private var currentTask: URLSessionTask? + + public var id: String = UUID().uuidString /// Designated initializer. /// @@ -25,10 +27,12 @@ public class NetworkFetchInterceptor: ApolloInterceptor, Cancellable { do { urlRequest = try request.toURLRequest() } catch { - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) + chain.handleErrorAsync( + error, + request: request, + response: response, + completion: completion + ) return } @@ -38,34 +42,45 @@ public class NetworkFetchInterceptor: ApolloInterceptor, Cancellable { } defer { - self.currentTask.mutate { $0 = nil } + if Operation.operationType != .subscription { + self.$currentTask.mutate { $0 = nil } + } } - guard chain.isNotCancelled else { + guard !chain.isCancelled else { return } switch result { case .failure(let error): - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) + chain.handleErrorAsync( + error, + request: request, + response: response, + completion: completion + ) + case .success(let (data, httpResponse)): - let response = HTTPResponse(response: httpResponse, - rawData: data, - parsedResponse: nil) - chain.proceedAsync(request: request, - response: response, - completion: completion) + let response = HTTPResponse( + response: httpResponse, + rawData: data, + parsedResponse: nil + ) + + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) } } - self.currentTask.mutate { $0 = task } + self.$currentTask.mutate { $0 = task } } public func cancel() { - guard let task = self.currentTask.value else { + guard let task = self.currentTask else { return } diff --git a/Sources/Apollo/NetworkTransport.swift b/Sources/ApolloPGATOUR/NetworkTransport.swift similarity index 90% rename from Sources/Apollo/NetworkTransport.swift rename to Sources/ApolloPGATOUR/NetworkTransport.swift index a7aadfed62..6b0cd953e8 100644 --- a/Sources/Apollo/NetworkTransport.swift +++ b/Sources/ApolloPGATOUR/NetworkTransport.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// A network transport is responsible for sending GraphQL operations to a server. public protocol NetworkTransport: AnyObject { @@ -11,12 +14,14 @@ public protocol NetworkTransport: AnyObject { /// - operation: The operation to send. /// - cachePolicy: The `CachePolicy` to use making this request. /// - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. + /// - context: [optional] A context that is being passed through the request chain. Defaults to `nil`. /// - callbackQueue: The queue to call back on with the results. Should default to `.main`. /// - completionHandler: A closure to call when a request completes. On `success` will contain the response received from the server. On `failure` will contain the error which occurred. /// - Returns: An object that can be used to cancel an in progress request. func send(operation: Operation, cachePolicy: CachePolicy, contextIdentifier: UUID?, + context: RequestContext?, callbackQueue: DispatchQueue, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable @@ -55,11 +60,11 @@ public extension NetworkTransport { /// The default client version to use when setting up the `clientVersion` property. static var defaultClientVersion: String { var version = String() - if let shortVersion = Bundle.main.apollo.shortVersion { + if let shortVersion = Bundle.main.shortVersion { version.append(shortVersion) } - if let buildNumber = Bundle.main.apollo.buildNumber { + if let buildNumber = Bundle.main.buildNumber { if version.isEmpty { version.append(buildNumber) } else { @@ -96,12 +101,14 @@ public protocol UploadingNetworkTransport: NetworkTransport { /// - Parameters: /// - operation: The operation to send /// - files: An array of `GraphQLFile` objects to send. + /// - context: [optional] A context that is being passed through the request chain. /// - callbackQueue: The queue to call back on with the results. Should default to `.main`. /// - completionHandler: The completion handler to execute when the request completes or errors /// - Returns: An object that can be used to cancel an in progress request. func upload( operation: Operation, files: [GraphQLFile], + context: RequestContext?, callbackQueue: DispatchQueue, completionHandler: @escaping (Result,Error>) -> Void) -> Cancellable } diff --git a/Sources/Apollo/NormalizedCache.swift b/Sources/ApolloPGATOUR/NormalizedCache.swift similarity index 97% rename from Sources/Apollo/NormalizedCache.swift rename to Sources/ApolloPGATOUR/NormalizedCache.swift index e81d4ef310..e72fad5275 100644 --- a/Sources/Apollo/NormalizedCache.swift +++ b/Sources/ApolloPGATOUR/NormalizedCache.swift @@ -1,6 +1,4 @@ -import Foundation - -public protocol NormalizedCache { +public protocol NormalizedCache: AnyObject { /// Loads records corresponding to the given keys. /// diff --git a/Sources/Apollo/PossiblyDeferred.swift b/Sources/ApolloPGATOUR/PossiblyDeferred.swift similarity index 67% rename from Sources/Apollo/PossiblyDeferred.swift rename to Sources/ApolloPGATOUR/PossiblyDeferred.swift index f8905b16d5..45d6bd2e0d 100644 --- a/Sources/Apollo/PossiblyDeferred.swift +++ b/Sources/ApolloPGATOUR/PossiblyDeferred.swift @@ -1,5 +1,3 @@ -import Foundation - /// Lazily evaluates an array of possibly deferred values. /// - Parameters: /// - elements: An array of possibly deferred values @@ -10,6 +8,38 @@ func lazilyEvaluateAll(_ elements: [PossiblyDeferred]) -> Possibly } } +/// Lazily evaluates an array of possibly deferred optional values, filtering out any nil values. +/// - Parameters: +/// - elements: An array of possibly deferred values +/// - Returns: A deferred array with the result of evaluating each element. +func compactLazilyEvaluateAll(_ elements: [PossiblyDeferred]) -> PossiblyDeferred<[Value]> { + return .deferred { + try elements.compactMap { try $0.get() } + } +} + +extension Sequence { + + /// A `flatMap` that defers executing the transformation, producing a `PossiblyDeferred` result + /// that will contain the transformed values when `get()` is called. + /// + /// - Parameter transform: A closure that takes the elements of the sequence and returns a + /// `PossiblyDeferred` instance for each element. + /// - Returns: A `PossiblyDeferred` instance with the result of evaluating `transform` + /// on each of the elements of the receiver. + func deferredFlatMap(_ transform: @escaping (Element) throws -> PossiblyDeferred) -> PossiblyDeferred<[NewValue]> { + do { + let deferredTransforms = try self.map { element in + try transform(element) + } + return lazilyEvaluateAll(deferredTransforms) + + } catch { + return .immediate(.failure(error)) + } + } +} + /// A possibly deferred value that represents either an immediate success or failure value, or a deferred /// value that is evaluated lazily when needed by invoking a throwing closure. enum PossiblyDeferred { @@ -26,6 +56,19 @@ enum PossiblyDeferred { init(_ body: () throws -> Value) { self = .immediate(Result(catching: body)) } + + /// Creates a new immediate result by evaluating a throwing closure, capturing the + /// returned value as a success, or any thrown error as a failure. + /// + /// - Parameter body: A throwing closure to evaluate. + @_disfavoredOverload + init(_ body: () throws -> PossiblyDeferred) { + do { + self = try body() + } catch { + self = .immediate(.failure(error)) + } + } /// Returns the success value as a throwing expression, evaluating a deferred value /// if needed. @@ -59,7 +102,7 @@ enum PossiblyDeferred { } } - /// Returns a new possibly deferred result, mapping any success value using the given + /// Returns a new possibly deferred result, mapping any success value using the given /// transformation and unwrapping the produced result. /// /// Use this method to avoid a nested result when your transformation @@ -68,7 +111,7 @@ enum PossiblyDeferred { /// - Parameter transform: A closure that takes the success value of the /// instance. /// - Returns: A `PossiblyDeferred` instance with the result of evaluating `transform` - /// as the new success value if this instance represents a failure. + /// as the new success value if this instance represents a success. func flatMap(_ transform: @escaping (Value) -> PossiblyDeferred) -> PossiblyDeferred { switch self { case .immediate(let result): @@ -105,4 +148,6 @@ enum PossiblyDeferred { } } } + + } diff --git a/Sources/Apollo/Record.swift b/Sources/ApolloPGATOUR/Record.swift similarity index 88% rename from Sources/Apollo/Record.swift rename to Sources/ApolloPGATOUR/Record.swift index 7551a5fe7a..6145ab0351 100644 --- a/Sources/Apollo/Record.swift +++ b/Sources/ApolloPGATOUR/Record.swift @@ -2,10 +2,10 @@ public typealias CacheKey = String /// A cache record. -public struct Record { +public struct Record: Hashable { public let key: CacheKey - public typealias Value = Any + public typealias Value = AnyHashable public typealias Fields = [CacheKey: Value] public private(set) var fields: Fields diff --git a/Sources/Apollo/RecordSet.swift b/Sources/ApolloPGATOUR/RecordSet.swift similarity index 91% rename from Sources/Apollo/RecordSet.swift rename to Sources/ApolloPGATOUR/RecordSet.swift index eced9d8a19..f1855bf4e1 100644 --- a/Sources/Apollo/RecordSet.swift +++ b/Sources/ApolloPGATOUR/RecordSet.swift @@ -1,5 +1,5 @@ /// A set of cache records. -public struct RecordSet { +public struct RecordSet: Hashable { public private(set) var storage: [CacheKey: Record] = [:] public init(records: S) where S.Iterator.Element == Record { @@ -59,7 +59,7 @@ public struct RecordSet { var changedKeys: Set = Set() for (key, value) in record.fields { - if let oldValue = oldRecord.fields[key], JSONValueMatcher.equals(oldValue, value) { + if let oldValue = oldRecord.fields[key], oldValue == value { continue } oldRecord[key] = value @@ -86,6 +86,12 @@ extension RecordSet: CustomStringConvertible { } } +extension RecordSet: CustomDebugStringConvertible { + public var debugDescription: String { + return description + } +} + extension RecordSet: CustomPlaygroundDisplayConvertible { public var playgroundDescription: Any { return description diff --git a/Sources/ApolloPGATOUR/RequestBodyCreator.swift b/Sources/ApolloPGATOUR/RequestBodyCreator.swift new file mode 100644 index 0000000000..b9d36bed59 --- /dev/null +++ b/Sources/ApolloPGATOUR/RequestBodyCreator.swift @@ -0,0 +1,62 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +public protocol RequestBodyCreator { + /// Creates a `JSONEncodableDictionary` out of the passed-in operation + /// + /// - Parameters: + /// - operation: The operation to use + /// - sendQueryDocument: Whether or not to send the full query document. Should default to `true`. + /// - autoPersistQuery: Whether to use auto-persisted query information. Should default to `false`. + /// - Returns: The created `JSONEncodableDictionary` + func requestBody( + for operation: Operation, + sendQueryDocument: Bool, + autoPersistQuery: Bool + ) -> JSONEncodableDictionary +} + +// MARK: - Default Implementation + +extension RequestBodyCreator { + + public func requestBody( + for operation: Operation, + sendQueryDocument: Bool, + autoPersistQuery: Bool + ) -> JSONEncodableDictionary { + var body: JSONEncodableDictionary = [ + "operationName": Operation.operationName, + ] + + if let variables = operation.__variables { + body["variables"] = variables._jsonEncodableObject + } + + if sendQueryDocument { + guard let document = Operation.definition?.queryDocument else { + preconditionFailure("To send query documents, Apollo types must be generated with `OperationDefinition`s.") + } + body["query"] = document + } + + if autoPersistQuery { + guard let operationIdentifier = Operation.operationIdentifier else { + preconditionFailure("To enable `autoPersistQueries`, Apollo types must be generated with operationIdentifiers") + } + + body["extensions"] = [ + "persistedQuery" : ["sha256Hash": operationIdentifier, "version": 1] + ] + } + + return body + } +} + +// Helper struct to create requests independently of HTTP operations. +public struct ApolloRequestBodyCreator: RequestBodyCreator { + // Internal init methods cannot be used in public methods + public init() { } +} diff --git a/Sources/ApolloPGATOUR/RequestChain.swift b/Sources/ApolloPGATOUR/RequestChain.swift new file mode 100644 index 0000000000..a0034f6328 --- /dev/null +++ b/Sources/ApolloPGATOUR/RequestChain.swift @@ -0,0 +1,46 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +public protocol RequestChain: Cancellable { + func kickoff( + request: HTTPRequest, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation + + @available(*, deprecated, renamed: "proceedAsync(request:response:interceptor:completion:)") + func proceedAsync( + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation + + func proceedAsync( + request: HTTPRequest, + response: HTTPResponse?, + interceptor: any ApolloInterceptor, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation + + func cancel() + + func retry( + request: HTTPRequest, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation + + func handleErrorAsync( + _ error: Error, + request: HTTPRequest, + response: HTTPResponse?, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation + + func returnValueAsync( + for request: HTTPRequest, + value: GraphQLResult, + completion: @escaping (Result, Error>) -> Void + ) where Operation : GraphQLOperation + + var isCancelled: Bool { get } +} diff --git a/Sources/Apollo/RequestChainNetworkTransport.swift b/Sources/ApolloPGATOUR/RequestChainNetworkTransport.swift similarity index 62% rename from Sources/Apollo/RequestChainNetworkTransport.swift rename to Sources/ApolloPGATOUR/RequestChainNetworkTransport.swift index 8a07bff866..fd9199526a 100644 --- a/Sources/Apollo/RequestChainNetworkTransport.swift +++ b/Sources/ApolloPGATOUR/RequestChainNetworkTransport.swift @@ -1,34 +1,52 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// An implementation of `NetworkTransport` which creates a `RequestChain` object /// for each item sent through it. open class RequestChainNetworkTransport: NetworkTransport { - + + /// The interceptor provider to use when constructing a request chain let interceptorProvider: InterceptorProvider /// The GraphQL endpoint URL to use. public let endpointURL: URL - - /// Any additional headers that should be automatically added to every request. + + /// Any additional HTTP headers that should be added to **every** request, such as an API key or a language setting. + /// + /// If a header should only be added to _certain_ requests, or if its value might differ between requests, + /// you should add that header in an interceptor instead. + /// + /// Defaults to an empty dictionary. public private(set) var additionalHeaders: [String: String] /// Set to `true` if Automatic Persisted Queries should be used to send a query hash instead of the full query body by default. public let autoPersistQueries: Bool - /// Set to `true` if you want to use `GET` instead of `POST` for queries, for example to take advantage of a CDN. + /// Set to `true` if you want to use `GET` instead of `POST` for queries. + /// + /// This can improve performance if your GraphQL server uses a CDN (Content Delivery Network) + /// to cache the results of queries that rarely change. + /// + /// Mutation operations always use POST, even when this is `false` + /// + /// Defaults to `false`. public let useGETForQueries: Bool /// Set to `true` to use `GET` instead of `POST` for a retry of a persisted query. public let useGETForPersistedQueryRetry: Bool - /// The `RequestBodyCreator` object to use to build your `URLRequest`. + /// The `RequestBodyCreator` object used to build your `URLRequest`. + /// + /// Defaults to an ``ApolloRequestBodyCreator`` initialized with the default configuration. public var requestBodyCreator: RequestBodyCreator /// Designated initializer /// /// - Parameters: - /// - interceptorProvider: The interceptor provider to use when constructing chains for a request - /// - endpointURL: The GraphQL endpoint URL to use. + /// - interceptorProvider: The interceptor provider to use when constructing a request chain + /// - endpointURL: The GraphQL endpoint URL to use /// - additionalHeaders: Any additional headers that should be automatically added to every request. Defaults to an empty dictionary. /// - autoPersistQueries: Pass `true` if Automatic Persisted Queries should be used to send a query hash instead of the full query body by default. Defaults to `false`. /// - requestBodyCreator: The `RequestBodyCreator` object to use to build your `URLRequest`. Defaults to the provided `ApolloRequestBodyCreator` implementation. @@ -51,7 +69,7 @@ open class RequestChainNetworkTransport: NetworkTransport { self.useGETForPersistedQueryRetry = useGETForPersistedQueryRetry } - /// Constructs a default (ie, non-multipart) GraphQL request. + /// Constructs a GraphQL request for the given operation. /// /// Override this method if you need to use a custom subclass of `HTTPRequest`. /// @@ -59,22 +77,44 @@ open class RequestChainNetworkTransport: NetworkTransport { /// - operation: The operation to create the request for /// - cachePolicy: The `CachePolicy` to use when creating the request /// - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - Returns: The constructed request. open func constructRequest( for operation: Operation, cachePolicy: CachePolicy, - contextIdentifier: UUID? = nil) -> HTTPRequest { - JSONRequest(operation: operation, - graphQLEndpoint: self.endpointURL, - contextIdentifier: contextIdentifier, - clientName: self.clientName, - clientVersion: self.clientVersion, - additionalHeaders: self.additionalHeaders, - cachePolicy: cachePolicy, - autoPersistQueries: self.autoPersistQueries, - useGETForQueries: self.useGETForQueries, - useGETForPersistedQueryRetry: self.useGETForPersistedQueryRetry, - requestBodyCreator: self.requestBodyCreator) + contextIdentifier: UUID? = nil, + context: RequestContext? = nil + ) -> HTTPRequest { + let request = JSONRequest( + operation: operation, + graphQLEndpoint: self.endpointURL, + contextIdentifier: contextIdentifier, + clientName: self.clientName, + clientVersion: self.clientVersion, + additionalHeaders: self.additionalHeaders, + cachePolicy: cachePolicy, + context: context, + autoPersistQueries: self.autoPersistQueries, + useGETForQueries: self.useGETForQueries, + useGETForPersistedQueryRetry: self.useGETForPersistedQueryRetry, + requestBodyCreator: self.requestBodyCreator + ) + + if Operation.operationType == .subscription { + request.addHeader( + name: "Accept", + value: "multipart/mixed;\(MultipartResponseSubscriptionParser.protocolSpec),application/json" + ) + } + + if Operation.hasDeferredFragments { + request.addHeader( + name: "Accept", + value: "multipart/mixed;boundary=\"graphql\";\(MultipartResponseDeferParser.protocolSpec),application/json" + ) + } + + return request } // MARK: - NetworkTransport Conformance @@ -86,19 +126,31 @@ open class RequestChainNetworkTransport: NetworkTransport { operation: Operation, cachePolicy: CachePolicy = .default, contextIdentifier: UUID? = nil, + context: RequestContext? = nil, callbackQueue: DispatchQueue = .main, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable { - let interceptors = self.interceptorProvider.interceptors(for: operation) - let chain = RequestChain(interceptors: interceptors, callbackQueue: callbackQueue) - chain.additionalErrorHandler = self.interceptorProvider.additionalErrorInterceptor(for: operation) - let request = self.constructRequest(for: operation, - cachePolicy: cachePolicy, - contextIdentifier: contextIdentifier) + let chain = makeChain(operation: operation, callbackQueue: callbackQueue) + let request = self.constructRequest( + for: operation, + cachePolicy: cachePolicy, + contextIdentifier: contextIdentifier, + context: context) chain.kickoff(request: request, completion: completionHandler) return chain } + + private func makeChain( + operation: Operation, + callbackQueue: DispatchQueue = .main + ) -> RequestChain { + let interceptors = self.interceptorProvider.interceptors(for: operation) + let chain = InterceptorRequestChain(interceptors: interceptors, callbackQueue: callbackQueue) + chain.additionalErrorHandler = self.interceptorProvider.additionalErrorInterceptor(for: operation) + return chain + } + } extension RequestChainNetworkTransport: UploadingNetworkTransport { @@ -110,11 +162,13 @@ extension RequestChainNetworkTransport: UploadingNetworkTransport { /// - Parameters: /// - operation: The operation to create a request for /// - files: The files you wish to upload + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - manualBoundary: [optional] A manually set boundary for your upload request. Defaults to nil. /// - Returns: The created request. - open func constructUploadRequest( + public func constructUploadRequest( for operation: Operation, with files: [GraphQLFile], + context: RequestContext? = nil, manualBoundary: String? = nil) -> HTTPRequest { UploadRequest(graphQLEndpoint: self.endpointURL, @@ -124,19 +178,19 @@ extension RequestChainNetworkTransport: UploadingNetworkTransport { additionalHeaders: self.additionalHeaders, files: files, manualBoundary: manualBoundary, + context: context, requestBodyCreator: self.requestBodyCreator) } public func upload( operation: Operation, files: [GraphQLFile], + context: RequestContext?, callbackQueue: DispatchQueue = .main, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable { - let request = self.constructUploadRequest(for: operation, with: files) - let interceptors = self.interceptorProvider.interceptors(for: operation) - let chain = RequestChain(interceptors: interceptors, callbackQueue: callbackQueue) - + let request = self.constructUploadRequest(for: operation, with: files, context: context) + let chain = makeChain(operation: operation, callbackQueue: callbackQueue) chain.kickoff(request: request, completion: completionHandler) return chain } diff --git a/Sources/ApolloPGATOUR/RequestContext.swift b/Sources/ApolloPGATOUR/RequestContext.swift new file mode 100644 index 0000000000..6e43358ea7 --- /dev/null +++ b/Sources/ApolloPGATOUR/RequestContext.swift @@ -0,0 +1,12 @@ +import Foundation +#if !COCOAPODS +import ApolloAPI +#endif + +/// A marker protocol to set up an object to pass through the request chain. +/// +/// Used to allow additional context-specific information to pass the length of the request chain. +/// +/// This allows the various interceptors to make modifications, or perform actions, with information +/// that they cannot get just from the existing operation. It can be anything that conforms to this protocol. +public protocol RequestContext {} diff --git a/Sources/ApolloPGATOUR/Resources/PrivacyInfo.xcprivacy b/Sources/ApolloPGATOUR/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000000..d37d6275f5 --- /dev/null +++ b/Sources/ApolloPGATOUR/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/Sources/Apollo/ResponseCodeInterceptor.swift b/Sources/ApolloPGATOUR/ResponseCodeInterceptor.swift similarity index 60% rename from Sources/Apollo/ResponseCodeInterceptor.swift rename to Sources/ApolloPGATOUR/ResponseCodeInterceptor.swift index 75ce281150..2c94ff7cd1 100644 --- a/Sources/Apollo/ResponseCodeInterceptor.swift +++ b/Sources/ApolloPGATOUR/ResponseCodeInterceptor.swift @@ -1,7 +1,12 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// An interceptor to check the response code returned with a request. public struct ResponseCodeInterceptor: ApolloInterceptor { + + public var id: String = UUID().uuidString public enum ResponseCodeError: Error, LocalizedError { case invalidResponseCode(response: HTTPURLResponse?, rawData: Data?) @@ -28,6 +33,17 @@ public struct ResponseCodeInterceptor: ApolloInterceptor { return errorStrings.joined(separator: " ") } } + + public var graphQLError: GraphQLError? { + switch self { + case .invalidResponseCode(_, let rawData): + if let jsonRawData = rawData, + let jsonData = try? JSONSerialization.jsonObject(with: jsonRawData, options: .allowFragments) as? JSONObject { + return GraphQLError(jsonData) + } + return nil + } + } } /// Designated initializer @@ -40,20 +56,26 @@ public struct ResponseCodeInterceptor: ApolloInterceptor { completion: @escaping (Result, Error>) -> Void) { - guard response?.httpResponse.apollo.isSuccessful == true else { - let error = ResponseCodeError.invalidResponseCode(response: response?.httpResponse, - - rawData: response?.rawData) + guard response?.httpResponse.isSuccessful == true else { + let error = ResponseCodeError.invalidResponseCode( + response: response?.httpResponse, + rawData: response?.rawData + ) - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) + chain.handleErrorAsync( + error, + request: request, + response: response, + completion: completion + ) return } - chain.proceedAsync(request: request, - response: response, - completion: completion) + chain.proceedAsync( + request: request, + response: response, + interceptor: self, + completion: completion + ) } } diff --git a/Sources/ApolloPGATOUR/ResponsePath.swift b/Sources/ApolloPGATOUR/ResponsePath.swift new file mode 100644 index 0000000000..c681f9d449 --- /dev/null +++ b/Sources/ApolloPGATOUR/ResponsePath.swift @@ -0,0 +1,108 @@ +/// Represents a list of string components joined into a path using a reverse linked list. +/// +/// A response path is stored as a linked list because using an array turned out to be +/// a performance bottleneck during decoding/execution. +/// +/// In order to optimize for calculation of a path string, `ResponsePath` does not allow insertion +/// of components in the middle or at the beginning of the path. Components may only be appended to +/// the end of an existing path. +public struct ResponsePath: ExpressibleByArrayLiteral { + public typealias Key = String + + private final class Node { + let previous: Node? + let key: Key + + init(previous: Node?, key: Key) { + self.previous = previous + self.key = key + } + + lazy var joined: String = { + if let previous = previous { + return previous.joined + ".\(key)" + } else { + return key + } + }() + + lazy var components: [String] = { + if let previous = previous { + var components = previous.components + components.append(key) + return components + } else { + return [key] + } + }() + } + + private var head: Node? + public var joined: String { + return head?.joined ?? "" + } + + public func toArray() -> [String] { + return head?.components ?? [] + } + + public init(arrayLiteral segments: Key...) { + for segment in segments { + append(segment) + } + } + + public init(_ key: Key) { + append(key) + } + + public mutating func append(_ key: Key) { + head = Node(previous: head, key: key) + } + + public func appending(_ key: Key) -> ResponsePath { + var copy = self + copy.append(key) + return copy + } + + public var isEmpty: Bool { + head == nil + } + + public static func + (lhs: ResponsePath, rhs: Key) -> ResponsePath { + lhs.appending(rhs) + } + + public static func + (lhs: ResponsePath, rhs: ResponsePath) -> ResponsePath { + lhs + rhs.toArray() + } + + public static func + ( + lhs: ResponsePath, rhs: T + ) -> ResponsePath where T.Element == Key { + var new = lhs + for component in rhs { + new.append(component) + } + return new + } +} + +extension ResponsePath: CustomStringConvertible { + public var description: String { + return joined + } +} + +extension ResponsePath: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(joined) + } +} + +extension ResponsePath: Equatable { + static public func == (lhs: ResponsePath, rhs: ResponsePath) -> Bool { + return lhs.joined == rhs.joined + } +} diff --git a/Sources/ApolloPGATOUR/SelectionSet+DictionaryIntializer.swift b/Sources/ApolloPGATOUR/SelectionSet+DictionaryIntializer.swift new file mode 100644 index 0000000000..dd9b90c0a2 --- /dev/null +++ b/Sources/ApolloPGATOUR/SelectionSet+DictionaryIntializer.swift @@ -0,0 +1,69 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +public enum RootSelectionSetInitializeError: Error { + case hasNonHashableValue +} + +extension RootSelectionSet { + /// Initializes a `SelectionSet` with a raw JSON response object. + /// + /// The process of converting a JSON response into `SelectionSetData` is done by using a + /// `GraphQLExecutor` with a`GraphQLSelectionSetMapper` to parse, validate, and transform + /// the JSON response data into the format expected by `SelectionSet`. + /// + /// - Parameters: + /// - data: A dictionary representing a JSON response object for a GraphQL object. + /// - variables: [Optional] The operation variables that would be used to obtain + /// the given JSON response data. + @_disfavoredOverload + public init( + data: [String: Any], + variables: GraphQLOperation.Variables? = nil + ) throws { + let jsonObject = try Self.convertToAnyHashableValueDict(dict: data) + try self.init(data: jsonObject, variables: variables) + } + + /// Convert dictionary type [String: Any] to [String: AnyHashable] + /// - Parameter dict: [String: Any] type dictionary + /// - Returns: converted [String: AnyHashable] type dictionary + private static func convertToAnyHashableValueDict(dict: [String: Any]) throws -> [String: AnyHashable] { + var result = [String: AnyHashable]() + + for (key, value) in dict { + if let arrayValue = value as? [Any] { + result[key] = try convertToAnyHashableArray(array: arrayValue) + } else { + if let dictValue = value as? [String: Any] { + result[key] = try convertToAnyHashableValueDict(dict: dictValue) + } else if let hashableValue = value as? AnyHashable { + result[key] = hashableValue + } else { + throw RootSelectionSetInitializeError.hasNonHashableValue + } + } + } + return result + } + + /// Convert Any type Array type to AnyHashable type Array + /// - Parameter array: Any type Array + /// - Returns: AnyHashable type Array + private static func convertToAnyHashableArray(array: [Any]) throws -> [AnyHashable] { + var result: [AnyHashable] = [] + for value in array { + if let array = value as? [Any] { + result.append(try convertToAnyHashableArray(array: array)) + } else if let dict = value as? [String: Any] { + result.append(try convertToAnyHashableValueDict(dict: dict)) + } else if let hashable = value as? AnyHashable { + result.append(hashable) + } else { + throw RootSelectionSetInitializeError.hasNonHashableValue + } + } + return result + } +} diff --git a/Sources/ApolloPGATOUR/SelectionSet+JSONInitializer.swift b/Sources/ApolloPGATOUR/SelectionSet+JSONInitializer.swift new file mode 100644 index 0000000000..12e5ce540f --- /dev/null +++ b/Sources/ApolloPGATOUR/SelectionSet+JSONInitializer.swift @@ -0,0 +1,34 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +extension RootSelectionSet { + + /// Initializes a `SelectionSet` with a raw JSON response object. + /// + /// The process of converting a JSON response into `SelectionSetData` is done by using a + /// `GraphQLExecutor` with a`GraphQLSelectionSetMapper` to parse, validate, and transform + /// the JSON response data into the format expected by `SelectionSet`. + /// + /// - Parameters: + /// - data: A dictionary representing a JSON response object for a GraphQL object. + /// - variables: [Optional] The operation variables that would be used to obtain + /// the given JSON response data. + public init( + data: JSONObject, + variables: GraphQLOperation.Variables? = nil + ) throws { + let accumulator = GraphQLSelectionSetMapper( + handleMissingValues: .allowForOptionalFields + ) + let executor = GraphQLExecutor(executionSource: NetworkResponseExecutionSource()) + + self = try executor.execute( + selectionSet: Self.self, + on: data, + variables: variables, + accumulator: accumulator + ) + } + +} diff --git a/Sources/Apollo/TaskData.swift b/Sources/ApolloPGATOUR/TaskData.swift similarity index 84% rename from Sources/Apollo/TaskData.swift rename to Sources/ApolloPGATOUR/TaskData.swift index e8f1026dca..2cae3c1594 100644 --- a/Sources/Apollo/TaskData.swift +++ b/Sources/ApolloPGATOUR/TaskData.swift @@ -17,6 +17,15 @@ public class TaskData { func append(additionalData: Data) { self.data.append(additionalData) } + + func reset(data: Data?) { + guard let data, !data.isEmpty else { + self.data = Data() + return + } + + self.data = data + } func responseReceived(response: URLResponse) { if let httpResponse = response as? HTTPURLResponse { diff --git a/Sources/Apollo/URLSessionClient.swift b/Sources/ApolloPGATOUR/URLSessionClient.swift similarity index 75% rename from Sources/Apollo/URLSessionClient.swift rename to Sources/ApolloPGATOUR/URLSessionClient.swift index 7444dec791..a77a2f28fa 100644 --- a/Sources/Apollo/URLSessionClient.swift +++ b/Sources/ApolloPGATOUR/URLSessionClient.swift @@ -1,7 +1,4 @@ import Foundation -#if !COCOAPODS -import ApolloUtils -#endif /// A class to handle URL Session calls that will support background execution, /// but still (mostly) use callbacks for its primary method of communication. @@ -19,6 +16,8 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat case dataForRequestNotFound(request: URLRequest?) case networkError(data: Data, response: HTTPURLResponse?, underlying: Error) case sessionInvalidated + case missingMultipartBoundary + case cannotParseBoundaryData public var errorDescription: String? { switch self { @@ -32,6 +31,10 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat return "A network error occurred: \(underlyingError.localizedDescription)" case .sessionInvalidated: return "Attempting to create a new request after the session has been invalidated!" + case .missingMultipartBoundary: + return "A multipart HTTP response was received without specifying a boundary!" + case .cannotParseBoundaryData: + return "Cannot parse the multipart boundary data!" } } } @@ -42,15 +45,15 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat /// A completion block returning a result. On `.success` it will contain a tuple with non-nil `Data` and its corresponding `HTTPURLResponse`. On `.failure` it will contain an error. public typealias Completion = (Result<(Data, HTTPURLResponse), Error>) -> Void - private var tasks = Atomic<[Int: TaskData]>([:]) + @Atomic private var tasks: [Int: TaskData] = [:] /// The raw URLSession being used for this client open private(set) var session: URLSession! - private var hasBeenInvalidated = Atomic(false) + @Atomic private var hasBeenInvalidated: Bool = false private var hasNotBeenInvalidated: Bool { - !self.hasBeenInvalidated.value + !self.hasBeenInvalidated } /// Designated initializer. @@ -58,19 +61,24 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat /// - Parameters: /// - sessionConfiguration: The `URLSessionConfiguration` to use to set up the URL session. /// - callbackQueue: [optional] The `OperationQueue` to tell the URL session to call back to this class on, which will in turn call back to your class. Defaults to `.main`. + /// - sessionDescription: [optional] A human-readable string that you can use for debugging purposes. public init(sessionConfiguration: URLSessionConfiguration = .default, - callbackQueue: OperationQueue? = .main) { + callbackQueue: OperationQueue? = .main, + sessionDescription: String? = nil) { super.init() - self.session = URLSession(configuration: sessionConfiguration, - delegate: self, - delegateQueue: callbackQueue) + + let session = URLSession(configuration: sessionConfiguration, + delegate: self, + delegateQueue: callbackQueue) + session.sessionDescription = sessionDescription + self.session = session } /// Cleans up and invalidates everything related to this session client. /// /// NOTE: This must be called from the `deinit` of anything holding onto this client in order to break a retain cycle with the delegate. public func invalidate() { - self.hasBeenInvalidated.mutate { $0 = true } + self.$hasBeenInvalidated.mutate { $0 = true } func cleanup() { self.session = nil self.clearAllTasks() @@ -90,31 +98,33 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat /// /// - Parameter identifier: The identifier of the task to clear. open func clear(task identifier: Int) { - self.tasks.mutate { _ = $0.removeValue(forKey: identifier) } + self.$tasks.mutate { _ = $0.removeValue(forKey: identifier) } } /// Clears underlying dictionaries of any data related to all tasks. /// /// Mostly useful for cleanup and/or after invalidation of the `URLSession`. open func clearAllTasks() { - guard self.tasks.value.apollo.isNotEmpty else { + guard !self.tasks.isEmpty else { // Nothing to clear return } - self.tasks.mutate { $0.removeAll() } + self.$tasks.mutate { $0.removeAll() } } /// The main method to perform a request. /// /// - Parameters: /// - request: The request to perform. + /// - taskDescription: [optional] A description to add to the `URLSessionTask` for debugging purposes. /// - rawTaskCompletionHandler: [optional] A completion handler to call once the raw task is done, so if an Error requires access to the headers, the user can still access these. /// - completion: A completion handler to call when the task has either completed successfully or failed. /// /// - Returns: The created URLSession task, already resumed, because nobody ever remembers to call `resume()`. @discardableResult open func sendRequest(_ request: URLRequest, + taskDescription: String? = nil, rawTaskCompletionHandler: RawCompletion? = nil, completion: @escaping Completion) -> URLSessionTask { guard self.hasNotBeenInvalidated else { @@ -123,16 +133,30 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat } let task = self.session.dataTask(with: request) + task.taskDescription = taskDescription + let taskData = TaskData(rawCompletion: rawTaskCompletionHandler, completionBlock: completion) - self.tasks.mutate { $0[task.taskIdentifier] = taskData } + self.$tasks.mutate { $0[task.taskIdentifier] = taskData } task.resume() return task } - + + @discardableResult + open func sendRequest(_ request: URLRequest, + rawTaskCompletionHandler: RawCompletion? = nil, + completion: @escaping Completion) -> URLSessionTask { + sendRequest( + request, + taskDescription: nil, + rawTaskCompletionHandler: nil, + completion: completion + ) + } + /// Cancels a given task and clears out its underlying data. /// /// NOTE: You will not receive any kind of "This was cancelled" error when this is called. @@ -147,7 +171,7 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { let finalError = error ?? URLSessionClientError.sessionBecameInvalidWithoutUnderlyingError - for task in self.tasks.value.values { + for task in self.tasks.values { task.completionBlock(.failure(finalError)) } @@ -193,7 +217,7 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat self.clear(task: task.taskIdentifier) } - guard let taskData = self.tasks.value[task.taskIdentifier] else { + guard let taskData = self.tasks[task.taskIdentifier] else { // No completion blocks, the task has likely been cancelled. Bail out. return } @@ -250,21 +274,48 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat // MARK: - URLSessionDataDelegate - open func urlSession(_ session: URLSession, - dataTask: URLSessionDataTask, - didReceive data: Data) { + open func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + didReceive data: Data + ) { guard dataTask.state != .canceling else { // Task is in the process of cancelling, don't bother handling its data. return } - - self.tasks.mutate { - guard let taskData = $0[dataTask.taskIdentifier] else { - assertionFailure("No data found for task \(dataTask.taskIdentifier), cannot append received data") + + guard let taskData = self.tasks[dataTask.taskIdentifier] else { + assertionFailure("No data found for task \(dataTask.taskIdentifier), cannot append received data") + return + } + + taskData.append(additionalData: data) + + if let httpResponse = dataTask.response as? HTTPURLResponse, httpResponse.isMultipart { + let multipartHeaderComponents = httpResponse.multipartHeaderComponents + guard let boundaryString = multipartHeaderComponents.boundary else { + taskData.completionBlock(.failure(URLSessionClientError.missingMultipartBoundary)) return } - - taskData.append(additionalData: data) + + let boundaryMarker = "--\(boundaryString)" + guard + let dataString = String(data: taskData.data, encoding: .utf8)?.trimmingCharacters(in: .newlines), + let lastBoundaryIndex = dataString.range(of: boundaryMarker, options: .backwards)?.upperBound, + let boundaryData = dataString.prefix(upTo: lastBoundaryIndex).data(using: .utf8) + else { + taskData.completionBlock(.failure(URLSessionClientError.cannotParseBoundaryData)) + return + } + + let remainingData = dataString.suffix(from: lastBoundaryIndex).data(using: .utf8) + taskData.reset(data: remainingData) + + if let rawCompletion = taskData.rawCompletion { + rawCompletion(boundaryData, httpResponse, nil) + } + + taskData.completionBlock(.success((boundaryData, httpResponse))) } } @@ -295,7 +346,7 @@ open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegat completionHandler(.allow) } - self.tasks.mutate { + self.$tasks.mutate { guard let taskData = $0[dataTask.taskIdentifier] else { return } diff --git a/Sources/Apollo/UploadRequest.swift b/Sources/ApolloPGATOUR/UploadRequest.swift similarity index 80% rename from Sources/Apollo/UploadRequest.swift rename to Sources/ApolloPGATOUR/UploadRequest.swift index ae0cbd7b1f..d2aacdfb59 100644 --- a/Sources/Apollo/UploadRequest.swift +++ b/Sources/ApolloPGATOUR/UploadRequest.swift @@ -1,4 +1,7 @@ import Foundation +#if !COCOAPODS +import ApolloAPI +#endif /// A request class allowing for a multipart-upload request. open class UploadRequest: HTTPRequest { @@ -19,6 +22,7 @@ open class UploadRequest: HTTPRequest { /// - additionalHeaders: Any additional headers you wish to add by default to this request. Defaults to an empty dictionary. /// - files: The array of files to upload for all `Upload` parameters in the mutation. /// - manualBoundary: [optional] A manual boundary to pass in. A default boundary will be used otherwise. Defaults to nil. + /// - context: [optional] A context that is being passed through the request chain. Should default to `nil`. /// - requestBodyCreator: An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation. public init(graphQLEndpoint: URL, operation: Operation, @@ -27,6 +31,7 @@ open class UploadRequest: HTTPRequest { additionalHeaders: [String: String] = [:], files: [GraphQLFile], manualBoundary: String? = nil, + context: RequestContext? = nil, requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator()) { self.requestBodyCreator = requestBodyCreator self.files = files @@ -36,7 +41,8 @@ open class UploadRequest: HTTPRequest { contentType: "multipart/form-data", clientName: clientName, clientVersion: clientVersion, - additionalHeaders: additionalHeaders) + additionalHeaders: additionalHeaders, + context: context) } public override func toURLRequest() throws -> URLRequest { @@ -56,8 +62,6 @@ open class UploadRequest: HTTPRequest { /// - Throws: Any error arising from creating the form data /// - Returns: The created form data open func requestMultipartFormData() throws -> MultipartFormData { - let shouldSendOperationID = (self.operation.operationIdentifier != nil) - let formData: MultipartFormData if let boundary = manualBoundary { @@ -70,18 +74,16 @@ open class UploadRequest: HTTPRequest { // for the files in the rest of the form data let fieldsForFiles = Set(files.map { $0.fieldName }).sorted() var fields = self.requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: shouldSendOperationID, sendQueryDocument: true, autoPersistQuery: false) - var variables = fields["variables"] as? GraphQLMap ?? GraphQLMap() + var variables = fields["variables"] as? JSONEncodableDictionary ?? JSONEncodableDictionary() for fieldName in fieldsForFiles { - if - let value = variables[fieldName], - let arrayValue = value as? [JSONEncodable] { - let arrayOfNils: [JSONEncodable?] = arrayValue.map { _ in nil } - variables.updateValue(arrayOfNils, forKey: fieldName) + if let value = variables[fieldName], + let arrayValue = value as? [JSONEncodable] { + let arrayOfNils: [NSNull?] = arrayValue.map { _ in NSNull() } + variables.updateValue(arrayOfNils, forKey: fieldName) } else { - variables.updateValue(nil, forKey: fieldName) + variables.updateValue(NSNull(), forKey: fieldName) } } fields["variables"] = variables @@ -125,4 +127,20 @@ open class UploadRequest: HTTPRequest { return formData } + + // MARK: - Equtable/Hashable Conformance + + public static func == (lhs: UploadRequest, rhs: UploadRequest) -> Bool { + lhs as HTTPRequest == rhs as HTTPRequest && + type(of: lhs.requestBodyCreator) == type(of: rhs.requestBodyCreator) && + lhs.files == rhs.files && + lhs.manualBoundary == rhs.manualBoundary + } + + public override func hash(into hasher: inout Hasher) { + super.hash(into: &hasher) + hasher.combine("\(type(of: requestBodyCreator))") + hasher.combine(files) + hasher.combine(manualBoundary) + } } diff --git a/Sources/ApolloSQLite/Documentation.docc/Documentation.md b/Sources/ApolloSQLite/Documentation.docc/Documentation.md new file mode 100644 index 0000000000..1ff9e4d4f3 --- /dev/null +++ b/Sources/ApolloSQLite/Documentation.docc/Documentation.md @@ -0,0 +1,7 @@ +# ``ApolloSQLite`` + +A [`NormalizedCache`](/documentation/apollo/normalizedcache) implementation backed by a `SQLite` database. + +## Overview + +``SQLiteNormalizedCache`` is currently the primary supported mechanism for persisting Apollo cache data between application runs. diff --git a/Sources/ApolloSQLite/Info.plist b/Sources/ApolloSQLite/Info.plist deleted file mode 100644 index b30021bc5b..0000000000 --- a/Sources/ApolloSQLite/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ApolloSQLite - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2017 Apollo GraphQL. All rights reserved. - NSPrincipalClass - - - diff --git a/Sources/ApolloSQLite/Resources/PrivacyInfo.xcprivacy b/Sources/ApolloSQLite/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000000..d37d6275f5 --- /dev/null +++ b/Sources/ApolloSQLite/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/Sources/ApolloSQLite/SQLiteDatabase.swift b/Sources/ApolloSQLite/SQLiteDatabase.swift index 7e21c652dc..ce125004ba 100644 --- a/Sources/ApolloSQLite/SQLiteDatabase.swift +++ b/Sources/ApolloSQLite/SQLiteDatabase.swift @@ -1,6 +1,6 @@ import Foundation #if !COCOAPODS -import Apollo +import ApolloPGATOUR #endif public struct DatabaseRow { diff --git a/Sources/ApolloSQLite/SQLiteDotSwiftDatabase.swift b/Sources/ApolloSQLite/SQLiteDotSwiftDatabase.swift index 6e4028289f..c1db109a72 100644 --- a/Sources/ApolloSQLite/SQLiteDotSwiftDatabase.swift +++ b/Sources/ApolloSQLite/SQLiteDotSwiftDatabase.swift @@ -1,6 +1,6 @@ import Foundation #if !COCOAPODS -import Apollo +import ApolloPGATOUR #endif import SQLite diff --git a/Sources/ApolloSQLite/SQLiteNormalizedCache.swift b/Sources/ApolloSQLite/SQLiteNormalizedCache.swift index b8c276c896..752413bdbb 100644 --- a/Sources/ApolloSQLite/SQLiteNormalizedCache.swift +++ b/Sources/ApolloSQLite/SQLiteNormalizedCache.swift @@ -1,6 +1,6 @@ import Foundation #if !COCOAPODS -import Apollo +import ApolloPGATOUR #endif public enum SQLiteNormalizedCacheError: Error { diff --git a/Sources/ApolloSQLite/SQLiteSerialization.swift b/Sources/ApolloSQLite/SQLiteSerialization.swift index 7fe69d7481..277572dc9a 100644 --- a/Sources/ApolloSQLite/SQLiteSerialization.swift +++ b/Sources/ApolloSQLite/SQLiteSerialization.swift @@ -1,12 +1,12 @@ import Foundation -import SQLite #if !COCOAPODS -import Apollo +import ApolloPGATOUR +import ApolloAPI #endif private let serializedReferenceKey = "$reference" -final class SQLiteSerialization { +enum SQLiteSerialization { static func serialize(fields: Record.Fields) throws -> Data { let jsonObject = try fields.compactMapValues(serialize(fieldValue:)) return try JSONSerialization.data(withJSONObject: jsonObject, options: []) @@ -41,7 +41,7 @@ final class SQLiteSerialization { guard let reference = dictionary[serializedReferenceKey] as? String else { return fieldJSONValue } - return CacheReference(key: reference) + return CacheReference(reference) case let array as [JSONValue]: return try array.map { try deserialize(fieldJSONValue: $0) } default: diff --git a/Sources/ApolloTestSupport/ApolloTestSupport.h b/Sources/ApolloTestSupport/ApolloTestSupport.h deleted file mode 100644 index 289783cfe2..0000000000 --- a/Sources/ApolloTestSupport/ApolloTestSupport.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -//! Project version number for ApolloTestSupport. -FOUNDATION_EXPORT double ApolloTestSupportVersionNumber; - -//! Project version string for ApolloTestSupport. -FOUNDATION_EXPORT const unsigned char ApolloTestSupportVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Sources/ApolloTestSupport/AsyncResultObserver.swift b/Sources/ApolloTestSupport/AsyncResultObserver.swift deleted file mode 100644 index 6868635cda..0000000000 --- a/Sources/ApolloTestSupport/AsyncResultObserver.swift +++ /dev/null @@ -1,70 +0,0 @@ -import XCTest - -/// `AsyncResultObserver` is a helper class that can be used to test `Result` values received through a completion handler against one or more expectations. It is primarily useful if you expect the completion handler to be called multiple times, when receiving a fetch result from the cache and then from the server for example. -/// -/// The main benefit is that it avoids having to manually keep track of expectations and mutable closures (like `verifyResult`), which can make code hard to read and is prone to mistakes. Instead, you can use a result observer to create multiple expectations that will be automatically fulfilled in order when results are received. Often, you'll also want to run assertions against the result, which you can do by passing in an optional handler that is specific to that expectation. These handlers are throwing, which means you can use `result.get()` and `XCTUnwrap` for example. Thrown errors will automatically be recorded as failures in the test case (with the right line numbers, etc.). -/// -/// By default, expectations returned from `AsyncResultObserver` only expect to be called once, which is similar to how other built-in expectations work. Unexpected fulfillments will result in test failures. Usually this is what you want, and you add additional expectations with their own assertions if you expect further results. -/// If multiple fulfillments of a single expectation are expected however, you can use the standard `expectedFulfillmentCount` property to change that. -public class AsyncResultObserver where Failure: Error { - public typealias ResultHandler = (Result) throws -> Void - - private class AsyncResultExpectation: XCTestExpectation { - let file: StaticString - let line: UInt - let handler: ResultHandler - - init(description: String, file: StaticString = #filePath, line: UInt = #line, handler: @escaping ResultHandler) { - self.file = file - self.line = line - self.handler = handler - - super.init(description: description) - } - } - - private let testCase: XCTestCase - - // We keep track of the file and line number associated with the constructor as a fallback, in addition te keeping - // these for each expectation. That way, we can still show a failure within the context of the test in case unexpected - // results are received (which by definition do not have an associated expectation). - private let file: StaticString - private let line: UInt - - private var expectations: [AsyncResultExpectation] = [] - - public init(testCase: XCTestCase, file: StaticString = #filePath, line: UInt = #line) { - self.testCase = testCase - self.file = file - self.line = line - } - - public func expectation(description: String, file: StaticString = #filePath, line: UInt = #line, resultHandler: @escaping ResultHandler) -> XCTestExpectation { - let expectation = AsyncResultExpectation(description: description, file: file, line: line, handler: resultHandler) - expectation.assertForOverFulfill = true - - expectations.append(expectation) - - return expectation - } - - public func handler(_ result: Result) { - guard let expectation = expectations.first else { - XCTFail("Unexpected result received by handler", file: file, line: line) - return - } - - do { - try expectation.handler(result) - } catch { - testCase.record(error, file: expectation.file, line: expectation.line) - } - - expectation.fulfill() - - if expectation.apollo.numberOfFulfillments >= expectation.expectedFulfillmentCount { - expectations.removeFirst() - } - } -} - diff --git a/Sources/ApolloTestSupport/Field.swift b/Sources/ApolloTestSupport/Field.swift new file mode 100644 index 0000000000..4979577496 --- /dev/null +++ b/Sources/ApolloTestSupport/Field.swift @@ -0,0 +1,19 @@ +#if !COCOAPODS +import ApolloAPI +#endif + +@propertyWrapper +public struct Field { + + let key: StaticString + + public init(_ field: StaticString) { + self.key = field + } + + public var wrappedValue: Self { + get { self } + set { preconditionFailure() } + } + +} diff --git a/Sources/ApolloTestSupport/Info.plist b/Sources/ApolloTestSupport/Info.plist deleted file mode 100644 index fbe1e6b314..0000000000 --- a/Sources/ApolloTestSupport/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/ApolloTestSupport/Matchable.swift b/Sources/ApolloTestSupport/Matchable.swift deleted file mode 100644 index 1df504ff06..0000000000 --- a/Sources/ApolloTestSupport/Matchable.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation -import Apollo - -public protocol Matchable { - associatedtype Base - static func ~=(pattern: Self, value: Base) -> Bool -} - -extension JSONDecodingError: Matchable { - public typealias Base = Error - public static func ~=(pattern: JSONDecodingError, value: Error) -> Bool { - guard let value = value as? JSONDecodingError else { - return false - } - - switch (value, pattern) { - case (.missingValue, .missingValue), (.nullValue, .nullValue), (.wrongType, .wrongType), (.couldNotConvert, .couldNotConvert): - return true - default: - return false - } - } -} diff --git a/Sources/ApolloTestSupport/MockGraphQLServer.swift b/Sources/ApolloTestSupport/MockGraphQLServer.swift deleted file mode 100644 index 3fa5d43136..0000000000 --- a/Sources/ApolloTestSupport/MockGraphQLServer.swift +++ /dev/null @@ -1,106 +0,0 @@ -@testable import Apollo -import XCTest - -/// A `MockGraphQLServer` can be used during tests to check whether expected GraphQL requests are received, and to respond with appropriate test data for a particular request. -/// -/// You usually create a mock server in the test's `setUpWithError`, and use it to initialize a `MockNetworkTransport` that is in turn used to initialize an `ApolloClient`: -/// ``` -/// let server = MockGraphQLServer() -/// let networkTransport = MockNetworkTransport(server: server, store: store) -/// let client = ApolloClient(networkTransport: networkTransport, store: store) -/// ``` -/// A mock server should be configured to expect particular operation types, and invokes the passed in request handler when a request of that type comes in. Because the request allows access to `operation`, you can return different responses based on query variables for example: - -/// ``` -/// let serverExpectation = server.expect(HeroNameQuery.self) { request in -/// [ -/// "data": [ -/// "hero": [ -/// "name": request.operation.episode == .empire ? "Luke Skywalker" : "R2-D2", -/// "__typename": "Droid" -/// ] -/// ] -/// ] -/// } -/// ``` -/// By default, expectations returned from `MockGraphQLServer` only expect to be called once, which is similar to how other built-in expectations work. Unexpected fulfillments will result in test failures. But if multiple fulfillments are expected, you can use the standard `expectedFulfillmentCount` property to change that. For example, some of the concurrent tests expect the server to receive the same number of request as the number of invoked fetch operations, so in that case we can use: - -/// ``` -/// serverExpectation.expectedFulfillmentCount = numberOfFetches -/// ``` -public class MockGraphQLServer { - enum ServerError: Error, CustomStringConvertible { - case unexpectedRequest(String) - - public var description: String { - switch self { - case .unexpectedRequest(let requestDescription): - return "Mock GraphQL server received an unexpected request: \(requestDescription)" - } - } - } - - public typealias RequestHandler = (HTTPRequest) -> JSONObject - - private class RequestExpectation: XCTestExpectation { - let file: StaticString - let line: UInt - let handler: RequestHandler - - init(description: String, file: StaticString = #filePath, line: UInt = #line, handler: @escaping RequestHandler) { - self.file = file - self.line = line - self.handler = handler - - super.init(description: description) - } - } - - private let queue = DispatchQueue(label: "com.apollographql.MockGraphQLServer") - - public init() { } - - // Since RequestExpectation is generic over a specific GraphQLOperation, we can't store these in the dictionary - // directly. Moreover, there is no way to specify the type relationship that holds between the key and value. - // To work around this, we store values as Any and use a generic subscript as a type-safe way to access them. - private var requestExpectations: [AnyHashable: Any] = [:] - - private subscript(_ operationType: Operation.Type) -> RequestExpectation? { - get { - requestExpectations[ObjectIdentifier(operationType)] as! RequestExpectation? - } - - set { - requestExpectations[ObjectIdentifier(operationType)] = newValue - } - } - - public func expect(_ operationType: Operation.Type, file: StaticString = #filePath, line: UInt = #line, requestHandler: @escaping (HTTPRequest) -> JSONObject) -> XCTestExpectation { - return queue.sync { - let expectation = RequestExpectation(description: "Served request for \(String(describing: operationType))", file: file, line: line, handler: requestHandler) - expectation.assertForOverFulfill = true - - self[operationType] = expectation - - return expectation - } - } - - func serve(request: HTTPRequest, completionHandler: @escaping (Result) -> Void) where Operation: GraphQLOperation { - let operationType = type(of: request.operation) - - if let expectation = self[operationType] { - // Dispatch after a small random delay to spread out concurrent requests and simulate somewhat real-world conditions. - queue.asyncAfter(deadline: .now() + .milliseconds(Int.random(in: 10...50))) { - completionHandler(.success(expectation.handler(request))) - expectation.fulfill() - } - - } else { - queue.async { - completionHandler(.failure(ServerError.unexpectedRequest(String(describing: operationType)))) - } - } - - } -} diff --git a/Sources/ApolloTestSupport/MockNetworkTransport.swift b/Sources/ApolloTestSupport/MockNetworkTransport.swift deleted file mode 100644 index 8a79e73b51..0000000000 --- a/Sources/ApolloTestSupport/MockNetworkTransport.swift +++ /dev/null @@ -1,91 +0,0 @@ -import Foundation -@testable import Apollo - -public final class MockNetworkTransport: RequestChainNetworkTransport { - public init( - server: MockGraphQLServer = MockGraphQLServer(), - store: ApolloStore = ApolloStore(), - clientName: String = "MockNetworkTransport_ClientName", - clientVersion: String = "MockNetworkTransport_ClientVersion" - ) { - super.init(interceptorProvider: TestInterceptorProvider(store: store, server: server), - endpointURL: TestURL.mockServer.url) - self.clientName = clientName - self.clientVersion = clientVersion - } - - struct TestInterceptorProvider: InterceptorProvider { - let store: ApolloStore - let server: MockGraphQLServer - - func interceptors(for operation: Operation) -> [ApolloInterceptor] where Operation: GraphQLOperation { - return [ - MaxRetryInterceptor(), - CacheReadInterceptor(store: self.store), - MockGraphQLServerInterceptor(server: server), - ResponseCodeInterceptor(), - JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject), - AutomaticPersistedQueryInterceptor(), - CacheWriteInterceptor(store: self.store), - ] - } - } -} - -private final class MockTask: Cancellable { - func cancel() { - // no-op - } -} - -private class MockGraphQLServerInterceptor: ApolloInterceptor { - let server: MockGraphQLServer - - init(server: MockGraphQLServer) { - self.server = server - } - - public func interceptAsync(chain: RequestChain, request: HTTPRequest, response: HTTPResponse?, completion: @escaping (Result, Error>) -> Void) where Operation: GraphQLOperation { - server.serve(request: request) { result in - let httpResponse = HTTPURLResponse(url: TestURL.mockServer.url, - statusCode: 200, - httpVersion: nil, - headerFields: nil)! - - switch result { - case .failure(let error): - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) - case .success(let body): - let data = try! JSONSerializationFormat.serialize(value: body) - let response = HTTPResponse(response: httpResponse, - rawData: data, - parsedResponse: nil) - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - } - } -} - -public class MockWebSocketTransport: NetworkTransport { - public var clientName, clientVersion: String - - public init(clientName: String, clientVersion: String) { - self.clientName = clientName - self.clientVersion = clientVersion - } - - public func send( - operation: Operation, - cachePolicy: CachePolicy, - contextIdentifier: UUID?, - callbackQueue: DispatchQueue, - completionHandler: @escaping (Result, Error>) -> Void - ) -> Cancellable where Operation : GraphQLOperation { - return MockTask() - } -} diff --git a/Sources/ApolloTestSupport/MockURLSession.swift b/Sources/ApolloTestSupport/MockURLSession.swift deleted file mode 100644 index e92b2a4897..0000000000 --- a/Sources/ApolloTestSupport/MockURLSession.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// MockURLSession.swift -// ApolloTestSupport -// -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import Foundation -import Apollo -import ApolloUtils - -public final class MockURLSessionClient: URLSessionClient { - - public private (set) var lastRequest: Atomic = Atomic(nil) - - public var data: Data? - public var response: HTTPURLResponse? - public var error: Error? - - private let callbackQueue: DispatchQueue - - public init(callbackQueue: DispatchQueue? = nil) { - self.callbackQueue = callbackQueue ?? .main - } - - public override func sendRequest(_ request: URLRequest, - rawTaskCompletionHandler: URLSessionClient.RawCompletion? = nil, - completion: @escaping URLSessionClient.Completion) -> URLSessionTask { - self.lastRequest.mutate { $0 = request } - - // Capture data, response, and error instead of self to ensure we complete with the current state - // even if it is changed before the block runs. - callbackQueue.async { [data, response, error] in - rawTaskCompletionHandler?(data, response, error) - - if let error = error { - completion(.failure(error)) - } else { - guard let data = data else { - completion(.failure(URLSessionClientError.dataForRequestNotFound(request: request))) - return - } - - guard let response = response else { - completion(.failure(URLSessionClientError.noHTTPResponse(request: request))) - return - } - - completion(.success((data, response))) - } - } - - let mockTaskType: URLSessionDataTaskMockProtocol.Type = URLSessionDataTaskMock.self - let mockTask = mockTaskType.init() as! URLSessionDataTaskMock - return mockTask - } -} - -protocol URLSessionDataTaskMockProtocol { - init() -} - -private final class URLSessionDataTaskMock: URLSessionDataTask, URLSessionDataTaskMockProtocol{ - - // This override is to supress the deprecation warning on macOS 10.15+. - // This deprecated method needs to be used for unit test mocking purposes only. - @available(macOS, deprecated: 10.15) - override init() { - super.init() - } - - override func resume() { - // No-op - } -} diff --git a/Sources/ApolloTestSupport/MockWebSocket.swift b/Sources/ApolloTestSupport/MockWebSocket.swift deleted file mode 100644 index c92e0bb3ef..0000000000 --- a/Sources/ApolloTestSupport/MockWebSocket.swift +++ /dev/null @@ -1,37 +0,0 @@ -import Foundation -@testable import ApolloWebSocket - -public class MockWebSocket: WebSocketClient { - - public var request: URLRequest - public var callbackQueue: DispatchQueue = DispatchQueue.main - public var delegate: WebSocketClientDelegate? = nil - public var isConnected: Bool = false - - public required init(request: URLRequest, protocol: WebSocket.WSProtocol) { - self.request = request - - self.request.setValue(`protocol`.description, forHTTPHeaderField: WebSocket.Constants.headerWSProtocolName) - } - - open func reportDidConnect() { - callbackQueue.async { - self.delegate?.websocketDidConnect(socket: self) - } - } - - open func write(string: String) { - callbackQueue.async { - self.delegate?.websocketDidReceiveMessage(socket: self, text: string) - } - } - - open func write(ping: Data, completion: (() -> ())?) { - } - - public func disconnect() { - } - - public func connect() { - } -} diff --git a/Sources/ApolloTestSupport/MockWebSocketDelegate.swift b/Sources/ApolloTestSupport/MockWebSocketDelegate.swift deleted file mode 100644 index 3b5701ff65..0000000000 --- a/Sources/ApolloTestSupport/MockWebSocketDelegate.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation -@testable import ApolloWebSocket - -public class MockWebSocketDelegate: WebSocketClientDelegate { - public var didReceiveMessage: ((String) -> Void)? - - public init() {} - - public func websocketDidConnect(socket: WebSocketClient) {} - - public func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {} - - public func websocketDidReceiveMessage(socket: WebSocketClient, text: String) { - didReceiveMessage?(text) - } - - public func websocketDidReceiveData(socket: WebSocketClient, data: Data) {} -} diff --git a/Sources/ApolloTestSupport/Resources/a.txt b/Sources/ApolloTestSupport/Resources/a.txt deleted file mode 100644 index 651cda1a9b..0000000000 --- a/Sources/ApolloTestSupport/Resources/a.txt +++ /dev/null @@ -1 +0,0 @@ -Alpha file content. diff --git a/Sources/ApolloTestSupport/Resources/b.txt b/Sources/ApolloTestSupport/Resources/b.txt deleted file mode 100644 index 7cc0a57915..0000000000 --- a/Sources/ApolloTestSupport/Resources/b.txt +++ /dev/null @@ -1 +0,0 @@ -Bravo file content. diff --git a/Sources/ApolloTestSupport/Resources/c.txt b/Sources/ApolloTestSupport/Resources/c.txt deleted file mode 100644 index 3adae37d8a..0000000000 --- a/Sources/ApolloTestSupport/Resources/c.txt +++ /dev/null @@ -1 +0,0 @@ -Charlie file content. diff --git a/Sources/ApolloTestSupport/SQLiteTestCacheProvider.swift b/Sources/ApolloTestSupport/SQLiteTestCacheProvider.swift deleted file mode 100644 index 55bebd166b..0000000000 --- a/Sources/ApolloTestSupport/SQLiteTestCacheProvider.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Foundation -import Apollo -import ApolloSQLite - -public class SQLiteTestCacheProvider: TestCacheProvider { - /// Execute a test block rather than return a cache synchronously, since cache setup may be - /// asynchronous at some point. - public static func withCache(initialRecords: RecordSet? = nil, fileURL: URL? = nil, execute test: (NormalizedCache) throws -> ()) throws { - let fileURL = fileURL ?? temporarySQLiteFileURL() - let cache = try! SQLiteNormalizedCache(fileURL: fileURL) - if let initialRecords = initialRecords { - _ = try cache.merge(records: initialRecords) - } - try test(cache) - } - - public static func makeNormalizedCache(_ completionHandler: (Result, Error>) -> ()) { - let fileURL = temporarySQLiteFileURL() - let cache = try! SQLiteNormalizedCache(fileURL: fileURL) - completionHandler(.success((cache, nil))) - } - - public static func temporarySQLiteFileURL() -> URL { - let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()) - - // Create a folder with a random UUID to hold the SQLite file, since creating them in the - // same folder this close together will cause DB locks when you try to delete between tests. - let folder = temporaryDirectoryURL.appendingPathComponent(UUID().uuidString) - try? FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true) - - return folder.appendingPathComponent("db.sqlite3") - } -} diff --git a/Sources/ApolloTestSupport/TestCacheProvider.swift b/Sources/ApolloTestSupport/TestCacheProvider.swift deleted file mode 100644 index 97a4719c5f..0000000000 --- a/Sources/ApolloTestSupport/TestCacheProvider.swift +++ /dev/null @@ -1,59 +0,0 @@ -import XCTest -@testable import Apollo - -public typealias TearDownHandler = () throws -> () -public typealias TestDependency = (Resource, TearDownHandler?) - -public protocol TestCacheProvider: AnyObject { - static func makeNormalizedCache(_ completionHandler: (Result, Error>) -> ()) -} - -public class InMemoryTestCacheProvider: TestCacheProvider { - public static func makeNormalizedCache(_ completionHandler: (Result, Error>) -> ()) { - let cache = InMemoryNormalizedCache() - completionHandler(.success((cache, nil))) - } -} - -public protocol CacheDependentTesting { - var cacheType: TestCacheProvider.Type { get } - var cache: NormalizedCache! { get } -} - -extension CacheDependentTesting where Self: XCTestCase { - public func makeNormalizedCache() throws -> NormalizedCache { - var result: Result = .failure(XCTestError(.timeoutWhileWaiting)) - - let expectation = XCTestExpectation(description: "Initialized normalized cache") - - cacheType.makeNormalizedCache() { [weak self] testDependencyResult in - guard let self = self else { return } - - result = testDependencyResult.map { testDependency in - let (cache, tearDownHandler) = testDependency - - if let tearDownHandler = tearDownHandler { - self.addTeardownBlock { - do { - try tearDownHandler() - } catch { - self.record(error) - } - } - } - - return cache - } - - expectation.fulfill() - } - - wait(for: [expectation], timeout: 1) - - return try result.get() - } - - public func mergeRecordsIntoCache(_ records: RecordSet) { - _ = try! cache.merge(records: records) - } -} diff --git a/Sources/ApolloTestSupport/TestFileHelper.swift b/Sources/ApolloTestSupport/TestFileHelper.swift deleted file mode 100644 index f675744a33..0000000000 --- a/Sources/ApolloTestSupport/TestFileHelper.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// TestFileHelper.swift -// ApolloTests -// -// Created by Ellen Shapiro on 3/18/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import Foundation -import Apollo - -public struct TestFileHelper { - - public static func testParentFolder(for file: StaticString = #file) -> URL { - let fileAsString = file.withUTF8Buffer { - String(decoding: $0, as: UTF8.self) - } - let url = URL(fileURLWithPath: fileAsString) - return url.deletingLastPathComponent() - } - - public static func uploadServerFolder(from file: StaticString = #file) -> URL { - self.testParentFolder(for: file) - .deletingLastPathComponent() // test root - .deletingLastPathComponent() // source root - .appendingPathComponent("SimpleUploadServer") - } - - public static func uploadsFolder(from file: StaticString = #file) -> URL { - self.uploadServerFolder(from: file) - .appendingPathComponent("uploads") - } - - public static func fileURLForFile(named name: String, extension fileExtension: String) -> URL { - return self.testParentFolder() - .appendingPathComponent("Resources") - .appendingPathComponent(name) - .appendingPathExtension(fileExtension) - } -} diff --git a/Sources/ApolloTestSupport/TestMock.swift b/Sources/ApolloTestSupport/TestMock.swift new file mode 100644 index 0000000000..11d22a128a --- /dev/null +++ b/Sources/ApolloTestSupport/TestMock.swift @@ -0,0 +1,214 @@ +#if !COCOAPODS +@_exported @testable import ApolloAPI +#endif +@testable import ApolloPGATOUR +import Foundation + +@dynamicMemberLookup +public class Mock: AnyMock, Hashable { + + public var _data: [String: AnyHashable] + + public init() { + _data = ["__typename": O.objectType.typename] + } + + public var __typename: String { _data["__typename"] as! String } + + public subscript( + dynamicMember keyPath: KeyPath> + ) -> T? { + get { + let field = O._mockFields[keyPath: keyPath] + return _data[field.key.description] as? T + } + set { + _setScalar(newValue, for: keyPath) + } + } + + public func _setScalar( + _ value: T?, + for keyPath: KeyPath> + ) { + let field = O._mockFields[keyPath: keyPath] + _data[field.key.description] = value + } + + public subscript( + dynamicMember keyPath: KeyPath> + ) -> T.MockValueCollectionType.Element? { + get { + let field = O._mockFields[keyPath: keyPath] + return _data[field.key.description] as? T.MockValueCollectionType.Element + } + set { + _setEntity(newValue, for: keyPath) + } + } + + public func _setEntity( + _ value: T.MockValueCollectionType.Element?, + for keyPath: KeyPath> + ) { + let field = O._mockFields[keyPath: keyPath] + _data[field.key.description] = (value as? AnyHashable) + } + + public subscript( + dynamicMember keyPath: KeyPath>> + ) -> [T.MockValueCollectionType.Element]? { + get { + let field = O._mockFields[keyPath: keyPath] + return _data[field.key.description] as? [T.MockValueCollectionType.Element] + } + set { + _setList(newValue, for: keyPath) + } + } + + public func _setList( + _ value: [T.MockValueCollectionType.Element]?, + for keyPath: KeyPath>> + ) { + let field = O._mockFields[keyPath: keyPath] + _data[field.key.description] = value?._unsafelyConvertToMockValue() + } + + public subscript( + dynamicMember keyPath: KeyPath>> + ) -> [T]? { + get { + let field = O._mockFields[keyPath: keyPath] + return _data[field.key.description] as? [T] + } + set { + _setScalarList(newValue, for: keyPath) + } + } + + public func _setScalarList( + _ value: [T]?, + for keyPath: KeyPath>> + ) { + let field = O._mockFields[keyPath: keyPath] + _data[field.key.description] = value?._unsafelyConvertToMockValue() + } + + public var _selectionSetMockData: JSONObject { + _data.mapValues { + if let mock = $0.base as? AnyMock { + return mock._selectionSetMockData + } + if let mockArray = $0 as? Array { + return mockArray._unsafelyConvertToSelectionSetData() + } + return $0 + } + } + + // MARK: Hashable + + public static func ==(lhs: Mock, rhs: Mock) -> Bool { + lhs._data == rhs._data + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(_data) + } +} + +// MARK: - Selection Set Conversion + +public extension RootSelectionSet { + static func from( + _ mock: Mock, + withVariables variables: GraphQLOperation.Variables? = nil + ) -> Self { + let accumulator = TestMockSelectionSetMapper() + let executor = GraphQLExecutor(executionSource: NetworkResponseExecutionSource()) + + return try! executor.execute( + selectionSet: Self.self, + on: mock._selectionSetMockData, + variables: variables, + accumulator: accumulator + ) + } +} + +// MARK: - Helper Protocols + +public protocol AnyMock { + var _selectionSetMockData: JSONObject { get } +} + +public protocol MockObject: MockFieldValue { + associatedtype MockFields + associatedtype MockValueCollectionType = Array> + + static var objectType: Object { get } + static var _mockFields: MockFields { get } +} + +public protocol MockFieldValue { + associatedtype MockValueCollectionType: Collection +} + +extension Interface: MockFieldValue { + public typealias MockValueCollectionType = Array +} + +extension Union: MockFieldValue { + public typealias MockValueCollectionType = Array +} + +extension Optional: MockFieldValue where Wrapped: MockFieldValue { + public typealias MockValueCollectionType = Array> +} + +extension Array: MockFieldValue where Array.Element: MockFieldValue { + public typealias MockValueCollectionType = Array +} + +fileprivate extension Array { + func _unsafelyConvertToMockValue() -> [AnyHashable?] { + map { element in + switch element { + case let element as AnyHashable: + return element + + case let innerArray as Array: + return innerArray._unsafelyConvertToMockValue() + + default: + return nil + } + } + } + + func _unsafelyConvertToSelectionSetData() -> [AnyHashable?] { + map(_unsafelyConvertToSelectionSetData(element:)) + } + + private func _unsafelyConvertToSelectionSetData(element: Any) -> AnyHashable? { + switch element { + case let element as AnyMock: + return element._selectionSetMockData + + case let innerArray as Array: + return innerArray._unsafelyConvertToSelectionSetData() + + case let element as AnyHashable: + if DataDict._AnyHashableCanBeCoerced { + return element + + } else { + return _unsafelyConvertToSelectionSetData(element: element.base) + } + + default: + return nil + } + } +} diff --git a/Sources/ApolloTestSupport/TestMockSelectionSetMapper.swift b/Sources/ApolloTestSupport/TestMockSelectionSetMapper.swift new file mode 100644 index 0000000000..b882bb1cbc --- /dev/null +++ b/Sources/ApolloTestSupport/TestMockSelectionSetMapper.swift @@ -0,0 +1,48 @@ +@testable import ApolloPGATOUR +import Foundation + +/// An accumulator that converts data from a `Mock` to the correct values to create a `SelectionSet`. +final class TestMockSelectionSetMapper: GraphQLResultAccumulator { + + var requiresCacheKeyComputation: Bool { underlyingMapper.requiresCacheKeyComputation } + let underlyingMapper = GraphQLSelectionSetMapper(handleMissingValues: .allowForAllFields) + + func accept(scalar: AnyHashable, info: FieldExecutionInfo) throws -> AnyHashable? { + return scalar + } + + func accept(customScalar: AnyHashable, info: FieldExecutionInfo) throws -> AnyHashable? { + return customScalar + } + + func acceptNullValue(info: FieldExecutionInfo) -> AnyHashable? { + return underlyingMapper.acceptNullValue(info: info) + } + + func acceptMissingValue(info: FieldExecutionInfo) throws -> AnyHashable? { + return try underlyingMapper.acceptMissingValue(info: info) + } + + func accept(list: [AnyHashable?], info: FieldExecutionInfo) -> AnyHashable? { + return underlyingMapper.accept(list: list, info: info) + } + + func accept(childObject: DataDict, info: FieldExecutionInfo) throws -> AnyHashable? { + return try underlyingMapper.accept(childObject: childObject, info: info) + } + + func accept(fieldEntry: AnyHashable?, info: FieldExecutionInfo) -> (key: String, value: AnyHashable)? { + return underlyingMapper.accept(fieldEntry: fieldEntry, info: info) + } + + func accept( + fieldEntries: [(key: String, value: AnyHashable)], + info: ObjectExecutionInfo + ) throws -> DataDict { + return try underlyingMapper.accept(fieldEntries: fieldEntries, info: info) + } + + func finish(rootValue: DataDict, info: ObjectExecutionInfo) -> T { + return underlyingMapper.finish(rootValue: rootValue, info: info) + } +} diff --git a/Sources/ApolloTestSupport/TestURLs.swift b/Sources/ApolloTestSupport/TestURLs.swift deleted file mode 100644 index 4b1a886050..0000000000 --- a/Sources/ApolloTestSupport/TestURLs.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -/// URLs used in testing -public enum TestURL { - case mockServer - case mockPort8080 - - public var url: URL { - let urlString: String - switch self { - case .mockServer: - urlString = "http://localhost/dummy_url" - case .mockPort8080: - urlString = "http://localhost:8080/graphql" - } - - return URL(string: urlString)! - } -} diff --git a/Sources/ApolloTestSupport/XCTAssertHelpers.swift b/Sources/ApolloTestSupport/XCTAssertHelpers.swift deleted file mode 100644 index 10ca082c7b..0000000000 --- a/Sources/ApolloTestSupport/XCTAssertHelpers.swift +++ /dev/null @@ -1,153 +0,0 @@ -import XCTest -@testable import Apollo - -public func XCTAssertEqual(_ expression1: @autoclosure () throws -> [T : U]?, _ expression2: @autoclosure () throws -> [T : U]?, file: StaticString = #filePath, line: UInt = #line) rethrows { - let optionalValue1 = try expression1() - let optionalValue2 = try expression2() - - let message = { - "(\"\(String(describing: optionalValue1))\") is not equal to (\"\(String(describing: optionalValue2))\")" - } - - switch (optionalValue1, optionalValue2) { - case (.none, .none): - break - case let (value1 as NSDictionary, value2 as NSDictionary): - XCTAssertEqual(value1, value2, message(), file: file, line: line) - default: - XCTFail(message(), file: file, line: line) - } -} - -public func XCTAssertEqualUnordered(_ expression1: @autoclosure () throws -> C1, _ expression2: @autoclosure () throws -> C2, file: StaticString = #filePath, line: UInt = #line) rethrows where Element: Hashable, C1.Element == Element, C2.Element == Element { - let collection1 = try expression1() - let collection2 = try expression2() - - // Convert to sets to ignore ordering and only check whether all elements are accounted for, - // but also check count to detect duplicates. - XCTAssertEqual(collection1.count, collection2.count, file: file, line: line) - XCTAssertEqual(Set(collection1), Set(collection2), file: file, line: line) -} - -public func XCTAssertMatch(_ valueExpression: @autoclosure () throws -> Pattern.Base, _ patternExpression: @autoclosure () throws -> Pattern, file: StaticString = #filePath, line: UInt = #line) rethrows { - let value = try valueExpression() - let pattern = try patternExpression() - - let message = { - "(\"\(value)\") does not match (\"\(pattern)\")" - } - - if case pattern = value { return } - - XCTFail(message(), file: file, line: line) -} - -// We need overloaded versions instead of relying on default arguments -// due to https://bugs.swift.org/browse/SR-1534 - -public func XCTAssertSuccessResult(_ expression: @autoclosure () throws -> Result, file: StaticString = #file, line: UInt = #line) rethrows { - try XCTAssertSuccessResult(expression(), file: file, line: line, {_ in }) -} - -public func XCTAssertSuccessResult(_ expression: @autoclosure () throws -> Result, file: StaticString = #file, line: UInt = #line, _ successHandler: (_ value: Success) throws -> Void) rethrows { - let result = try expression() - - switch result { - case .success(let value): - try successHandler(value) - case .failure(let error): - XCTFail("Expected success, but result was an error: \(String(describing: error))", file: file, line: line) - } -} - -public func XCTAssertFailureResult(_ expression: @autoclosure () throws -> Result, file: StaticString = #file, line: UInt = #line) rethrows { - try XCTAssertFailureResult(expression(), file: file, line: line, {_ in }) -} - -public func XCTAssertFailureResult(_ expression: @autoclosure () throws -> Result, file: StaticString = #file, line: UInt = #line, _ errorHandler: (_ error: Error) throws -> Void) rethrows { - let result = try expression() - - switch result { - case .success(let success): - XCTFail("Expected failure, but result was successful: \(String(describing: success))", file: file, line: line) - case .failure(let error): - try errorHandler(error) - } -} - -/// Checks that the condition is eventually true with a given timeout (default 1 second). -/// -/// This assertion runs the run loop for 0.01 second after each time it checks the condition until -/// the condition is true or the timeout is reached. -/// -/// - Parameters: -/// - test: An autoclosure for the condition to test for truthiness. -/// - timeout: The timeout, at which point the test will fail. Defaults to 1 second. -/// - message: A message to send on failure. -public func XCTAssertTrueEventually(_ test: @autoclosure () -> Bool, timeout: TimeInterval = 1.0, message: String = "", file: StaticString = #file, line: UInt = #line) { - let runLoop = RunLoop.current - let timeoutDate = Date(timeIntervalSinceNow: timeout) - repeat { - if test() { - return - } - runLoop.run(until: Date(timeIntervalSinceNow: 0.01)) - } while Date().compare(timeoutDate) == .orderedAscending - - XCTFail(message, file: file, line: line) -} - -/// Checks that the condition is eventually false with a given timeout (default 1 second). -/// -/// This assertion runs the run loop for 0.01 second after each time it checks the condition until -/// the condition is false or the timeout is reached. -/// -/// - Parameters: -/// - test: An autoclosure for the condition to test for falsiness. -/// - timeout: The timeout, at which point the test will fail. Defaults to 1 second. -/// - message: A message to send on failure. -public func XCTAssertFalseEventually(_ test: @autoclosure () -> Bool, timeout: TimeInterval = 1.0, message: String = "", file: StaticString = #file, line: UInt = #line) { - XCTAssertTrueEventually(!test(), timeout: timeout, message: message, file: file, line: line) -} - -/// Downcast an expression to a specified type. -/// -/// Generates a failure when the downcast doesn't succeed. -/// -/// - Parameters: -/// - expression: An expression to downcast to `ExpectedType`. -/// - file: The file in which failure occurred. Defaults to the file name of the test case in which this function was called. -/// - line: The line number on which failure occurred. Defaults to the line number on which this function was called. -/// - Returns: A value of type `ExpectedType`, the result of evaluating and downcasting the given `expression`. -/// - Throws: An error when the downcast doesn't succeed. It will also rethrow any error thrown while evaluating the given expression. -public func XCTDowncast(_ expression: @autoclosure () throws -> AnyObject, to type: ExpectedType.Type, file: StaticString = #filePath, line: UInt = #line) throws -> ExpectedType { - let object = try expression() - - guard let expected = object as? ExpectedType else { - throw XCTFailure("Expected type to be \(ExpectedType.self), but found \(Swift.type(of: object))", file: file, line: line) - } - - return expected -} - -/// An error which causes the current test to cease executing and fail when it is thrown. -/// Similar to `XCTSkip`, but without marking the test as skipped. -public struct XCTFailure: Error, CustomNSError { - - public init(_ message: @autoclosure () -> String = "", file: StaticString = #filePath, line: UInt = #line) { - XCTFail(message(), file: file, line: line) - } - - /// The domain of the error. - public static let errorDomain = XCTestErrorDomain - - /// The error code within the given domain. - public let errorCode: Int = 0 - - /// The user-info dictionary. - public let errorUserInfo: [String : Any] = [ - // Make sure the thrown error doesn't show up as a test failure, because we already record - // a more detailed failure (with the right source location) ourselves. - "XCTestErrorUserInfoKeyShouldIgnore": true - ] -} diff --git a/Sources/ApolloTestSupport/XCTestCase+Helpers.swift b/Sources/ApolloTestSupport/XCTestCase+Helpers.swift deleted file mode 100644 index e5f942f36b..0000000000 --- a/Sources/ApolloTestSupport/XCTestCase+Helpers.swift +++ /dev/null @@ -1,79 +0,0 @@ -import XCTest -import ApolloUtils - -extension ApolloExtension where Base: XCTestExpectation { - /// Private API for accessing the number of times an expectation has been fulfilled. - public var numberOfFulfillments: Int { - base.value(forKey: "numberOfFulfillments") as! Int - } -} - -extension XCTestExpectation: ApolloCompatible {} - -public extension XCTestCase { - /// Record the specified`error` as an `XCTIssue`. - func record(_ error: Error, compactDescription: String? = nil, file: StaticString = #filePath, line: UInt = #line) { - var issue = XCTIssue(type: .thrownError, compactDescription: compactDescription ?? String(describing: error)) - - issue.associatedError = error - - let location = XCTSourceCodeLocation(filePath: file, lineNumber: line) - issue.sourceCodeContext = XCTSourceCodeContext(location: location) - - record(issue) - } - - /// Invoke a throwing closure, and record any thrown errors without rethrowing. This is useful if you need to run code that may throw - /// in a place where throwing isn't allowed, like `measure` blocks. - func whileRecordingErrors(file: StaticString = #file, line: UInt = #line, _ perform: () throws -> Void) { - do { - try perform() - } catch { - // Respect XCTestErrorUserInfoKeyShouldIgnore key that is used by XCTUnwrap, XCTSkip, and our own XCTFailure. - let shouldIgnore = (((error as NSError).userInfo["XCTestErrorUserInfoKeyShouldIgnore"] as? Bool) == true) - if !shouldIgnore { - record(error, file: file, line: line) - } - } - } - - /// Wrapper around `XCTContext.runActivity` to allow for future extension. - func runActivity(_ name: String, perform: (XCTActivity) throws -> Result) rethrows -> Result { - return try XCTContext.runActivity(named: name, block: perform) - } -} - -@testable import Apollo - -public extension XCTestCase { - /// Make an `AsyncResultObserver` for receiving results of the specified GraphQL operation. - func makeResultObserver(for operation: Operation, file: StaticString = #filePath, line: UInt = #line) -> AsyncResultObserver, Error> { - return AsyncResultObserver(testCase: self, file: file, line: line) - } -} - -public protocol StoreLoading { - static var defaultWaitTimeout: TimeInterval { get } - var store: ApolloStore! { get } -} - -public extension StoreLoading { - static var defaultWaitTimeout: TimeInterval { 1.0 } -} - -extension StoreLoading where Self: XCTestCase { - public func loadFromStore( - query: Operation, - file: StaticString = #filePath, - line: UInt = #line, - resultHandler: @escaping AsyncResultObserver, Error>.ResultHandler - ) { - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Loaded query from store", file: file, line: line, resultHandler: resultHandler) - - store.load(query: query, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Sources/ApolloUtils/ApolloCore.h b/Sources/ApolloUtils/ApolloCore.h deleted file mode 100644 index a8ef009628..0000000000 --- a/Sources/ApolloUtils/ApolloCore.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -//! Project version number for ApolloCore. -FOUNDATION_EXPORT double ApolloCoreVersionNumber; - -//! Project version string for Apollo. -FOUNDATION_EXPORT const unsigned char ApolloCoreVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Sources/ApolloUtils/ApolloExtension.swift b/Sources/ApolloUtils/ApolloExtension.swift deleted file mode 100644 index 3f102ee5e6..0000000000 --- a/Sources/ApolloUtils/ApolloExtension.swift +++ /dev/null @@ -1,76 +0,0 @@ -import Foundation - -/// Wrapper to allow calls to extended methods and vars as object.apollo.method -public struct ApolloExtension { - - /// The base type in the extension - public let base: Base -} - -/// Protocol to allow calls to extended methods and vars as object.apollo.method -/// -/// NOTE: This does not work with a bunch of stuff involving generic types - those -/// still need to use old-school `apollo_method` naming conventions. -public protocol ApolloCompatible { - /// The base type being extended - associatedtype Base - - /// The `ApolloExtension` object for an instance - var apollo: ApolloExtension { get } - - /// The `ApolloExtension` object for a type - static var apollo: ApolloExtension.Type { get } -} - -// MARK: - Default implementation - -extension ApolloCompatible { - public var apollo: ApolloExtension { - ApolloExtension(base: self) - } - - public static var apollo: ApolloExtension.Type { - ApolloExtension.self - } -} - -// MARK: - PAT Wrappers - -/// Provides a PAT interface to `Optional` -public protocol OptionalType: ExpressibleByNilLiteral { - associatedtype WrappedType - var underlying: WrappedType? { get } -} - -extension Optional: OptionalType { - /// Return the value if it exists, otherwise `nil` - public var underlying: Wrapped? { self } -} - -/// Provides a PAT interface to `Result` -public protocol ResultType { - associatedtype SuccessType - associatedtype FailureType: Error - - var underlying: Result { get } -} - -extension Result: ResultType { - - public var underlying: Result { self } -} - - -/// Provides a PAT interface to `Dictionary` -public protocol DictionaryType: ExpressibleByDictionaryLiteral { - associatedtype KeyType: Hashable - associatedtype ValueType - - var underlying: [KeyType: ValueType] { get } -} - -extension Dictionary: DictionaryType { - public var underlying: [Key: Value] { - self - } -} diff --git a/Sources/ApolloUtils/Atomic.swift b/Sources/ApolloUtils/Atomic.swift deleted file mode 100644 index d611a96704..0000000000 --- a/Sources/ApolloUtils/Atomic.swift +++ /dev/null @@ -1,44 +0,0 @@ -import Foundation - -/// Wrapper for a value protected by an NSLock -public class Atomic { - private let lock = NSLock() - private var _value: T - - /// Designated initializer - /// - /// - Parameter value: The value to begin with. - public init(_ value: T) { - _value = value - } - - /// The current value. Read-only. To update the underlying value, use `mutate`. - public var value: T { - lock.lock() - defer { lock.unlock() } - - return _value - } - - /// Mutates the underlying value within a lock. - /// - Parameter block: The block to execute to mutate the value. - /// - Returns: The value returned by the block. - public func mutate(block: (inout T) -> U) -> U { - lock.lock() - let result = block(&_value) - lock.unlock() - return result - } -} - -public extension Atomic where T == Int { - - /// Increments in a lock-compatible fashion - func increment() -> T { - lock.lock() - defer { lock.unlock() } - - _value += 1 - return _value - } -} diff --git a/Sources/ApolloUtils/Collection+Apollo.swift b/Sources/ApolloUtils/Collection+Apollo.swift deleted file mode 100644 index 0fedaaebef..0000000000 --- a/Sources/ApolloUtils/Collection+Apollo.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Foundation - -// MARK: - Emptiness + Optionality - -public extension ApolloExtension where Base: Collection { - - /// Convenience helper to make `guard` statements more readable - /// - /// - returns: `true` if the collection has contents. - var isNotEmpty: Bool { - return !base.isEmpty - } -} - -extension Array: ApolloCompatible {} -extension Dictionary: ApolloCompatible {} - -public extension ApolloExtension where Base: OptionalType, Base.WrappedType: Collection { - - /// - returns: `true` if the collection is empty or nil - var isEmptyOrNil: Bool { - switch base.underlying { - case .none: - return true - case .some(let collection): - return collection.isEmpty - } - } - - /// - returns: `true` if the collection is non-nil AND has contents. - var isNotEmpty: Bool { - switch base.underlying { - case .none: - return false - case .some(let collection): - return !collection.isEmpty - } - } -} - diff --git a/Sources/ApolloUtils/Info.plist b/Sources/ApolloUtils/Info.plist deleted file mode 100644 index 0e600e67e7..0000000000 --- a/Sources/ApolloUtils/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/ApolloUtils/String+SHA.swift b/Sources/ApolloUtils/String+SHA.swift deleted file mode 100644 index 08a4b7835e..0000000000 --- a/Sources/ApolloUtils/String+SHA.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation -import CommonCrypto - -extension String: ApolloCompatible {} - -extension ApolloExtension where Base == String { - - /// The SHA256 hash of the current string. - public var sha256Hash: String { - let data = base.data(using: .utf8)! - var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) - data.withUnsafeBytes { - _ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash) - } - - var hashString = "" - for byte in hash { - hashString += String(format:"%02x", UInt8(byte)) - } - return hashString - } -} diff --git a/Sources/ApolloWebSocket/DefaultImplementation/WebSocket.swift b/Sources/ApolloWebSocket/DefaultImplementation/WebSocket.swift index 6a597a4ca6..b4eb4fd3c2 100644 --- a/Sources/ApolloWebSocket/DefaultImplementation/WebSocket.swift +++ b/Sources/ApolloWebSocket/DefaultImplementation/WebSocket.swift @@ -40,7 +40,7 @@ public struct SSLSettings { //WebSocket implementation -open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStreamDelegate { +open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStreamDelegate, SOCKSProxyable { public enum OpCode : UInt8 { case continueFrame = 0x0 @@ -85,13 +85,14 @@ open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStream } } - struct Constants { + @_spi(Testable) + public struct Constants { static let headerWSUpgradeName = "Upgrade" static let headerWSUpgradeValue = "websocket" static let headerWSHostName = "Host" static let headerWSConnectionName = "Connection" static let headerWSConnectionValue = "Upgrade" - static let headerWSProtocolName = "Sec-WebSocket-Protocol" + public static let headerWSProtocolName = "Sec-WebSocket-Protocol" static let headerWSVersionName = "Sec-WebSocket-Version" static let headerWSVersionValue = "13" static let headerWSExtensionName = "Sec-WebSocket-Extensions" @@ -166,6 +167,29 @@ open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStream public var respondToPingWithPong: Bool = true + /// Determines whether a SOCKS proxy is enabled on the underlying request. + /// Mostly useful for debugging with tools like Charles Proxy. + /// Note: Will return `false` from the getter and no-op the setter for implementations that do not conform to `SOCKSProxyable`. + public var enableSOCKSProxy: Bool { + get { + guard let stream = stream as? SOCKSProxyable else { + // If it's not proxyable, then the proxy can't be enabled + return false + } + + return stream.enableSOCKSProxy + } + + set { + guard var stream = stream as? SOCKSProxyable else { + // If it's not proxyable, there's nothing to do here. + return + } + + stream.enableSOCKSProxy = newValue + } + } + // MARK: - Private private struct CompressionState { @@ -204,14 +228,10 @@ open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStream /// - Parameters: /// - request: A URL request object that provides request-specific information such as the URL. /// - protocol: Protocol to use for communication over the web socket. - public init(request: URLRequest, protocol: WSProtocol, enableSocksProxy: Bool = false) { + public init(request: URLRequest, protocol: WSProtocol) { self.request = request self.stream = FoundationStream() - if let stream = self.stream as? FoundationStream { - stream.enableSOCKSProxy = enableSocksProxy - } - if request.value(forHTTPHeaderField: Constants.headerOriginName) == nil { guard let url = request.url else {return} var origin = url.absoluteString @@ -266,14 +286,22 @@ open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStream } /** - Disconnect from the server. I send a Close control frame to the server, then expect the server to respond with a Close control frame and close the socket from its end. I notify my delegate once the socket has been closed. + Disconnect from the server. Send a Close control frame to the server, then expect the server to + respond with a Close control frame and close the socket from its end. Notify the delegate once + the socket has been closed. + + If `forceTimeout` > 0, wait at most that long (in seconds) for the server to close the socket. + After the timeout expires, close the socket (without sending a Close control frame) and notify + the delegate. - If you supply a non-nil `forceTimeout`, I wait at most that long (in seconds) for the server to close the socket. After the timeout expires, I close the socket and notify my delegate. + If `forceTimeout` <= 0, immediately close the socket (without sending a Close control frame) + and notify the delegate. - If you supply a zero (or negative) `forceTimeout`, I immediately close the socket (without sending a Close control frame) and notify my delegate. + If `forceTimeout` is `nil`, send the Close control frame to the server. - Parameter forceTimeout: Maximum time to wait for the server to close the socket. - - Parameter closeCode: The code to send on disconnect. The default is the normal close code for cleanly disconnecting a webSocket. + - Parameter closeCode: The code to send on disconnect. The default is the normal close code for + cleanly disconnecting a webSocket. */ func disconnect( forceTimeout: TimeInterval? = nil, @@ -295,8 +323,24 @@ open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStream } } - public func disconnect() { - self.disconnect(forceTimeout: nil, closeCode: CloseCode.normal.rawValue) + /** + Disconnect from the server. Send a Close control frame to the server, then expect the server to + respond with a Close control frame and close the socket from its end. Notify the delegate once + the socket has been closed. + + If `forceTimeout` > 0, wait at most that long (in seconds) for the server to close the socket. + After the timeout expires, close the socket (without sending a Close control frame) and notify + the delegate. + + If `forceTimeout` <= 0, immediately close the socket (without sending a Close control frame) + and notify the delegate. + + If `forceTimeout` is `nil`, send the Close control frame to the server. + + - Parameter forceTimeout: Maximum time to wait for the server to close the socket. + */ + public func disconnect(forceTimeout: TimeInterval?) { + self.disconnect(forceTimeout: forceTimeout, closeCode: CloseCode.normal.rawValue) } /** @@ -529,7 +573,7 @@ open class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStream let data = stream.read() guard let d = data else { return } var process = false - if inputQueue.count == 0 { + if inputQueue.isEmpty { process = true } inputQueue.append(d) diff --git a/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift b/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift index fa60ef4b60..88f978a28e 100644 --- a/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift +++ b/Sources/ApolloWebSocket/DefaultImplementation/WebSocketStream.swift @@ -15,6 +15,12 @@ protocol WebSocketStreamDelegate: AnyObject { func streamDidError(error: Error?) } +public protocol SOCKSProxyable { + /// Determines whether a SOCKS proxy is enabled on the underlying request. + /// Mostly useful for debugging with tools like Charles Proxy. + var enableSOCKSProxy: Bool { get set } +} + // This protocol is to allow custom implemention of the underlining stream. // This way custom socket libraries (e.g. linux) can be used protocol WebSocketStream { @@ -36,7 +42,7 @@ protocol WebSocketStream { #endif } -class FoundationStream : NSObject, WebSocketStream, StreamDelegate { +class FoundationStream : NSObject, WebSocketStream, StreamDelegate, SOCKSProxyable { private let workQueue = DispatchQueue(label: "com.apollographql.websocket", attributes: []) private var inputStream: InputStream? private var outputStream: OutputStream? diff --git a/Sources/ApolloWebSocket/Documentation.docc/Documentation.md b/Sources/ApolloWebSocket/Documentation.docc/Documentation.md new file mode 100644 index 0000000000..d26785ea43 --- /dev/null +++ b/Sources/ApolloWebSocket/Documentation.docc/Documentation.md @@ -0,0 +1,7 @@ +# ``ApolloWebSocket`` + +A web socket network transport implementation that provides support for [`GraphQLSubscription`](/documentation/apolloapi/graphqlsubscription) operations over a web socket connection. + +## Overview + +To support subscriptions over web sockets, initialize your [`ApolloClient`](/documentation/apollo/apolloclient) with a ``SplitNetworkTransport``. diff --git a/Sources/ApolloWebSocket/Info.plist b/Sources/ApolloWebSocket/Info.plist deleted file mode 100644 index 28165a5b96..0000000000 --- a/Sources/ApolloWebSocket/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ApolloWebSocket - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/ApolloWebSocket/OperationMessage.swift b/Sources/ApolloWebSocket/OperationMessage.swift index 96cb4da2de..520938e3c7 100644 --- a/Sources/ApolloWebSocket/OperationMessage.swift +++ b/Sources/ApolloWebSocket/OperationMessage.swift @@ -1,5 +1,6 @@ #if !COCOAPODS -import Apollo +import ApolloPGATOUR +import ApolloAPI #endif import Foundation @@ -25,7 +26,7 @@ final class OperationMessage { } let serializationFormat = JSONSerializationFormat.self - let message: GraphQLMap + let message: JSONEncodableDictionary var serialized: String? var rawMessage : String? { @@ -37,10 +38,10 @@ final class OperationMessage { } } - init(payload: GraphQLMap? = nil, + init(payload: JSONEncodableDictionary? = nil, id: String? = nil, type: Types) { - var message: GraphQLMap = [:] + var message: JSONEncodableDictionary = [:] if let payload = payload { message["payload"] = payload } diff --git a/Sources/ApolloWebSocket/OperationMessageIdCreator.swift b/Sources/ApolloWebSocket/OperationMessageIdCreator.swift index 2d84bc7a9e..2d3da731bb 100644 --- a/Sources/ApolloWebSocket/OperationMessageIdCreator.swift +++ b/Sources/ApolloWebSocket/OperationMessageIdCreator.swift @@ -1,6 +1,6 @@ import Foundation #if !COCOAPODS -import ApolloUtils +import ApolloPGATOUR #endif public protocol OperationMessageIdCreator { @@ -11,19 +11,19 @@ public protocol OperationMessageIdCreator { /// The default implementation of `OperationMessageIdCreator` that uses a sequential numbering scheme. public struct ApolloSequencedOperationMessageIdCreator: OperationMessageIdCreator { - private var sequenceNumberCounter = Atomic(0) + @Atomic private var sequenceNumberCounter: Int = 0 /// Designated initializer. /// /// - Parameter startAt: The number from which the sequenced numbering scheme should start. public init(startAt sequenceNumber: Int = 1) { - sequenceNumberCounter = Atomic(sequenceNumber) + _sequenceNumberCounter = Atomic(wrappedValue: sequenceNumber) } /// Returns the number in the current sequence. Will be incremented when calling this method. public func requestId() -> String { - let id = sequenceNumberCounter.value - _ = sequenceNumberCounter.increment() + let id = sequenceNumberCounter + _ = $sequenceNumberCounter.increment() return "\(id)" } diff --git a/Sources/ApolloWebSocket/Resources/PrivacyInfo.xcprivacy b/Sources/ApolloWebSocket/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000000..d37d6275f5 --- /dev/null +++ b/Sources/ApolloWebSocket/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + NSPrivacyTrackingDomains + + NSPrivacyTracking + + + diff --git a/Sources/ApolloWebSocket/SplitNetworkTransport.swift b/Sources/ApolloWebSocket/SplitNetworkTransport.swift index 7b9f6bb28b..9a2cf37db4 100644 --- a/Sources/ApolloWebSocket/SplitNetworkTransport.swift +++ b/Sources/ApolloWebSocket/SplitNetworkTransport.swift @@ -1,6 +1,7 @@ import Foundation #if !COCOAPODS -import Apollo +import ApolloPGATOUR +import ApolloAPI #endif /// A network transport that sends subscriptions using one `NetworkTransport` and other requests using another `NetworkTransport`. Ideal for sending subscriptions via a web socket but everything else via HTTP. @@ -46,18 +47,21 @@ extension SplitNetworkTransport: NetworkTransport { public func send(operation: Operation, cachePolicy: CachePolicy, contextIdentifier: UUID? = nil, + context: RequestContext? = nil, callbackQueue: DispatchQueue = .main, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable { - if operation.operationType == .subscription { + if Operation.operationType == .subscription { return webSocketNetworkTransport.send(operation: operation, cachePolicy: cachePolicy, contextIdentifier: contextIdentifier, + context: context, callbackQueue: callbackQueue, completionHandler: completionHandler) } else { return uploadingNetworkTransport.send(operation: operation, cachePolicy: cachePolicy, contextIdentifier: contextIdentifier, + context: context, callbackQueue: callbackQueue, completionHandler: completionHandler) } @@ -71,10 +75,12 @@ extension SplitNetworkTransport: UploadingNetworkTransport { public func upload( operation: Operation, files: [GraphQLFile], + context: RequestContext?, callbackQueue: DispatchQueue = .main, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable { return uploadingNetworkTransport.upload(operation: operation, files: files, + context: context, callbackQueue: callbackQueue, completionHandler: completionHandler) } diff --git a/Sources/ApolloWebSocket/WebSocketClient.swift b/Sources/ApolloWebSocket/WebSocketClient.swift index a51e7cb8d9..91b0e887c9 100644 --- a/Sources/ApolloWebSocket/WebSocketClient.swift +++ b/Sources/ApolloWebSocket/WebSocketClient.swift @@ -23,7 +23,7 @@ public protocol WebSocketClient: AnyObject { func connect() /// Disconnects from the websocket server. - func disconnect() + func disconnect(forceTimeout: TimeInterval?) /// Writes ping data to the websocket. func write(ping: Data, completion: (() -> Void)?) diff --git a/Sources/ApolloWebSocket/WebSocketError.swift b/Sources/ApolloWebSocket/WebSocketError.swift index 1d511e251e..7a0e3c8eff 100644 --- a/Sources/ApolloWebSocket/WebSocketError.swift +++ b/Sources/ApolloWebSocket/WebSocketError.swift @@ -1,5 +1,5 @@ #if !COCOAPODS -import Apollo +import ApolloAPI #endif import Foundation diff --git a/Sources/ApolloWebSocket/WebSocketTask.swift b/Sources/ApolloWebSocket/WebSocketTask.swift index 0420c1c199..839fd79561 100644 --- a/Sources/ApolloWebSocket/WebSocketTask.swift +++ b/Sources/ApolloWebSocket/WebSocketTask.swift @@ -1,5 +1,6 @@ #if !COCOAPODS -import Apollo +import ApolloPGATOUR +import ApolloAPI #endif import Foundation diff --git a/Sources/ApolloWebSocket/WebSocketTransport.swift b/Sources/ApolloWebSocket/WebSocketTransport.swift index ae35d1fa69..21d0ae42cf 100644 --- a/Sources/ApolloWebSocket/WebSocketTransport.swift +++ b/Sources/ApolloWebSocket/WebSocketTransport.swift @@ -1,6 +1,6 @@ #if !COCOAPODS -import Apollo -import ApolloUtils +import ApolloPGATOUR +import ApolloAPI #endif import Foundation @@ -26,14 +26,11 @@ public extension WebSocketTransportDelegate { public class WebSocketTransport { public weak var delegate: WebSocketTransportDelegate? - let connectOnInit: Bool - let reconnect: Atomic let websocket: WebSocketClient let store: ApolloStore? - let error: Atomic = Atomic(nil) + private(set) var config: Configuration + @Atomic var error: Error? let serializationFormat = JSONSerializationFormat.self - private let requestBodyCreator: RequestBodyCreator - private let operationMessageIdCreator: OperationMessageIdCreator /// non-private for testing - you should not use this directly enum SocketConnectionState { @@ -45,10 +42,10 @@ public class WebSocketTransport { self == .connected } } - var socketConnectionState = Atomic(.disconnected) + @Atomic var socketConnectionState: SocketConnectionState = .disconnected /// Indicates if the websocket connection has been acknowledged by the server. - private var timeoutTimer = Atomic(nil) + private var timeoutTimer = Atomic(wrappedValue: nil) private var ackTimeout: TimeInterval? { didSet { resetTimeoutTimer() @@ -59,81 +56,133 @@ public class WebSocketTransport { } private var queue: [Int: String] = [:] - private var connectingPayload: GraphQLMap? private var subscribers = [String: (Result) -> Void]() private var subscriptions : [String: String] = [:] let processingQueue = DispatchQueue(label: "com.apollographql.WebSocketTransport") - private let sendOperationIdentifiers: Bool - private let reconnectionInterval: TimeInterval - private let allowSendingDuplicates: Bool fileprivate var reconnected = false + var reconnect: Bool { + get { config.reconnect } + set { config.$reconnect.mutate { $0 = newValue } } + } + /// - NOTE: Setting this won't override immediately if the socket is still connected, only on reconnection. public var clientName: String { - didSet { + get { config.clientName } + set { + config.clientName = newValue self.addApolloClientHeaders(to: &self.websocket.request) } } /// - NOTE: Setting this won't override immediately if the socket is still connected, only on reconnection. public var clientVersion: String { - didSet { + get { config.clientVersion } + set { + config.clientVersion = newValue self.addApolloClientHeaders(to: &self.websocket.request) } } + public struct Configuration { + /// The client name to use for this client. Defaults to `Self.defaultClientName` + public fileprivate(set) var clientName: String + /// The client version to use for this client. Defaults to `Self.defaultClientVersion`. + public fileprivate(set) var clientVersion: String + /// Whether to auto reconnect when websocket looses connection. Defaults to true. + @Atomic public var reconnect: Bool + /// How long to wait before attempting to reconnect. Defaults to half a second. + public let reconnectionInterval: TimeInterval + /// Allow sending duplicate messages. Important when reconnected. Defaults to true. + public let allowSendingDuplicates: Bool + /// Whether the websocket connects immediately on creation. + /// If false, remember to call `resumeWebSocketConnection()` to connect. + /// Defaults to true. + public let connectOnInit: Bool + /// [optional]The payload to send on connection. Defaults to an empty `JSONEncodableDictionary`. + public fileprivate(set) var connectingPayload: JSONEncodableDictionary? + /// The `RequestBodyCreator` to use when serializing requests. Defaults to an `ApolloRequestBodyCreator`. + public let requestBodyCreator: RequestBodyCreator + /// The `OperationMessageIdCreator` used to generate a unique message identifier per request. + /// Defaults to `ApolloSequencedOperationMessageIdCreator`. + public let operationMessageIdCreator: OperationMessageIdCreator + + /// The designated initializer + public init( + clientName: String = WebSocketTransport.defaultClientName, + clientVersion: String = WebSocketTransport.defaultClientVersion, + reconnect: Bool = true, + reconnectionInterval: TimeInterval = 0.5, + allowSendingDuplicates: Bool = true, + connectOnInit: Bool = true, + connectingPayload: JSONEncodableDictionary? = [:], + requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator(), + operationMessageIdCreator: OperationMessageIdCreator = ApolloSequencedOperationMessageIdCreator() + ) { + self.clientName = clientName + self.clientVersion = clientVersion + self._reconnect = Atomic(wrappedValue: reconnect) + self.reconnectionInterval = reconnectionInterval + self.allowSendingDuplicates = allowSendingDuplicates + self.connectOnInit = connectOnInit + self.connectingPayload = connectingPayload + self.requestBodyCreator = requestBodyCreator + self.operationMessageIdCreator = operationMessageIdCreator + } + } + + /// Determines whether a SOCKS proxy is enabled on the underlying request. + /// Mostly useful for debugging with tools like Charles Proxy. + /// Note: Will return `false` from the getter and no-op the setter for implementations that do not conform to `SOCKSProxyable`. + public var enableSOCKSProxy: Bool { + get { + guard let websocket = websocket as? SOCKSProxyable else { + // If it's not proxyable, then the proxy can't be enabled + return false + } + + return websocket.enableSOCKSProxy + } + + set { + guard var websocket = websocket as? SOCKSProxyable else { + // If it's not proxyable, there's nothing to do here. + return + } + + websocket.enableSOCKSProxy = newValue + } + } + /// Designated initializer /// /// - Parameters: /// - websocket: The websocket client to use for creating a websocket connection. - /// - store: [optional] The `ApolloStore` used as a local cache. Defaults to `nil`. - /// - clientName: The client name to use for this client. Defaults to `Self.defaultClientName` - /// - clientVersion: The client version to use for this client. Defaults to `Self.defaultClientVersion`. - /// - sendOperationIdentifiers: Whether or not to send operation identifiers with operations. Defaults to false. - /// - reconnect: Whether to auto reconnect when websocket looses connection. Defaults to true. - /// - reconnectionInterval: How long to wait before attempting to reconnect. Defaults to half a second. - /// - allowSendingDuplicates: Allow sending duplicate messages. Important when reconnected. Defaults to true. - /// - connectOnInit: Whether the websocket connects immediately on creation. If false, remember to call `resumeWebSocketConnection()` to connect. Defaults to true. - /// - connectingPayload: [optional] The payload to send on connection. Defaults to an empty `GraphQLMap`. - /// - requestBodyCreator: The `RequestBodyCreator` to use when serializing requests. Defaults to an `ApolloRequestBodyCreator`. - /// - operationMessageIdCreator: The `OperationMessageIdCreator` used to generate a unique message identifier per request. Defaults to `ApolloSequencedOperationMessageIdCreator`. - public init(websocket: WebSocketClient, - store: ApolloStore? = nil, - clientName: String = WebSocketTransport.defaultClientName, - clientVersion: String = WebSocketTransport.defaultClientVersion, - sendOperationIdentifiers: Bool = false, - reconnect: Bool = true, - reconnectionInterval: TimeInterval = 0.5, - allowSendingDuplicates: Bool = true, - connectOnInit: Bool = true, - connectingPayload: GraphQLMap? = [:], - requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator(), - operationMessageIdCreator: OperationMessageIdCreator = ApolloSequencedOperationMessageIdCreator()) { + /// - store: [optional] The `ApolloStore` used as a local cache. + /// - config: A `WebSocketTransport.Configuration` object with options for configuring the + /// web socket connection. Defaults to a configuration with default values. + public init( + websocket: WebSocketClient, + store: ApolloStore? = nil, + config: Configuration = Configuration() + ) { self.websocket = websocket self.store = store - self.connectingPayload = connectingPayload - self.sendOperationIdentifiers = sendOperationIdentifiers - self.reconnect = Atomic(reconnect) - self.reconnectionInterval = reconnectionInterval - self.allowSendingDuplicates = allowSendingDuplicates - self.requestBodyCreator = requestBodyCreator - self.operationMessageIdCreator = operationMessageIdCreator - self.clientName = clientName - self.clientVersion = clientVersion - self.connectOnInit = connectOnInit + self.config = config + self.addApolloClientHeaders(to: &self.websocket.request) - + self.websocket.delegate = self - if connectOnInit { + if config.connectOnInit { self.websocket.connect() } self.websocket.callbackQueue = processingQueue } public func isConnected() -> Bool { - return self.socketConnectionState.value.isConnected + return self.socketConnectionState.isConnected } public func ping(data: Data, completionHandler: (() -> Void)? = nil) { @@ -269,14 +318,15 @@ public class WebSocketTransport { processingQueue.async { self.ackTimeout = nil - if let str = OperationMessage(payload: self.connectingPayload, type: .connectionInit).rawMessage { + if let str = OperationMessage(payload: self.config.connectingPayload, + type: .connectionInit).rawMessage { self.write(str, force:true) } } } public func closeConnection() { - self.reconnect.mutate { $0 = false } + self.reconnect = false let str = OperationMessage(type: .connectionTerminate).rawMessage processingQueue.async { @@ -292,7 +342,7 @@ public class WebSocketTransport { private func write(_ str: String, force forced: Bool = false, id: Int? = nil) { - if self.socketConnectionState.value.isConnected && (acked || forced) { + if self.socketConnectionState.isConnected && (acked || forced) { websocket.write(string: str) } else { // using sequence number to make sure that the queue is processed correctly @@ -308,16 +358,15 @@ public class WebSocketTransport { } deinit { - websocket.disconnect() + websocket.disconnect(forceTimeout: nil) self.websocket.delegate = nil } func sendHelper(operation: Operation, resultHandler: @escaping (_ result: Result) -> Void) -> String? { - let body = requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: self.sendOperationIdentifiers, + let body = config.requestBodyCreator.requestBody(for: operation, sendQueryDocument: true, autoPersistQuery: false) - let identifier = operationMessageIdCreator.requestId() + let identifier = config.operationMessageIdCreator.requestId() let messageType: OperationMessage.Types switch websocket.request.wsProtocol { @@ -334,7 +383,7 @@ public class WebSocketTransport { self.write(message) self.subscribers[identifier] = resultHandler - if operation.operationType == .subscription { + if Operation.operationType == .subscription { self.subscriptions[identifier] = message } } @@ -370,8 +419,8 @@ public class WebSocketTransport { } } - public func updateConnectingPayload(_ payload: GraphQLMap, reconnectIfConnected: Bool = true) { - self.connectingPayload = payload + public func updateConnectingPayload(_ payload: JSONEncodableDictionary, reconnectIfConnected: Bool = true) { + self.config.connectingPayload = payload if reconnectIfConnected && isConnected() { self.reconnectWebSocket() @@ -379,29 +428,30 @@ public class WebSocketTransport { } private func reconnectWebSocket() { - let oldReconnectValue = reconnect.value - self.reconnect.mutate { $0 = false } + let oldReconnectValue = reconnect + self.reconnect = false - self.websocket.disconnect() + self.websocket.disconnect(forceTimeout: 0) self.websocket.connect() - self.reconnect.mutate { $0 = oldReconnectValue } + self.reconnect = oldReconnectValue } /// Disconnects the websocket while setting the auto-reconnect value to false, /// allowing purposeful disconnects that do not dump existing subscriptions. /// NOTE: You will receive an error on the subscription (should be a `WebSocket.WSError` with code 1000) when the socket disconnects. + /// ALSO NOTE: In case pauseWebSocketConnection is called when app is backgrounded, app might get suspended within 5 seconds. In case disconnect did not complete within that time, websocket won't resume properly. That is why forceTimeout is set to 2 seconds. /// ALSO NOTE: To reconnect after calling this, you will need to call `resumeWebSocketConnection`. public func pauseWebSocketConnection() { - self.reconnect.mutate { $0 = false } - self.websocket.disconnect() + self.reconnect = false + self.websocket.disconnect(forceTimeout: 2.0) } /// Reconnects a paused web socket. /// /// - Parameter autoReconnect: `true` if you want the websocket to automatically reconnect if the connection drops. Defaults to true. public func resumeWebSocketConnection(autoReconnect: Bool = true) { - self.reconnect.mutate { $0 = autoReconnect } + self.reconnect = autoReconnect self.websocket.connect() } } @@ -427,6 +477,7 @@ extension WebSocketTransport: NetworkTransport { operation: Operation, cachePolicy: CachePolicy, contextIdentifier: UUID? = nil, + context: RequestContext? = nil, callbackQueue: DispatchQueue = .main, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable { @@ -436,7 +487,7 @@ extension WebSocketTransport: NetworkTransport { } } - if let error = self.error.value { + if let error = self.error { callCompletion(with: .failure(error)) return EmptyCancellable() } @@ -448,7 +499,7 @@ extension WebSocketTransport: NetworkTransport { let response = GraphQLResponse(operation: operation, body: jsonBody) if let store = store { - let (graphQLResult, parsedRecords) = try response.parseResult(cacheKeyForObject: store.cacheKeyForObject) + let (graphQLResult, parsedRecords) = try response.parseResult() guard let records = parsedRecords else { callCompletion(with: .success(graphQLResult)) return @@ -490,15 +541,15 @@ extension WebSocketTransport: WebSocketClientDelegate { } public func handleConnection() { - self.error.mutate { $0 = nil } - self.socketConnectionState.mutate { $0 = .connected } + self.$error.mutate { $0 = nil } + self.$socketConnectionState.mutate { $0 = .connected } initServer() if self.reconnected { self.delegate?.webSocketTransportDidReconnect(self) // re-send the subscriptions whenever we are re-connected // for the first connect, any subscriptions are already in queue for (_, msg) in self.subscriptions { - if self.allowSendingDuplicates { + if self.config.allowSendingDuplicates { write(msg) } else { // search duplicate message from the queue @@ -514,26 +565,25 @@ extension WebSocketTransport: WebSocketClientDelegate { } public func websocketDidDisconnect(socket: WebSocketClient, error: Error?) { - self.socketConnectionState.mutate { $0 = .disconnected } + self.$socketConnectionState.mutate { $0 = .disconnected } if let error = error { - debugPrint("websocket is disconnected: \(error)") handleDisconnection(with: error) + } else { - self.error.mutate { $0 = nil } - debugPrint("websocket is disconnected") + self.$error.mutate { $0 = nil } self.handleDisconnection() } } private func handleDisconnection(with error: Error) { // Set state to `.failed`, and grab its previous value. - let previousState: SocketConnectionState = self.socketConnectionState.mutate { socketConnectionState in + let previousState: SocketConnectionState = self.$socketConnectionState.mutate { socketConnectionState in let previousState = socketConnectionState socketConnectionState = .failed return previousState } // report any error to all subscribers - self.error.mutate { $0 = WebSocketError(payload: nil, + self.$error.mutate { $0 = WebSocketError(payload: nil, error: error, kind: .networkError) } self.notifyErrorAllHandlers(error) @@ -551,20 +601,20 @@ extension WebSocketTransport: WebSocketClientDelegate { } private func handleDisconnection() { - self.delegate?.webSocketTransport(self, didDisconnectWithError: self.error.value) + self.delegate?.webSocketTransport(self, didDisconnectWithError: self.error) self.ackTimeout = nil // need new connect and ack before sending self.attemptReconnectionIfDesired() } private func attemptReconnectionIfDesired() { - guard self.reconnect.value else { + guard self.reconnect else { return } - DispatchQueue.main.asyncAfter(deadline: .now() + reconnectionInterval) { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + config.reconnectionInterval) { [weak self] in guard let self = self else { return } - self.socketConnectionState.mutate { socketConnectionState in + self.$socketConnectionState.mutate { socketConnectionState in switch socketConnectionState { case .disconnected, .connected: break diff --git a/Sources/GitHubAPI/API.swift b/Sources/GitHubAPI/API.swift deleted file mode 100644 index dbed0d7037..0000000000 --- a/Sources/GitHubAPI/API.swift +++ /dev/null @@ -1,1268 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -public final class IssuesAndCommentsForRepositoryQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - "query IssuesAndCommentsForRepository { repository(name: \"apollo-ios\", owner: \"apollographql\") { __typename name issues(last: 100) { __typename nodes { __typename title author { __typename ...AuthorDetails } body comments(last: 100) { __typename nodes { __typename body author { __typename ...AuthorDetails } } } } } } }" - - public let operationName: String = "IssuesAndCommentsForRepository" - - public let operationIdentifier: String? = "187f0f83986b0269e8d0860e24c1b40ef4243ccbc86c15495076dabfef7a70c1" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + AuthorDetails.fragmentDefinition) - return document - } - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("repository", arguments: ["name": "apollo-ios", "owner": "apollographql"], type: .object(Repository.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(repository: Repository? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "repository": repository.flatMap { (value: Repository) -> ResultMap in value.resultMap }]) - } - - /// Lookup a given repository by the owner and repository name. - public var repository: Repository? { - get { - return (resultMap["repository"] as? ResultMap).flatMap { Repository(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "repository") - } - } - - public struct Repository: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Repository"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("issues", arguments: ["last": 100], type: .nonNull(.object(Issue.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, issues: Issue) { - self.init(unsafeResultMap: ["__typename": "Repository", "name": name, "issues": issues.resultMap]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the repository. - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// A list of issues that have been opened in the repository. - public var issues: Issue { - get { - return Issue(unsafeResultMap: resultMap["issues"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "issues") - } - } - - public struct Issue: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["IssueConnection"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("nodes", type: .list(.object(Node.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(nodes: [Node?]? = nil) { - self.init(unsafeResultMap: ["__typename": "IssueConnection", "nodes": nodes.flatMap { (value: [Node?]) -> [ResultMap?] in value.map { (value: Node?) -> ResultMap? in value.flatMap { (value: Node) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// A list of nodes. - public var nodes: [Node?]? { - get { - return (resultMap["nodes"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Node?] in value.map { (value: ResultMap?) -> Node? in value.flatMap { (value: ResultMap) -> Node in Node(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Node?]) -> [ResultMap?] in value.map { (value: Node?) -> ResultMap? in value.flatMap { (value: Node) -> ResultMap in value.resultMap } } }, forKey: "nodes") - } - } - - public struct Node: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Issue"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("title", type: .nonNull(.scalar(String.self))), - GraphQLField("author", type: .object(Author.selections)), - GraphQLField("body", type: .nonNull(.scalar(String.self))), - GraphQLField("comments", arguments: ["last": 100], type: .nonNull(.object(Comment.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(title: String, author: Author? = nil, body: String, comments: Comment) { - self.init(unsafeResultMap: ["__typename": "Issue", "title": title, "author": author.flatMap { (value: Author) -> ResultMap in value.resultMap }, "body": body, "comments": comments.resultMap]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Identifies the issue title. - public var title: String { - get { - return resultMap["title"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "title") - } - } - - /// The actor who authored the comment. - public var author: Author? { - get { - return (resultMap["author"] as? ResultMap).flatMap { Author(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "author") - } - } - - /// Identifies the body of the issue. - public var body: String { - get { - return resultMap["body"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "body") - } - } - - /// A list of comments associated with the Issue. - public var comments: Comment { - get { - return Comment(unsafeResultMap: resultMap["comments"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "comments") - } - } - - public struct Author: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["User": AsUser.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeBot(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Bot", "login": login]) - } - - public static func makeEnterpriseUserAccount(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "EnterpriseUserAccount", "login": login]) - } - - public static func makeMannequin(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Mannequin", "login": login]) - } - - public static func makeOrganization(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Organization", "login": login]) - } - - public static func makeUser(login: String, id: GraphQLID, name: String? = nil) -> Author { - return Author(unsafeResultMap: ["__typename": "User", "login": login, "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username of the actor. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var authorDetails: AuthorDetails { - get { - return AuthorDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - - public var asUser: AsUser? { - get { - if !AsUser.possibleTypes.contains(__typename) { return nil } - return AsUser(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsUser: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(login: String, id: GraphQLID, name: String? = nil) { - self.init(unsafeResultMap: ["__typename": "User", "login": login, "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username used to login. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The user's public profile name. - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var authorDetails: AuthorDetails { - get { - return AuthorDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } - - public struct Comment: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["IssueCommentConnection"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("nodes", type: .list(.object(Node.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(nodes: [Node?]? = nil) { - self.init(unsafeResultMap: ["__typename": "IssueCommentConnection", "nodes": nodes.flatMap { (value: [Node?]) -> [ResultMap?] in value.map { (value: Node?) -> ResultMap? in value.flatMap { (value: Node) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// A list of nodes. - public var nodes: [Node?]? { - get { - return (resultMap["nodes"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Node?] in value.map { (value: ResultMap?) -> Node? in value.flatMap { (value: ResultMap) -> Node in Node(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Node?]) -> [ResultMap?] in value.map { (value: Node?) -> ResultMap? in value.flatMap { (value: Node) -> ResultMap in value.resultMap } } }, forKey: "nodes") - } - } - - public struct Node: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["IssueComment"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("body", type: .nonNull(.scalar(String.self))), - GraphQLField("author", type: .object(Author.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(body: String, author: Author? = nil) { - self.init(unsafeResultMap: ["__typename": "IssueComment", "body": body, "author": author.flatMap { (value: Author) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The body as Markdown. - public var body: String { - get { - return resultMap["body"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "body") - } - } - - /// The actor who authored the comment. - public var author: Author? { - get { - return (resultMap["author"] as? ResultMap).flatMap { Author(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "author") - } - } - - public struct Author: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["User": AsUser.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeBot(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Bot", "login": login]) - } - - public static func makeEnterpriseUserAccount(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "EnterpriseUserAccount", "login": login]) - } - - public static func makeMannequin(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Mannequin", "login": login]) - } - - public static func makeOrganization(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Organization", "login": login]) - } - - public static func makeUser(login: String, id: GraphQLID, name: String? = nil) -> Author { - return Author(unsafeResultMap: ["__typename": "User", "login": login, "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username of the actor. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var authorDetails: AuthorDetails { - get { - return AuthorDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - - public var asUser: AsUser? { - get { - if !AsUser.possibleTypes.contains(__typename) { return nil } - return AsUser(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsUser: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(login: String, id: GraphQLID, name: String? = nil) { - self.init(unsafeResultMap: ["__typename": "User", "login": login, "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username used to login. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The user's public profile name. - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var authorDetails: AuthorDetails { - get { - return AuthorDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } - } - } - } - } - } - } -} - -public final class RepositoryQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - "query Repository { repository(owner: \"apollographql\", name: \"apollo-ios\") { __typename issueOrPullRequest(number: 13) { __typename ... on Issue { __typename body ... on UniformResourceLocatable { __typename url } author { __typename avatarUrl } } ... on Reactable { __typename viewerCanReact ... on Comment { __typename author { __typename login } } } } } }" - - public let operationName: String = "Repository" - - public let operationIdentifier: String? = "68de6d66c791c0d7b4fe4c21496b4623acb91c0086366aded49366f57e9f0b68" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("repository", arguments: ["owner": "apollographql", "name": "apollo-ios"], type: .object(Repository.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(repository: Repository? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "repository": repository.flatMap { (value: Repository) -> ResultMap in value.resultMap }]) - } - - /// Lookup a given repository by the owner and repository name. - public var repository: Repository? { - get { - return (resultMap["repository"] as? ResultMap).flatMap { Repository(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "repository") - } - } - - public struct Repository: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Repository"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("issueOrPullRequest", arguments: ["number": 13], type: .object(IssueOrPullRequest.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(issueOrPullRequest: IssueOrPullRequest? = nil) { - self.init(unsafeResultMap: ["__typename": "Repository", "issueOrPullRequest": issueOrPullRequest.flatMap { (value: IssueOrPullRequest) -> ResultMap in value.resultMap }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Returns a single issue-like object from the current repository by number. - public var issueOrPullRequest: IssueOrPullRequest? { - get { - return (resultMap["issueOrPullRequest"] as? ResultMap).flatMap { IssueOrPullRequest(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "issueOrPullRequest") - } - } - - public struct IssueOrPullRequest: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Issue", "PullRequest"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Issue": AsIssue.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("viewerCanReact", type: .nonNull(.scalar(Bool.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("author", type: .object(Author.selections)), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makePullRequest(viewerCanReact: Bool, author: Author? = nil) -> IssueOrPullRequest { - return IssueOrPullRequest(unsafeResultMap: ["__typename": "PullRequest", "viewerCanReact": viewerCanReact, "author": author.flatMap { (value: Author) -> ResultMap in value.resultMap }]) - } - - public static func makeIssue(body: String, url: String, author: AsIssue.Author? = nil, viewerCanReact: Bool) -> IssueOrPullRequest { - return IssueOrPullRequest(unsafeResultMap: ["__typename": "Issue", "body": body, "url": url, "author": author.flatMap { (value: AsIssue.Author) -> ResultMap in value.resultMap }, "viewerCanReact": viewerCanReact]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Can user react to this subject - public var viewerCanReact: Bool { - get { - return resultMap["viewerCanReact"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "viewerCanReact") - } - } - - /// The actor who authored the comment. - public var author: Author? { - get { - return (resultMap["author"] as? ResultMap).flatMap { Author(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "author") - } - } - - public struct Author: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeBot(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Bot", "login": login]) - } - - public static func makeEnterpriseUserAccount(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "EnterpriseUserAccount", "login": login]) - } - - public static func makeMannequin(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Mannequin", "login": login]) - } - - public static func makeOrganization(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Organization", "login": login]) - } - - public static func makeUser(login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "User", "login": login]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username of the actor. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - } - - public var asIssue: AsIssue? { - get { - if !AsIssue.possibleTypes.contains(__typename) { return nil } - return AsIssue(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsIssue: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Issue"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("body", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .nonNull(.scalar(String.self))), - GraphQLField("author", type: .object(Author.selections)), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("viewerCanReact", type: .nonNull(.scalar(Bool.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("author", type: .object(Author.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(body: String, url: String, author: Author? = nil, viewerCanReact: Bool) { - self.init(unsafeResultMap: ["__typename": "Issue", "body": body, "url": url, "author": author.flatMap { (value: Author) -> ResultMap in value.resultMap }, "viewerCanReact": viewerCanReact]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Identifies the body of the issue. - public var body: String { - get { - return resultMap["body"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "body") - } - } - - /// The HTTP URL for this issue - public var url: String { - get { - return resultMap["url"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - - /// The actor who authored the comment. - public var author: Author? { - get { - return (resultMap["author"] as? ResultMap).flatMap { Author(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "author") - } - } - - /// Can user react to this subject - public var viewerCanReact: Bool { - get { - return resultMap["viewerCanReact"]! as! Bool - } - set { - resultMap.updateValue(newValue, forKey: "viewerCanReact") - } - } - - public struct Author: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("avatarUrl", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeBot(avatarUrl: String, login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Bot", "avatarUrl": avatarUrl, "login": login]) - } - - public static func makeEnterpriseUserAccount(avatarUrl: String, login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "EnterpriseUserAccount", "avatarUrl": avatarUrl, "login": login]) - } - - public static func makeMannequin(avatarUrl: String, login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Mannequin", "avatarUrl": avatarUrl, "login": login]) - } - - public static func makeOrganization(avatarUrl: String, login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "Organization", "avatarUrl": avatarUrl, "login": login]) - } - - public static func makeUser(avatarUrl: String, login: String) -> Author { - return Author(unsafeResultMap: ["__typename": "User", "avatarUrl": avatarUrl, "login": login]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// A URL pointing to the actor's public avatar. - public var avatarUrl: String { - get { - return resultMap["avatarUrl"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "avatarUrl") - } - } - - /// The username of the actor. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - } - } - } - } - } -} - -public final class RepoUrlQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - "query RepoURL { repository(owner: \"apollographql\", name: \"apollo-ios\") { __typename url } }" - - public let operationName: String = "RepoURL" - - public let operationIdentifier: String? = "b55f22bcbfaea0d861089b3fbe06299675a21d11ba7138ace39ecbde606a3dc1" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("repository", arguments: ["owner": "apollographql", "name": "apollo-ios"], type: .object(Repository.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(repository: Repository? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "repository": repository.flatMap { (value: Repository) -> ResultMap in value.resultMap }]) - } - - /// Lookup a given repository by the owner and repository name. - public var repository: Repository? { - get { - return (resultMap["repository"] as? ResultMap).flatMap { Repository(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "repository") - } - } - - public struct Repository: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Repository"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("url", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(url: String) { - self.init(unsafeResultMap: ["__typename": "Repository", "url": url]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The HTTP URL for this repository - public var url: String { - get { - return resultMap["url"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "url") - } - } - } - } -} - -public struct AuthorDetails: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - "fragment AuthorDetails on Actor { __typename login ... on User { __typename id name } }" - - public static let possibleTypes: [String] = ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["User": AsUser.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeBot(login: String) -> AuthorDetails { - return AuthorDetails(unsafeResultMap: ["__typename": "Bot", "login": login]) - } - - public static func makeEnterpriseUserAccount(login: String) -> AuthorDetails { - return AuthorDetails(unsafeResultMap: ["__typename": "EnterpriseUserAccount", "login": login]) - } - - public static func makeMannequin(login: String) -> AuthorDetails { - return AuthorDetails(unsafeResultMap: ["__typename": "Mannequin", "login": login]) - } - - public static func makeOrganization(login: String) -> AuthorDetails { - return AuthorDetails(unsafeResultMap: ["__typename": "Organization", "login": login]) - } - - public static func makeUser(login: String, id: GraphQLID, name: String? = nil) -> AuthorDetails { - return AuthorDetails(unsafeResultMap: ["__typename": "User", "login": login, "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username of the actor. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - - public var asUser: AsUser? { - get { - if !AsUser.possibleTypes.contains(__typename) { return nil } - return AsUser(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsUser: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["User"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("login", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(login: String, id: GraphQLID, name: String? = nil) { - self.init(unsafeResultMap: ["__typename": "User", "login": login, "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The username used to login. - public var login: String { - get { - return resultMap["login"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "login") - } - } - - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The user's public profile name. - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } -} diff --git a/Sources/GitHubAPI/GitHubAPI.h b/Sources/GitHubAPI/GitHubAPI.h deleted file mode 100644 index 742b59d853..0000000000 --- a/Sources/GitHubAPI/GitHubAPI.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -//! Project version number for StarWarsAPI. -FOUNDATION_EXPORT double StarWarsAPIVersionNumber; - -//! Project version string for StarWarsAPI. -FOUNDATION_EXPORT const unsigned char StarWarsAPIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Sources/GitHubAPI/Info.plist b/Sources/GitHubAPI/Info.plist deleted file mode 100644 index 09738dfd75..0000000000 --- a/Sources/GitHubAPI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/GitHubAPI/graphql/Queries/IssuesAndCommentsForRepository.graphql b/Sources/GitHubAPI/graphql/Queries/IssuesAndCommentsForRepository.graphql deleted file mode 100644 index ce533b88da..0000000000 --- a/Sources/GitHubAPI/graphql/Queries/IssuesAndCommentsForRepository.graphql +++ /dev/null @@ -1,31 +0,0 @@ -query IssuesAndCommentsForRepository { - repository(name: "apollo-ios", owner: "apollographql") { - name - issues(last: 100) { - nodes { - title - author { - ...AuthorDetails - } - body - comments(last: 100) { - nodes { - body - author { - ...AuthorDetails - } - } - } - } - } - } -} - -fragment AuthorDetails on Actor { - login - ... on User { - id - name - } -} - diff --git a/Sources/GitHubAPI/graphql/Queries/Repository.graphql b/Sources/GitHubAPI/graphql/Queries/Repository.graphql deleted file mode 100644 index a98638e456..0000000000 --- a/Sources/GitHubAPI/graphql/Queries/Repository.graphql +++ /dev/null @@ -1,24 +0,0 @@ -query Repository { - repository(owner: "apollographql", name: "apollo-ios") { - issueOrPullRequest(number: 13) { - ... on Issue { - body - __typename - ... on UniformResourceLocatable { - url - } - author { - avatarUrl - } - } - ... on Reactable { - viewerCanReact - ... on Comment { - author { - login - } - } - } - } - } -} diff --git a/Sources/GitHubAPI/graphql/Queries/TestFolder/TestFolder2/TestFolder3/RepoURL.graphql b/Sources/GitHubAPI/graphql/Queries/TestFolder/TestFolder2/TestFolder3/RepoURL.graphql deleted file mode 100644 index 10f80cf4cb..0000000000 --- a/Sources/GitHubAPI/graphql/Queries/TestFolder/TestFolder2/TestFolder3/RepoURL.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query RepoURL { - repository(owner: "apollographql", name: "apollo-ios") { - url - } -} diff --git a/Sources/GitHubAPI/graphql/operationIDs.json b/Sources/GitHubAPI/graphql/operationIDs.json deleted file mode 100644 index b0577da579..0000000000 --- a/Sources/GitHubAPI/graphql/operationIDs.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "187f0f83986b0269e8d0860e24c1b40ef4243ccbc86c15495076dabfef7a70c1": { - "name": "IssuesAndCommentsForRepository", - "source": "query IssuesAndCommentsForRepository {\n repository(name: \"apollo-ios\", owner: \"apollographql\") {\n __typename\n name\n issues(last: 100) {\n __typename\n nodes {\n __typename\n title\n author {\n __typename\n ...AuthorDetails\n }\n body\n comments(last: 100) {\n __typename\n nodes {\n __typename\n body\n author {\n __typename\n ...AuthorDetails\n }\n }\n }\n }\n }\n }\n}\nfragment AuthorDetails on Actor {\n __typename\n login\n ... on User {\n __typename\n id\n name\n }\n}" - }, - "68de6d66c791c0d7b4fe4c21496b4623acb91c0086366aded49366f57e9f0b68": { - "name": "Repository", - "source": "query Repository {\n repository(owner: \"apollographql\", name: \"apollo-ios\") {\n __typename\n issueOrPullRequest(number: 13) {\n __typename\n ... on Issue {\n __typename\n body\n ... on UniformResourceLocatable {\n __typename\n url\n }\n author {\n __typename\n avatarUrl\n }\n }\n ... on Reactable {\n __typename\n viewerCanReact\n ... on Comment {\n __typename\n author {\n __typename\n login\n }\n }\n }\n }\n }\n}" - }, - "b55f22bcbfaea0d861089b3fbe06299675a21d11ba7138ace39ecbde606a3dc1": { - "name": "RepoURL", - "source": "query RepoURL {\n repository(owner: \"apollographql\", name: \"apollo-ios\") {\n __typename\n url\n }\n}" - } -} \ No newline at end of file diff --git a/Sources/GitHubAPI/graphql/schema.docs.graphql b/Sources/GitHubAPI/graphql/schema.docs.graphql deleted file mode 100644 index 7d8b8cc41c..0000000000 --- a/Sources/GitHubAPI/graphql/schema.docs.graphql +++ /dev/null @@ -1,38245 +0,0 @@ -""" -Defines what type of global IDs are accepted for a mutation argument of type ID. -""" -directive @possibleTypes( - """ - Abstract type of accepted global ID - """ - abstractType: String - - """ - Accepted types of global IDs. - """ - concreteTypes: [String!]! -) on INPUT_FIELD_DEFINITION - -""" -Marks an element of a GraphQL schema as only available via a preview header -""" -directive @preview( - """ - The identifier of the API preview that toggles this field. - """ - toggledBy: String! -) on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION - -""" -Autogenerated input type of AcceptEnterpriseAdministratorInvitation -""" -input AcceptEnterpriseAdministratorInvitationInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the invitation being accepted - """ - invitationId: ID! @possibleTypes(concreteTypes: ["EnterpriseAdministratorInvitation"]) -} - -""" -Autogenerated return type of AcceptEnterpriseAdministratorInvitation -""" -type AcceptEnterpriseAdministratorInvitationPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The invitation that was accepted. - """ - invitation: EnterpriseAdministratorInvitation - - """ - A message confirming the result of accepting an administrator invitation. - """ - message: String -} - -""" -Autogenerated input type of AcceptTopicSuggestion -""" -input AcceptTopicSuggestionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the suggested topic. - """ - name: String! - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of AcceptTopicSuggestion -""" -type AcceptTopicSuggestionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The accepted topic. - """ - topic: Topic -} - -""" -The possible capabilities for action executions setting. -""" -enum ActionExecutionCapabilitySetting { - """ - All action executions are enabled. - """ - ALL_ACTIONS - - """ - All action executions are disabled. - """ - DISABLED - - """ - Only actions defined within the repo are allowed. - """ - LOCAL_ACTIONS_ONLY - - """ - Organization administrators action execution capabilities. - """ - NO_POLICY -} - -""" -Represents an object which can take actions on GitHub. Typically a User or Bot. -""" -interface Actor { - """ - A URL pointing to the actor's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - The username of the actor. - """ - login: String! - - """ - The HTTP path for this actor. - """ - resourcePath: URI! - - """ - The HTTP URL for this actor. - """ - url: URI! -} - -""" -Location information for an actor -""" -type ActorLocation { - """ - City - """ - city: String - - """ - Country name - """ - country: String - - """ - Country code - """ - countryCode: String - - """ - Region name - """ - region: String - - """ - Region or state code - """ - regionCode: String -} - -""" -Autogenerated input type of AddAssigneesToAssignable -""" -input AddAssigneesToAssignableInput { - """ - The id of the assignable object to add assignees to. - """ - assignableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Assignable") - - """ - The id of users to add as assignees. - """ - assigneeIds: [ID!]! @possibleTypes(concreteTypes: ["User"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of AddAssigneesToAssignable -""" -type AddAssigneesToAssignablePayload { - """ - The item that was assigned. - """ - assignable: Assignable - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of AddComment -""" -input AddCommentInput { - """ - The contents of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "IssueOrPullRequest") -} - -""" -Autogenerated return type of AddComment -""" -type AddCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The edge from the subject's comment connection. - """ - commentEdge: IssueCommentEdge - - """ - The subject - """ - subject: Node - - """ - The edge from the subject's timeline connection. - """ - timelineEdge: IssueTimelineItemEdge -} - -""" -Autogenerated input type of AddLabelsToLabelable -""" -input AddLabelsToLabelableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ids of the labels to add. - """ - labelIds: [ID!]! @possibleTypes(concreteTypes: ["Label"]) - - """ - The id of the labelable object to add labels to. - """ - labelableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Labelable") -} - -""" -Autogenerated return type of AddLabelsToLabelable -""" -type AddLabelsToLabelablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was labeled. - """ - labelable: Labelable -} - -""" -Autogenerated input type of AddProjectCard -""" -input AddProjectCardInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The content of the card. Must be a member of the ProjectCardItem union - """ - contentId: ID @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "ProjectCardItem") - - """ - The note on the card. - """ - note: String - - """ - The Node ID of the ProjectColumn. - """ - projectColumnId: ID! @possibleTypes(concreteTypes: ["ProjectColumn"]) -} - -""" -Autogenerated return type of AddProjectCard -""" -type AddProjectCardPayload { - """ - The edge from the ProjectColumn's card connection. - """ - cardEdge: ProjectCardEdge - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ProjectColumn - """ - projectColumn: ProjectColumn -} - -""" -Autogenerated input type of AddProjectColumn -""" -input AddProjectColumnInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the column. - """ - name: String! - - """ - The Node ID of the project. - """ - projectId: ID! @possibleTypes(concreteTypes: ["Project"]) -} - -""" -Autogenerated return type of AddProjectColumn -""" -type AddProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The edge from the project's column connection. - """ - columnEdge: ProjectColumnEdge - - """ - The project - """ - project: Project -} - -""" -Autogenerated input type of AddPullRequestReviewComment -""" -input AddPullRequestReviewCommentInput { - """ - The text of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The SHA of the commit to comment on. - """ - commitOID: GitObjectID - - """ - The comment id to reply to. - """ - inReplyTo: ID @possibleTypes(concreteTypes: ["PullRequestReviewComment"]) - - """ - The relative path of the file to comment on. - """ - path: String - - """ - The line index in the diff to comment on. - """ - position: Int - - """ - The node ID of the pull request reviewing - """ - pullRequestId: ID @possibleTypes(concreteTypes: ["PullRequest"]) - - """ - The Node ID of the review to modify. - """ - pullRequestReviewId: ID @possibleTypes(concreteTypes: ["PullRequestReview"]) -} - -""" -Autogenerated return type of AddPullRequestReviewComment -""" -type AddPullRequestReviewCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created comment. - """ - comment: PullRequestReviewComment - - """ - The edge from the review's comment connection. - """ - commentEdge: PullRequestReviewCommentEdge -} - -""" -Autogenerated input type of AddPullRequestReview -""" -input AddPullRequestReviewInput { - """ - The contents of the review body comment. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The review line comments. - """ - comments: [DraftPullRequestReviewComment] - - """ - The commit OID the review pertains to. - """ - commitOID: GitObjectID - - """ - The event to perform on the pull request review. - """ - event: PullRequestReviewEvent - - """ - The Node ID of the pull request to modify. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) - - """ - The review line comment threads. - """ - threads: [DraftPullRequestReviewThread] -} - -""" -Autogenerated return type of AddPullRequestReview -""" -type AddPullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created pull request review. - """ - pullRequestReview: PullRequestReview - - """ - The edge from the pull request's review connection. - """ - reviewEdge: PullRequestReviewEdge -} - -""" -Autogenerated input type of AddPullRequestReviewThread -""" -input AddPullRequestReviewThreadInput { - """ - Body of the thread's first comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The line of the blob to which the thread refers. The end of the line range for multi-line comments. - """ - line: Int! - - """ - Path to the file being commented on. - """ - path: String! - - """ - The Node ID of the review to modify. - """ - pullRequestReviewId: ID! @possibleTypes(concreteTypes: ["PullRequestReview"]) - - """ - The side of the diff on which the line resides. For multi-line comments, this is the side for the end of the line range. - """ - side: DiffSide = RIGHT - - """ - The first line of the range to which the comment refers. - """ - startLine: Int - - """ - The side of the diff on which the start line resides. - """ - startSide: DiffSide = RIGHT -} - -""" -Autogenerated return type of AddPullRequestReviewThread -""" -type AddPullRequestReviewThreadPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created thread. - """ - thread: PullRequestReviewThread -} - -""" -Autogenerated input type of AddReaction -""" -input AddReactionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the emoji to react with. - """ - content: ReactionContent! - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! @possibleTypes(concreteTypes: ["CommitComment", "Issue", "IssueComment", "PullRequest", "PullRequestReview", "PullRequestReviewComment", "TeamDiscussion", "TeamDiscussionComment"], abstractType: "Reactable") -} - -""" -Autogenerated return type of AddReaction -""" -type AddReactionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The reaction object. - """ - reaction: Reaction - - """ - The reactable subject. - """ - subject: Reactable -} - -""" -Autogenerated input type of AddStar -""" -input AddStarInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Starrable ID to star. - """ - starrableId: ID! @possibleTypes(concreteTypes: ["Gist", "Repository", "Topic"], abstractType: "Starrable") -} - -""" -Autogenerated return type of AddStar -""" -type AddStarPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The starrable. - """ - starrable: Starrable -} - -""" -Represents a 'added_to_project' event on a given issue or pull request. -""" -type AddedToProjectEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Project referenced by event. - """ - project: Project @preview(toggledBy: "starfox-preview") - - """ - Project card referenced by this project event. - """ - projectCard: ProjectCard @preview(toggledBy: "starfox-preview") - - """ - Column name referenced by this project event. - """ - projectColumnName: String! @preview(toggledBy: "starfox-preview") -} - -""" -A GitHub App. -""" -type App implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The description of the app. - """ - description: String - id: ID! - - """ - The hex color code, without the leading '#', for the logo background. - """ - logoBackgroundColor: String! - - """ - A URL pointing to the app's logo. - """ - logoUrl( - """ - The size of the resulting image. - """ - size: Int - ): URI! - - """ - The name of the app. - """ - name: String! - - """ - A slug based on the name of the app for use in URLs. - """ - slug: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The URL to the app's homepage. - """ - url: URI! -} - -""" -Autogenerated input type of ArchiveRepository -""" -input ArchiveRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the repository to mark as archived. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of ArchiveRepository -""" -type ArchiveRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The repository that was marked as archived. - """ - repository: Repository -} - -""" -An object that can have users assigned to it. -""" -interface Assignable { - """ - A list of Users assigned to this object. - """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! -} - -""" -Represents an 'assigned' event on any assignable object. -""" -type AssignedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the assignable associated with the event. - """ - assignable: Assignable! - - """ - Identifies the user or mannequin that was assigned. - """ - assignee: Assignee - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the user who was assigned. - """ - user: User @deprecated(reason: "Assignees can now be mannequins. Use the `assignee` field instead. Removal on 2020-01-01 UTC.") -} - -""" -Types that can be assigned to issues. -""" -union Assignee = Bot | Mannequin | Organization | User - -""" -An entry in the audit log. -""" -interface AuditEntry { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Types that can initiate an audit log event. -""" -union AuditEntryActor = Bot | Organization | User - -""" -Ordering options for Audit Log connections. -""" -input AuditLogOrder { - """ - The ordering direction. - """ - direction: OrderDirection - - """ - The field to order Audit Logs by. - """ - field: AuditLogOrderField -} - -""" -Properties by which Audit Log connections can be ordered. -""" -enum AuditLogOrderField { - """ - Order audit log entries by timestamp - """ - CREATED_AT -} - -""" -Represents a 'automatic_base_change_failed' event on a given pull request. -""" -type AutomaticBaseChangeFailedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The new base for this PR - """ - newBase: String! - - """ - The old base for this PR - """ - oldBase: String! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Represents a 'automatic_base_change_succeeded' event on a given pull request. -""" -type AutomaticBaseChangeSucceededEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The new base for this PR - """ - newBase: String! - - """ - The old base for this PR - """ - oldBase: String! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Represents a 'base_ref_changed' event on a given issue or pull request. -""" -type BaseRefChangedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Represents a 'base_ref_force_pushed' event on a given pull request. -""" -type BaseRefForcePushedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the after commit SHA for the 'base_ref_force_pushed' event. - """ - afterCommit: Commit - - """ - Identifies the before commit SHA for the 'base_ref_force_pushed' event. - """ - beforeCommit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the fully qualified ref name for the 'base_ref_force_pushed' event. - """ - ref: Ref -} - -""" -Represents a Git blame. -""" -type Blame { - """ - The list of ranges from a Git blame. - """ - ranges: [BlameRange!]! -} - -""" -Represents a range of information from a Git blame. -""" -type BlameRange { - """ - Identifies the recency of the change, from 1 (new) to 10 (old). This is - calculated as a 2-quantile and determines the length of distance between the - median age of all the changes in the file and the recency of the current - range's change. - """ - age: Int! - - """ - Identifies the line author - """ - commit: Commit! - - """ - The ending line for the range - """ - endingLine: Int! - - """ - The starting line for the range - """ - startingLine: Int! -} - -""" -Represents a Git blob. -""" -type Blob implements GitObject & Node { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - Byte size of Blob object - """ - byteSize: Int! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - id: ID! - - """ - Indicates whether the Blob is binary or text. Returns null if unable to determine the encoding. - """ - isBinary: Boolean - - """ - Indicates whether the contents is truncated - """ - isTruncated: Boolean! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! - - """ - UTF8 text data or null if the Blob is binary - """ - text: String -} - -""" -A special type of user which takes actions on behalf of GitHub Apps. -""" -type Bot implements Actor & Node & UniformResourceLocatable { - """ - A URL pointing to the GitHub App's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The username of the actor. - """ - login: String! - - """ - The HTTP path for this bot - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this bot - """ - url: URI! -} - -""" -A branch protection rule. -""" -type BranchProtectionRule implements Node { - """ - A list of conflicts matching branches protection rule and other branch protection rules - """ - branchProtectionRuleConflicts( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): BranchProtectionRuleConflictConnection! - - """ - The actor who created this branch protection rule. - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - Will new commits pushed to matching branches dismiss pull request review approvals. - """ - dismissesStaleReviews: Boolean! - id: ID! - - """ - Can admins overwrite branch protection. - """ - isAdminEnforced: Boolean! - - """ - Repository refs that are protected by this rule - """ - matchingRefs( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filters refs with query on name - """ - query: String - ): RefConnection! - - """ - Identifies the protection rule pattern. - """ - pattern: String! - - """ - A list push allowances for this branch protection rule. - """ - pushAllowances( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PushAllowanceConnection! - - """ - The repository associated with this branch protection rule. - """ - repository: Repository - - """ - Number of approving reviews required to update matching branches. - """ - requiredApprovingReviewCount: Int - - """ - List of required status check contexts that must pass for commits to be accepted to matching branches. - """ - requiredStatusCheckContexts: [String] - - """ - Are approving reviews required to update matching branches. - """ - requiresApprovingReviews: Boolean! - - """ - Are reviews from code owners required to update matching branches. - """ - requiresCodeOwnerReviews: Boolean! - - """ - Are commits required to be signed. - """ - requiresCommitSignatures: Boolean! - - """ - Are status checks required to update matching branches. - """ - requiresStatusChecks: Boolean! - - """ - Are branches required to be up to date before merging. - """ - requiresStrictStatusChecks: Boolean! - - """ - Is pushing to matching branches restricted. - """ - restrictsPushes: Boolean! - - """ - Is dismissal of pull request reviews restricted. - """ - restrictsReviewDismissals: Boolean! - - """ - A list review dismissal allowances for this branch protection rule. - """ - reviewDismissalAllowances( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ReviewDismissalAllowanceConnection! -} - -""" -A conflict between two branch protection rules. -""" -type BranchProtectionRuleConflict { - """ - Identifies the branch protection rule. - """ - branchProtectionRule: BranchProtectionRule - - """ - Identifies the conflicting branch protection rule. - """ - conflictingBranchProtectionRule: BranchProtectionRule - - """ - Identifies the branch ref that has conflicting rules - """ - ref: Ref -} - -""" -The connection type for BranchProtectionRuleConflict. -""" -type BranchProtectionRuleConflictConnection { - """ - A list of edges. - """ - edges: [BranchProtectionRuleConflictEdge] - - """ - A list of nodes. - """ - nodes: [BranchProtectionRuleConflict] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type BranchProtectionRuleConflictEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: BranchProtectionRuleConflict -} - -""" -The connection type for BranchProtectionRule. -""" -type BranchProtectionRuleConnection { - """ - A list of edges. - """ - edges: [BranchProtectionRuleEdge] - - """ - A list of nodes. - """ - nodes: [BranchProtectionRule] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type BranchProtectionRuleEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: BranchProtectionRule -} - -""" -Autogenerated input type of CancelEnterpriseAdminInvitation -""" -input CancelEnterpriseAdminInvitationInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pending enterprise administrator invitation. - """ - invitationId: ID! @possibleTypes(concreteTypes: ["EnterpriseAdministratorInvitation"]) -} - -""" -Autogenerated return type of CancelEnterpriseAdminInvitation -""" -type CancelEnterpriseAdminInvitationPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The invitation that was canceled. - """ - invitation: EnterpriseAdministratorInvitation - - """ - A message confirming the result of canceling an administrator invitation. - """ - message: String -} - -""" -Autogenerated input type of ChangeUserStatus -""" -input ChangeUserStatusInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The emoji to represent your status. Can either be a native Unicode emoji or an emoji name with colons, e.g., :grinning:. - """ - emoji: String - - """ - If set, the user status will not be shown after this date. - """ - expiresAt: DateTime - - """ - Whether this status should indicate you are not fully available on GitHub, e.g., you are away. - """ - limitedAvailability: Boolean = false - - """ - A short description of your current status. - """ - message: String - - """ - The ID of the organization whose members will be allowed to see the status. If - omitted, the status will be publicly visible. - """ - organizationId: ID @possibleTypes(concreteTypes: ["Organization"]) -} - -""" -Autogenerated return type of ChangeUserStatus -""" -type ChangeUserStatusPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Your updated status. - """ - status: UserStatus -} - -""" -A single check annotation. -""" -type CheckAnnotation @preview(toggledBy: "antiope-preview") { - """ - The annotation's severity level. - """ - annotationLevel: CheckAnnotationLevel - - """ - The path to the file that this annotation was made on. - """ - blobUrl: URI! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The position of this annotation. - """ - location: CheckAnnotationSpan! - - """ - The annotation's message. - """ - message: String! - - """ - The path that this annotation was made on. - """ - path: String! - - """ - Additional information about the annotation. - """ - rawDetails: String - - """ - The annotation's title - """ - title: String -} - -""" -The connection type for CheckAnnotation. -""" -type CheckAnnotationConnection { - """ - A list of edges. - """ - edges: [CheckAnnotationEdge] - - """ - A list of nodes. - """ - nodes: [CheckAnnotation] @preview(toggledBy: "antiope-preview") - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Information from a check run analysis to specific lines of code. -""" -input CheckAnnotationData @preview(toggledBy: "antiope-preview") { - """ - Represents an annotation's information level - """ - annotationLevel: CheckAnnotationLevel! - - """ - The location of the annotation - """ - location: CheckAnnotationRange! - - """ - A short description of the feedback for these lines of code. - """ - message: String! - - """ - The path of the file to add an annotation to. - """ - path: String! - - """ - Details about this annotation. - """ - rawDetails: String - - """ - The title that represents the annotation. - """ - title: String -} - -""" -An edge in a connection. -""" -type CheckAnnotationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CheckAnnotation @preview(toggledBy: "antiope-preview") -} - -""" -Represents an annotation's information level. -""" -enum CheckAnnotationLevel @preview(toggledBy: "antiope-preview") { - """ - An annotation indicating an inescapable error. - """ - FAILURE - - """ - An annotation indicating some information. - """ - NOTICE - - """ - An annotation indicating an ignorable error. - """ - WARNING -} - -""" -A character position in a check annotation. -""" -type CheckAnnotationPosition @preview(toggledBy: "antiope-preview") { - """ - Column number (1 indexed). - """ - column: Int - - """ - Line number (1 indexed). - """ - line: Int! -} - -""" -Information from a check run analysis to specific lines of code. -""" -input CheckAnnotationRange @preview(toggledBy: "antiope-preview") { - """ - The ending column of the range. - """ - endColumn: Int - - """ - The ending line of the range. - """ - endLine: Int! - - """ - The starting column of the range. - """ - startColumn: Int - - """ - The starting line of the range. - """ - startLine: Int! -} - -""" -An inclusive pair of positions for a check annotation. -""" -type CheckAnnotationSpan @preview(toggledBy: "antiope-preview") { - """ - End position (inclusive). - """ - end: CheckAnnotationPosition! - - """ - Start position (inclusive). - """ - start: CheckAnnotationPosition! -} - -""" -The possible states for a check suite or run conclusion. -""" -enum CheckConclusionState @preview(toggledBy: "antiope-preview") { - """ - The check suite or run requires action. - """ - ACTION_REQUIRED - - """ - The check suite or run has been cancelled. - """ - CANCELLED - - """ - The check suite or run has failed. - """ - FAILURE - - """ - The check suite or run was neutral. - """ - NEUTRAL - - """ - The check suite or run was skipped. - """ - SKIPPED - - """ - The check suite or run was marked stale by GitHub. Only GitHub can use this conclusion. - """ - STALE - - """ - The check suite or run has succeeded. - """ - SUCCESS - - """ - The check suite or run has timed out. - """ - TIMED_OUT -} - -""" -A check run. -""" -type CheckRun implements Node & UniformResourceLocatable @preview(toggledBy: "antiope-preview") { - """ - The check run's annotations - """ - annotations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CheckAnnotationConnection - - """ - The check suite that this run is a part of. - """ - checkSuite: CheckSuite! - - """ - Identifies the date and time when the check run was completed. - """ - completedAt: DateTime - - """ - The conclusion of the check run. - """ - conclusion: CheckConclusionState - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The URL from which to find full details of the check run on the integrator's site. - """ - detailsUrl: URI - - """ - A reference for the check run on the integrator's system. - """ - externalId: String - id: ID! - - """ - The name of the check for this check run. - """ - name: String! - - """ - The permalink to the check run summary. - """ - permalink: URI! - - """ - The repository associated with this check run. - """ - repository: Repository! - - """ - The HTTP path for this check run. - """ - resourcePath: URI! - - """ - Identifies the date and time when the check run was started. - """ - startedAt: DateTime - - """ - The current status of the check run. - """ - status: CheckStatusState! - - """ - A string representing the check run's summary - """ - summary: String - - """ - A string representing the check run's text - """ - text: String - - """ - A string representing the check run - """ - title: String - - """ - The HTTP URL for this check run. - """ - url: URI! -} - -""" -Possible further actions the integrator can perform. -""" -input CheckRunAction @preview(toggledBy: "antiope-preview") { - """ - A short explanation of what this action would do. - """ - description: String! - - """ - A reference for the action on the integrator's system. - """ - identifier: String! - - """ - The text to be displayed on a button in the web UI. - """ - label: String! -} - -""" -The connection type for CheckRun. -""" -type CheckRunConnection { - """ - A list of edges. - """ - edges: [CheckRunEdge] - - """ - A list of nodes. - """ - nodes: [CheckRun] @preview(toggledBy: "antiope-preview") - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CheckRunEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CheckRun @preview(toggledBy: "antiope-preview") -} - -""" -The filters that are available when fetching check runs. -""" -input CheckRunFilter @preview(toggledBy: "antiope-preview") { - """ - Filters the check runs created by this application ID. - """ - appId: Int - - """ - Filters the check runs by this name. - """ - checkName: String - - """ - Filters the check runs by this type. - """ - checkType: CheckRunType - - """ - Filters the check runs by this status. - """ - status: CheckStatusState -} - -""" -Descriptive details about the check run. -""" -input CheckRunOutput @preview(toggledBy: "antiope-preview") { - """ - The annotations that are made as part of the check run. - """ - annotations: [CheckAnnotationData!] - - """ - Images attached to the check run output displayed in the GitHub pull request UI. - """ - images: [CheckRunOutputImage!] - - """ - The summary of the check run (supports Commonmark). - """ - summary: String! - - """ - The details of the check run (supports Commonmark). - """ - text: String - - """ - A title to provide for this check run. - """ - title: String! -} - -""" -Images attached to the check run output displayed in the GitHub pull request UI. -""" -input CheckRunOutputImage @preview(toggledBy: "antiope-preview") { - """ - The alternative text for the image. - """ - alt: String! - - """ - A short image description. - """ - caption: String - - """ - The full URL of the image. - """ - imageUrl: URI! -} - -""" -The possible types of check runs. -""" -enum CheckRunType @preview(toggledBy: "antiope-preview") { - """ - Every check run available. - """ - ALL - - """ - The latest check run. - """ - LATEST -} - -""" -The possible states for a check suite or run status. -""" -enum CheckStatusState @preview(toggledBy: "antiope-preview") { - """ - The check suite or run has been completed. - """ - COMPLETED - - """ - The check suite or run is in progress. - """ - IN_PROGRESS - - """ - The check suite or run has been queued. - """ - QUEUED - - """ - The check suite or run has been requested. - """ - REQUESTED -} - -""" -A check suite. -""" -type CheckSuite implements Node @preview(toggledBy: "antiope-preview") { - """ - The GitHub App which created this check suite. - """ - app: App - - """ - The name of the branch for this check suite. - """ - branch: Ref - - """ - The check runs associated with a check suite. - """ - checkRuns( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filters the check runs by this type. - """ - filterBy: CheckRunFilter - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CheckRunConnection - - """ - The commit for this check suite - """ - commit: Commit! - - """ - The conclusion of this check suite. - """ - conclusion: CheckConclusionState - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - A list of open pull requests matching the check suite. - """ - matchingPullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection - - """ - The push that triggered this check suite. - """ - push: Push - - """ - The repository associated with this check suite. - """ - repository: Repository! - - """ - The HTTP path for this check suite - """ - resourcePath: URI! - - """ - The status of this check suite. - """ - status: CheckStatusState! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this check suite - """ - url: URI! -} - -""" -The auto-trigger preferences that are available for check suites. -""" -input CheckSuiteAutoTriggerPreference @preview(toggledBy: "antiope-preview") { - """ - The node ID of the application that owns the check suite. - """ - appId: ID! - - """ - Set to `true` to enable automatic creation of CheckSuite events upon pushes to the repository. - """ - setting: Boolean! -} - -""" -The connection type for CheckSuite. -""" -type CheckSuiteConnection { - """ - A list of edges. - """ - edges: [CheckSuiteEdge] - - """ - A list of nodes. - """ - nodes: [CheckSuite] @preview(toggledBy: "antiope-preview") - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CheckSuiteEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CheckSuite @preview(toggledBy: "antiope-preview") -} - -""" -The filters that are available when fetching check suites. -""" -input CheckSuiteFilter @preview(toggledBy: "antiope-preview") { - """ - Filters the check suites created by this application ID. - """ - appId: Int - - """ - Filters the check suites by this name. - """ - checkName: String -} - -""" -Autogenerated input type of ClearLabelsFromLabelable -""" -input ClearLabelsFromLabelableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the labelable object to clear the labels from. - """ - labelableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Labelable") -} - -""" -Autogenerated return type of ClearLabelsFromLabelable -""" -type ClearLabelsFromLabelablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was unlabeled. - """ - labelable: Labelable -} - -""" -Autogenerated input type of CloneProject -""" -input CloneProjectInput { - """ - The description of the project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Whether or not to clone the source project's workflows. - """ - includeWorkflows: Boolean! - - """ - The name of the project. - """ - name: String! - - """ - The visibility of the project, defaults to false (private). - """ - public: Boolean - - """ - The source project to clone. - """ - sourceId: ID! @possibleTypes(concreteTypes: ["Project"]) - - """ - The owner ID to create the project under. - """ - targetOwnerId: ID! @possibleTypes(concreteTypes: ["Organization", "Repository", "User"], abstractType: "ProjectOwner") -} - -""" -Autogenerated return type of CloneProject -""" -type CloneProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the JobStatus for populating cloned fields. - """ - jobStatusId: String - - """ - The new cloned project. - """ - project: Project -} - -""" -Autogenerated input type of CloneTemplateRepository -""" -input CloneTemplateRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A short description of the new repository. - """ - description: String - - """ - Whether to copy all branches from the template to the new repository. Defaults - to copying only the default branch of the template. - """ - includeAllBranches: Boolean = false - - """ - The name of the new repository. - """ - name: String! - - """ - The ID of the owner for the new repository. - """ - ownerId: ID! @possibleTypes(concreteTypes: ["Organization", "User"], abstractType: "RepositoryOwner") - - """ - The Node ID of the template repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - Indicates the repository's visibility level. - """ - visibility: RepositoryVisibility! -} - -""" -Autogenerated return type of CloneTemplateRepository -""" -type CloneTemplateRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new repository. - """ - repository: Repository -} - -""" -An object that can be closed -""" -interface Closable { - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime -} - -""" -Autogenerated input type of CloseIssue -""" -input CloseIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue to be closed. - """ - issueId: ID! @possibleTypes(concreteTypes: ["Issue"]) -} - -""" -Autogenerated return type of CloseIssue -""" -type CloseIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was closed. - """ - issue: Issue -} - -""" -Autogenerated input type of ClosePullRequest -""" -input ClosePullRequestInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the pull request to be closed. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) -} - -""" -Autogenerated return type of ClosePullRequest -""" -type ClosePullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that was closed. - """ - pullRequest: PullRequest -} - -""" -Represents a 'closed' event on any `Closable`. -""" -type ClosedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Object that was closed. - """ - closable: Closable! - - """ - Object which triggered the creation of this event. - """ - closer: Closer - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The HTTP path for this closed event. - """ - resourcePath: URI! - - """ - The HTTP URL for this closed event. - """ - url: URI! -} - -""" -The object which triggered a `ClosedEvent`. -""" -union Closer = Commit | PullRequest - -""" -The Code of Conduct for a repository -""" -type CodeOfConduct implements Node { - """ - The body of the Code of Conduct - """ - body: String - id: ID! - - """ - The key for the Code of Conduct - """ - key: String! - - """ - The formal name of the Code of Conduct - """ - name: String! - - """ - The HTTP path for this Code of Conduct - """ - resourcePath: URI - - """ - The HTTP URL for this Code of Conduct - """ - url: URI -} - -""" -Collaborators affiliation level with a subject. -""" -enum CollaboratorAffiliation { - """ - All collaborators the authenticated user can see. - """ - ALL - - """ - All collaborators with permissions to an organization-owned subject, regardless of organization membership status. - """ - DIRECT - - """ - All outside collaborators of an organization-owned subject. - """ - OUTSIDE -} - -""" -Represents a comment. -""" -interface Comment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -A comment author association with repository. -""" -enum CommentAuthorAssociation { - """ - Author has been invited to collaborate on the repository. - """ - COLLABORATOR - - """ - Author has previously committed to the repository. - """ - CONTRIBUTOR - - """ - Author has not previously committed to GitHub. - """ - FIRST_TIMER - - """ - Author has not previously committed to the repository. - """ - FIRST_TIME_CONTRIBUTOR - - """ - Author is a member of the organization that owns the repository. - """ - MEMBER - - """ - Author has no association with the repository. - """ - NONE - - """ - Author is the owner of the repository. - """ - OWNER -} - -""" -The possible errors that will prevent a user from updating a comment. -""" -enum CommentCannotUpdateReason { - """ - Unable to create comment because repository is archived. - """ - ARCHIVED - - """ - You cannot update this comment - """ - DENIED - - """ - You must be the author or have write access to this repository to update this comment. - """ - INSUFFICIENT_ACCESS - - """ - Unable to create comment because issue is locked. - """ - LOCKED - - """ - You must be logged in to update this comment. - """ - LOGIN_REQUIRED - - """ - Repository is under maintenance. - """ - MAINTENANCE - - """ - At least one email address must be verified to update this comment. - """ - VERIFIED_EMAIL_REQUIRED -} - -""" -Represents a 'comment_deleted' event on a given issue or pull request. -""" -type CommentDeletedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Represents a Git commit. -""" -type Commit implements GitObject & Node & Subscribable & UniformResourceLocatable { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The number of additions in this commit. - """ - additions: Int! - - """ - The pull requests associated with a commit - """ - associatedPullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests. - """ - orderBy: PullRequestOrder = {field: CREATED_AT, direction: ASC} - ): PullRequestConnection - - """ - Authorship details of the commit. - """ - author: GitActor - - """ - Check if the committer and the author match. - """ - authoredByCommitter: Boolean! - - """ - The datetime when this commit was authored. - """ - authoredDate: DateTime! - - """ - Fetches `git blame` information. - """ - blame( - """ - The file whose Git blame information you want. - """ - path: String! - ): Blame! - - """ - The number of changed files in this commit. - """ - changedFiles: Int! - - """ - The check suites associated with a commit. - """ - checkSuites( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filters the check suites by this type. - """ - filterBy: CheckSuiteFilter - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CheckSuiteConnection @preview(toggledBy: "antiope-preview") - - """ - Comments made on the commit. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - - """ - The datetime when this commit was committed. - """ - committedDate: DateTime! - - """ - Check if commited via GitHub web UI. - """ - committedViaWeb: Boolean! - - """ - Committership details of the commit. - """ - committer: GitActor - - """ - The number of deletions in this commit. - """ - deletions: Int! - - """ - The deployments associated with a commit. - """ - deployments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Environments to list deployments for - """ - environments: [String!] - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for deployments returned from the connection. - """ - orderBy: DeploymentOrder = {field: CREATED_AT, direction: ASC} - ): DeploymentConnection - - """ - The linear commit history starting from (and including) this commit, in the same order as `git log`. - """ - history( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - If non-null, filters history to only show commits with matching authorship. - """ - author: CommitAuthor - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - If non-null, filters history to only show commits touching files under this path. - """ - path: String - - """ - Allows specifying a beginning time or date for fetching commits. - """ - since: GitTimestamp - - """ - Allows specifying an ending time or date for fetching commits. - """ - until: GitTimestamp - ): CommitHistoryConnection! - id: ID! - - """ - The Git commit message - """ - message: String! - - """ - The Git commit message body - """ - messageBody: String! - - """ - The commit message body rendered to HTML. - """ - messageBodyHTML: HTML! - - """ - The Git commit message headline - """ - messageHeadline: String! - - """ - The commit message headline rendered to HTML. - """ - messageHeadlineHTML: HTML! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The organization this commit was made on behalf of. - """ - onBehalfOf: Organization - - """ - The parents of a commit. - """ - parents( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitConnection! - - """ - The datetime when this commit was pushed. - """ - pushedDate: DateTime - - """ - The Repository this commit belongs to - """ - repository: Repository! - - """ - The HTTP path for this commit - """ - resourcePath: URI! - - """ - Commit signing information, if present. - """ - signature: GitSignature - - """ - Status information for this commit - """ - status: Status - - """ - Check and Status rollup information for this commit. - """ - statusCheckRollup: StatusCheckRollup - - """ - Returns a list of all submodules in this repository as of this Commit parsed from the .gitmodules file. - """ - submodules( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): SubmoduleConnection! - - """ - Returns a URL to download a tarball archive for a repository. - Note: For private repositories, these links are temporary and expire after five minutes. - """ - tarballUrl: URI! - - """ - Commit's root Tree - """ - tree: Tree! - - """ - The HTTP path for the tree of this commit - """ - treeResourcePath: URI! - - """ - The HTTP URL for the tree of this commit - """ - treeUrl: URI! - - """ - The HTTP URL for this commit - """ - url: URI! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState - - """ - Returns a URL to download a zipball archive for a repository. - Note: For private repositories, these links are temporary and expire after five minutes. - """ - zipballUrl: URI! -} - -""" -Specifies an author for filtering Git commits. -""" -input CommitAuthor { - """ - Email addresses to filter by. Commits authored by any of the specified email addresses will be returned. - """ - emails: [String!] - - """ - ID of a User to filter by. If non-null, only commits authored by this user - will be returned. This field takes precedence over emails. - """ - id: ID -} - -""" -Represents a comment on a given Commit. -""" -type CommitComment implements Comment & Deletable & Minimizable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the comment body. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the commit associated with the comment, if the commit exists. - """ - commit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies the file path associated with the comment. - """ - path: String - - """ - Identifies the line position associated with the comment. - """ - position: Int - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path permalink for this commit comment. - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL permalink for this commit comment. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for CommitComment. -""" -type CommitCommentConnection { - """ - A list of edges. - """ - edges: [CommitCommentEdge] - - """ - A list of nodes. - """ - nodes: [CommitComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CommitCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CommitComment -} - -""" -A thread of comments on a commit. -""" -type CommitCommentThread implements Node & RepositoryNode { - """ - The comments that exist in this thread. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The commit the comments were made on. - """ - commit: Commit - id: ID! - - """ - The file the comments were made on. - """ - path: String - - """ - The position in the diff for the commit that the comment was made on. - """ - position: Int - - """ - The repository associated with this node. - """ - repository: Repository! -} - -""" -The connection type for Commit. -""" -type CommitConnection { - """ - A list of edges. - """ - edges: [CommitEdge] - - """ - A list of nodes. - """ - nodes: [Commit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Ordering options for commit contribution connections. -""" -input CommitContributionOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field by which to order commit contributions. - """ - field: CommitContributionOrderField! -} - -""" -Properties by which commit contribution connections can be ordered. -""" -enum CommitContributionOrderField { - """ - Order commit contributions by how many commits they represent. - """ - COMMIT_COUNT - - """ - Order commit contributions by when they were made. - """ - OCCURRED_AT -} - -""" -This aggregates commits made by a user within one repository. -""" -type CommitContributionsByRepository { - """ - The commit contributions, each representing a day. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for commit contributions returned from the connection. - """ - orderBy: CommitContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedCommitContributionConnection! - - """ - The repository in which the commits were made. - """ - repository: Repository! - - """ - The HTTP path for the user's commits to the repository in this time range. - """ - resourcePath: URI! - - """ - The HTTP URL for the user's commits to the repository in this time range. - """ - url: URI! -} - -""" -An edge in a connection. -""" -type CommitEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Commit -} - -""" -The connection type for Commit. -""" -type CommitHistoryConnection { - """ - A list of edges. - """ - edges: [CommitEdge] - - """ - A list of nodes. - """ - nodes: [Commit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a 'connected' event on a given issue or pull request. -""" -type ConnectedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reference originated in a different repository. - """ - isCrossRepository: Boolean! - - """ - Issue or pull request that made the reference. - """ - source: ReferencedSubject! - - """ - Issue or pull request which was connected. - """ - subject: ReferencedSubject! -} - -""" -A content attachment -""" -type ContentAttachment { - """ - The body text of the content attachment. This parameter supports markdown. - """ - body: String! - - """ - The content reference that the content attachment is attached to. - """ - contentReference: ContentReference! - - """ - Identifies the primary key from the database. - """ - databaseId: Int! - id: ID! - - """ - The title of the content attachment. - """ - title: String! -} - -""" -A content reference -""" -type ContentReference { - """ - Identifies the primary key from the database. - """ - databaseId: Int! - id: ID! - - """ - The reference of the content reference. - """ - reference: String! -} - -""" -Represents a contribution a user made on GitHub, such as opening an issue. -""" -interface Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -A calendar of contributions made on GitHub by a user. -""" -type ContributionCalendar { - """ - A list of hex color codes used in this calendar. The darker the color, the more contributions it represents. - """ - colors: [String!]! - - """ - Determine if the color set was chosen because it's currently Halloween. - """ - isHalloween: Boolean! - - """ - A list of the months of contributions in this calendar. - """ - months: [ContributionCalendarMonth!]! - - """ - The count of total contributions in the calendar. - """ - totalContributions: Int! - - """ - A list of the weeks of contributions in this calendar. - """ - weeks: [ContributionCalendarWeek!]! -} - -""" -Represents a single day of contributions on GitHub by a user. -""" -type ContributionCalendarDay { - """ - The hex color code that represents how many contributions were made on this day compared to others in the calendar. - """ - color: String! - - """ - How many contributions were made by the user on this day. - """ - contributionCount: Int! - - """ - The day this square represents. - """ - date: Date! - - """ - A number representing which day of the week this square represents, e.g., 1 is Monday. - """ - weekday: Int! -} - -""" -A month of contributions in a user's contribution graph. -""" -type ContributionCalendarMonth { - """ - The date of the first day of this month. - """ - firstDay: Date! - - """ - The name of the month. - """ - name: String! - - """ - How many weeks started in this month. - """ - totalWeeks: Int! - - """ - The year the month occurred in. - """ - year: Int! -} - -""" -A week of contributions in a user's contribution graph. -""" -type ContributionCalendarWeek { - """ - The days of contributions in this week. - """ - contributionDays: [ContributionCalendarDay!]! - - """ - The date of the earliest square in this week. - """ - firstDay: Date! -} - -""" -Ordering options for contribution connections. -""" -input ContributionOrder { - """ - The ordering direction. - """ - direction: OrderDirection! -} - -""" -A contributions collection aggregates contributions such as opened issues and commits created by a user. -""" -type ContributionsCollection { - """ - Commit contributions made by the user, grouped by repository. - """ - commitContributionsByRepository( - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [CommitContributionsByRepository!]! - - """ - A calendar of this user's contributions on GitHub. - """ - contributionCalendar: ContributionCalendar! - - """ - The years the user has been making contributions with the most recent year first. - """ - contributionYears: [Int!]! - - """ - Determine if this collection's time span ends in the current month. - """ - doesEndInCurrentMonth: Boolean! - - """ - The date of the first restricted contribution the user made in this time - period. Can only be non-null when the user has enabled private contribution counts. - """ - earliestRestrictedContributionDate: Date - - """ - The ending date and time of this collection. - """ - endedAt: DateTime! - - """ - The first issue the user opened on GitHub. This will be null if that issue was - opened outside the collection's time range and ignoreTimeRange is false. If - the issue is not visible but the user has opted to show private contributions, - a RestrictedContribution will be returned. - """ - firstIssueContribution: CreatedIssueOrRestrictedContribution - - """ - The first pull request the user opened on GitHub. This will be null if that - pull request was opened outside the collection's time range and - ignoreTimeRange is not true. If the pull request is not visible but the user - has opted to show private contributions, a RestrictedContribution will be returned. - """ - firstPullRequestContribution: CreatedPullRequestOrRestrictedContribution - - """ - The first repository the user created on GitHub. This will be null if that - first repository was created outside the collection's time range and - ignoreTimeRange is false. If the repository is not visible, then a - RestrictedContribution is returned. - """ - firstRepositoryContribution: CreatedRepositoryOrRestrictedContribution - - """ - Does the user have any more activity in the timeline that occurred prior to the collection's time range? - """ - hasActivityInThePast: Boolean! - - """ - Determine if there are any contributions in this collection. - """ - hasAnyContributions: Boolean! - - """ - Determine if the user made any contributions in this time frame whose details - are not visible because they were made in a private repository. Can only be - true if the user enabled private contribution counts. - """ - hasAnyRestrictedContributions: Boolean! - - """ - Whether or not the collector's time span is all within the same day. - """ - isSingleDay: Boolean! - - """ - A list of issues the user opened. - """ - issueContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Should the user's first issue ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from the result. - """ - excludePopular: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedIssueContributionConnection! - - """ - Issue contributions made by the user, grouped by repository. - """ - issueContributionsByRepository( - """ - Should the user's first issue ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from the result. - """ - excludePopular: Boolean = false - - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [IssueContributionsByRepository!]! - - """ - When the user signed up for GitHub. This will be null if that sign up date - falls outside the collection's time range and ignoreTimeRange is false. - """ - joinedGitHubContribution: JoinedGitHubContribution - - """ - The date of the most recent restricted contribution the user made in this time - period. Can only be non-null when the user has enabled private contribution counts. - """ - latestRestrictedContributionDate: Date - - """ - When this collection's time range does not include any activity from the user, use this - to get a different collection from an earlier time range that does have activity. - """ - mostRecentCollectionWithActivity: ContributionsCollection - - """ - Returns a different contributions collection from an earlier time range than this one - that does not have any contributions. - """ - mostRecentCollectionWithoutActivity: ContributionsCollection - - """ - The issue the user opened on GitHub that received the most comments in the specified - time frame. - """ - popularIssueContribution: CreatedIssueContribution - - """ - The pull request the user opened on GitHub that received the most comments in the - specified time frame. - """ - popularPullRequestContribution: CreatedPullRequestContribution - - """ - Pull request contributions made by the user. - """ - pullRequestContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Should the user's first pull request ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from the result. - """ - excludePopular: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedPullRequestContributionConnection! - - """ - Pull request contributions made by the user, grouped by repository. - """ - pullRequestContributionsByRepository( - """ - Should the user's first pull request ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from the result. - """ - excludePopular: Boolean = false - - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [PullRequestContributionsByRepository!]! - - """ - Pull request review contributions made by the user. - """ - pullRequestReviewContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedPullRequestReviewContributionConnection! - - """ - Pull request review contributions made by the user, grouped by repository. - """ - pullRequestReviewContributionsByRepository( - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [PullRequestReviewContributionsByRepository!]! - - """ - A list of repositories owned by the user that the user created in this time range. - """ - repositoryContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Should the user's first repository ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedRepositoryContributionConnection! - - """ - A count of contributions made by the user that the viewer cannot access. Only - non-zero when the user has chosen to share their private contribution counts. - """ - restrictedContributionsCount: Int! - - """ - The beginning date and time of this collection. - """ - startedAt: DateTime! - - """ - How many commits were made by the user in this time span. - """ - totalCommitContributions: Int! - - """ - How many issues the user opened. - """ - totalIssueContributions( - """ - Should the user's first issue ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many pull requests the user opened. - """ - totalPullRequestContributions( - """ - Should the user's first pull request ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many pull request reviews the user left. - """ - totalPullRequestReviewContributions: Int! - - """ - How many different repositories the user committed to. - """ - totalRepositoriesWithContributedCommits: Int! - - """ - How many different repositories the user opened issues in. - """ - totalRepositoriesWithContributedIssues( - """ - Should the user's first issue ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many different repositories the user left pull request reviews in. - """ - totalRepositoriesWithContributedPullRequestReviews: Int! - - """ - How many different repositories the user opened pull requests in. - """ - totalRepositoriesWithContributedPullRequests( - """ - Should the user's first pull request ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many repositories the user created. - """ - totalRepositoryContributions( - """ - Should the user's first repository ever be excluded from this count. - """ - excludeFirst: Boolean = false - ): Int! - - """ - The user who made the contributions in this collection. - """ - user: User! -} - -""" -Autogenerated input type of ConvertProjectCardNoteToIssue -""" -input ConvertProjectCardNoteToIssueInput { - """ - The body of the newly created issue. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ProjectCard ID to convert. - """ - projectCardId: ID! @possibleTypes(concreteTypes: ["ProjectCard"]) - - """ - The ID of the repository to create the issue in. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - The title of the newly created issue. Defaults to the card's note text. - """ - title: String -} - -""" -Autogenerated return type of ConvertProjectCardNoteToIssue -""" -type ConvertProjectCardNoteToIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated ProjectCard. - """ - projectCard: ProjectCard -} - -""" -Represents a 'convert_to_draft' event on a given pull request. -""" -type ConvertToDraftEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this convert to draft event. - """ - resourcePath: URI! - - """ - The HTTP URL for this convert to draft event. - """ - url: URI! -} - -""" -Represents a 'converted_note_to_issue' event on a given issue or pull request. -""" -type ConvertedNoteToIssueEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Project referenced by event. - """ - project: Project @preview(toggledBy: "starfox-preview") - - """ - Project card referenced by this project event. - """ - projectCard: ProjectCard @preview(toggledBy: "starfox-preview") - - """ - Column name referenced by this project event. - """ - projectColumnName: String! @preview(toggledBy: "starfox-preview") -} - -""" -Autogenerated input type of CreateBranchProtectionRule -""" -input CreateBranchProtectionRuleInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Will new commits pushed to matching branches dismiss pull request review approvals. - """ - dismissesStaleReviews: Boolean - - """ - Can admins overwrite branch protection. - """ - isAdminEnforced: Boolean - - """ - The glob-like pattern used to determine matching branches. - """ - pattern: String! - - """ - A list of User, Team or App IDs allowed to push to matching branches. - """ - pushActorIds: [ID!] - - """ - The global relay id of the repository in which a new branch protection rule should be created in. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - Number of approving reviews required to update matching branches. - """ - requiredApprovingReviewCount: Int - - """ - List of required status check contexts that must pass for commits to be accepted to matching branches. - """ - requiredStatusCheckContexts: [String!] - - """ - Are approving reviews required to update matching branches. - """ - requiresApprovingReviews: Boolean - - """ - Are reviews from code owners required to update matching branches. - """ - requiresCodeOwnerReviews: Boolean - - """ - Are commits required to be signed. - """ - requiresCommitSignatures: Boolean - - """ - Are status checks required to update matching branches. - """ - requiresStatusChecks: Boolean - - """ - Are branches required to be up to date before merging. - """ - requiresStrictStatusChecks: Boolean - - """ - Is pushing to matching branches restricted. - """ - restrictsPushes: Boolean - - """ - Is dismissal of pull request reviews restricted. - """ - restrictsReviewDismissals: Boolean - - """ - A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. - """ - reviewDismissalActorIds: [ID!] -} - -""" -Autogenerated return type of CreateBranchProtectionRule -""" -type CreateBranchProtectionRulePayload { - """ - The newly created BranchProtectionRule. - """ - branchProtectionRule: BranchProtectionRule - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of CreateCheckRun -""" -input CreateCheckRunInput @preview(toggledBy: "antiope-preview") { - """ - Possible further actions the integrator can perform, which a user may trigger. - """ - actions: [CheckRunAction!] - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The time that the check run finished. - """ - completedAt: DateTime - - """ - The final conclusion of the check. - """ - conclusion: CheckConclusionState - - """ - The URL of the integrator's site that has the full details of the check. - """ - detailsUrl: URI - - """ - A reference for the run on the integrator's system. - """ - externalId: String - - """ - The SHA of the head commit. - """ - headSha: GitObjectID! - - """ - The name of the check. - """ - name: String! - - """ - Descriptive details about the run. - """ - output: CheckRunOutput - - """ - The node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - The time that the check run began. - """ - startedAt: DateTime - - """ - The current status. - """ - status: RequestableCheckStatusState -} - -""" -Autogenerated return type of CreateCheckRun -""" -type CreateCheckRunPayload @preview(toggledBy: "antiope-preview") { - """ - The newly created check run. - """ - checkRun: CheckRun - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of CreateCheckSuite -""" -input CreateCheckSuiteInput @preview(toggledBy: "antiope-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The SHA of the head commit. - """ - headSha: GitObjectID! - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of CreateCheckSuite -""" -type CreateCheckSuitePayload @preview(toggledBy: "antiope-preview") { - """ - The newly created check suite. - """ - checkSuite: CheckSuite - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of CreateContentAttachment -""" -input CreateContentAttachmentInput { - """ - The body of the content attachment, which may contain markdown. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The node ID of the content_reference. - """ - contentReferenceId: ID! @possibleTypes(concreteTypes: ["ContentReference"]) - - """ - The title of the content attachment. - """ - title: String! -} - -""" -Autogenerated return type of CreateContentAttachment -""" -type CreateContentAttachmentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created content attachment. - """ - contentAttachment: ContentAttachment -} - -""" -Autogenerated input type of CreateDeployment -""" -input CreateDeploymentInput @preview(toggledBy: "flash-preview") { - """ - Attempt to automatically merge the default branch into the requested ref, defaults to true. - """ - autoMerge: Boolean = true - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Short description of the deployment. - """ - description: String = "" - - """ - Name for the target deployment environment. - """ - environment: String = "production" - - """ - JSON payload with extra information about the deployment. - """ - payload: String = "{}" - - """ - The node ID of the ref to be deployed. - """ - refId: ID! @possibleTypes(concreteTypes: ["Ref"]) - - """ - The node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - The status contexts to verify against commit status checks. To bypass required - contexts, pass an empty array. Defaults to all unique contexts. - """ - requiredContexts: [String!] - - """ - Specifies a task to execute. - """ - task: String = "deploy" -} - -""" -Autogenerated return type of CreateDeployment -""" -type CreateDeploymentPayload @preview(toggledBy: "flash-preview") { - """ - True if the default branch has been auto-merged into the deployment ref. - """ - autoMerged: Boolean - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new deployment. - """ - deployment: Deployment -} - -""" -Autogenerated input type of CreateDeploymentStatus -""" -input CreateDeploymentStatusInput @preview(toggledBy: "flash-preview") { - """ - Adds a new inactive status to all non-transient, non-production environment - deployments with the same repository and environment name as the created - status's deployment. - """ - autoInactive: Boolean = true - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The node ID of the deployment. - """ - deploymentId: ID! @possibleTypes(concreteTypes: ["Deployment"]) - - """ - A short description of the status. Maximum length of 140 characters. - """ - description: String = "" - - """ - If provided, updates the environment of the deploy. Otherwise, does not modify the environment. - """ - environment: String - - """ - Sets the URL for accessing your environment. - """ - environmentUrl: String = "" - - """ - The log URL to associate with this status. This URL should contain - output to keep the user updated while the task is running or serve as - historical information for what happened in the deployment. - """ - logUrl: String = "" - - """ - The state of the deployment. - """ - state: DeploymentStatusState! -} - -""" -Autogenerated return type of CreateDeploymentStatus -""" -type CreateDeploymentStatusPayload @preview(toggledBy: "flash-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new deployment status. - """ - deploymentStatus: DeploymentStatus -} - -""" -Autogenerated input type of CreateEnterpriseOrganization -""" -input CreateEnterpriseOrganizationInput { - """ - The logins for the administrators of the new organization. - """ - adminLogins: [String!]! - - """ - The email used for sending billing receipts. - """ - billingEmail: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise owning the new organization. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The login of the new organization. - """ - login: String! - - """ - The profile name of the new organization. - """ - profileName: String! -} - -""" -Autogenerated return type of CreateEnterpriseOrganization -""" -type CreateEnterpriseOrganizationPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise that owns the created organization. - """ - enterprise: Enterprise - - """ - The organization that was created. - """ - organization: Organization -} - -""" -Autogenerated input type of CreateIpAllowListEntry -""" -input CreateIpAllowListEntryInput { - """ - An IP address or range of addresses in CIDR notation. - """ - allowListValue: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Whether the IP allow list entry is active when an IP allow list is enabled. - """ - isActive: Boolean! - - """ - An optional name for the IP allow list entry. - """ - name: String - - """ - The ID of the owner for which to create the new IP allow list entry. - """ - ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner") -} - -""" -Autogenerated return type of CreateIpAllowListEntry -""" -type CreateIpAllowListEntryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The IP allow list entry that was created. - """ - ipAllowListEntry: IpAllowListEntry -} - -""" -Autogenerated input type of CreateIssue -""" -input CreateIssueInput { - """ - The Node ID for the user assignee for this issue. - """ - assigneeIds: [ID!] @possibleTypes(concreteTypes: ["User"]) - - """ - The body for the issue description. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - An array of Node IDs of labels for this issue. - """ - labelIds: [ID!] @possibleTypes(concreteTypes: ["Label"]) - - """ - The Node ID of the milestone for this issue. - """ - milestoneId: ID @possibleTypes(concreteTypes: ["Milestone"]) - - """ - An array of Node IDs for projects associated with this issue. - """ - projectIds: [ID!] @possibleTypes(concreteTypes: ["Project"]) - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - The title for the issue. - """ - title: String! -} - -""" -Autogenerated return type of CreateIssue -""" -type CreateIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new issue. - """ - issue: Issue -} - -""" -Autogenerated input type of CreateLabel -""" -input CreateLabelInput @preview(toggledBy: "bane-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A 6 character hex code, without the leading #, identifying the color of the label. - """ - color: String! - - """ - A brief description of the label, such as its purpose. - """ - description: String - - """ - The name of the label. - """ - name: String! - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of CreateLabel -""" -type CreateLabelPayload @preview(toggledBy: "bane-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new label. - """ - label: Label -} - -""" -Autogenerated input type of CreateProject -""" -input CreateProjectInput { - """ - The description of project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of project. - """ - name: String! - - """ - The owner ID to create the project under. - """ - ownerId: ID! @possibleTypes(concreteTypes: ["Organization", "Repository", "User"], abstractType: "ProjectOwner") - - """ - A list of repository IDs to create as linked repositories for the project - """ - repositoryIds: [ID!] @possibleTypes(concreteTypes: ["Repository"]) - - """ - The name of the GitHub-provided template. - """ - template: ProjectTemplate -} - -""" -Autogenerated return type of CreateProject -""" -type CreateProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new project. - """ - project: Project -} - -""" -Autogenerated input type of CreatePullRequest -""" -input CreatePullRequestInput { - """ - The name of the branch you want your changes pulled into. This should be an existing branch - on the current repository. You cannot update the base branch on a pull request to point - to another repository. - """ - baseRefName: String! - - """ - The contents of the pull request. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Indicates whether this pull request should be a draft. - """ - draft: Boolean = false - - """ - The name of the branch where your changes are implemented. For cross-repository pull requests - in the same network, namespace `head_ref_name` with a user like this: `username:branch`. - """ - headRefName: String! - - """ - Indicates whether maintainers can modify the pull request. - """ - maintainerCanModify: Boolean = true - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - The title of the pull request. - """ - title: String! -} - -""" -Autogenerated return type of CreatePullRequest -""" -type CreatePullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new pull request. - """ - pullRequest: PullRequest -} - -""" -Autogenerated input type of CreateRef -""" -input CreateRefInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The fully qualified name of the new Ref (ie: `refs/heads/my_new_branch`). - """ - name: String! - - """ - The GitObjectID that the new Ref shall target. Must point to a commit. - """ - oid: GitObjectID! - - """ - The Node ID of the Repository to create the Ref in. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of CreateRef -""" -type CreateRefPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created ref. - """ - ref: Ref -} - -""" -Autogenerated input type of CreateRepository -""" -input CreateRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A short description of the new repository. - """ - description: String - - """ - Indicates if the repository should have the issues feature enabled. - """ - hasIssuesEnabled: Boolean = true - - """ - Indicates if the repository should have the wiki feature enabled. - """ - hasWikiEnabled: Boolean = false - - """ - The URL for a web page about this repository. - """ - homepageUrl: URI - - """ - The name of the new repository. - """ - name: String! - - """ - The ID of the owner for the new repository. - """ - ownerId: ID @possibleTypes(concreteTypes: ["Organization", "User"], abstractType: "RepositoryOwner") - - """ - When an organization is specified as the owner, this ID identifies the team - that should be granted access to the new repository. - """ - teamId: ID @possibleTypes(concreteTypes: ["Team"]) - - """ - Whether this repository should be marked as a template such that anyone who - can access it can create new repositories with the same files and directory structure. - """ - template: Boolean = false - - """ - Indicates the repository's visibility level. - """ - visibility: RepositoryVisibility! -} - -""" -Autogenerated return type of CreateRepository -""" -type CreateRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new repository. - """ - repository: Repository -} - -""" -Autogenerated input type of CreateTeamDiscussionComment -""" -input CreateTeamDiscussionCommentInput { - """ - The content of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the discussion to which the comment belongs. - """ - discussionId: ID! @possibleTypes(concreteTypes: ["TeamDiscussion"]) -} - -""" -Autogenerated return type of CreateTeamDiscussionComment -""" -type CreateTeamDiscussionCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new comment. - """ - teamDiscussionComment: TeamDiscussionComment -} - -""" -Autogenerated input type of CreateTeamDiscussion -""" -input CreateTeamDiscussionInput { - """ - The content of the discussion. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - If true, restricts the visiblity of this discussion to team members and - organization admins. If false or not specified, allows any organization member - to view this discussion. - """ - private: Boolean - - """ - The ID of the team to which the discussion belongs. - """ - teamId: ID! @possibleTypes(concreteTypes: ["Team"]) - - """ - The title of the discussion. - """ - title: String! -} - -""" -Autogenerated return type of CreateTeamDiscussion -""" -type CreateTeamDiscussionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new discussion. - """ - teamDiscussion: TeamDiscussion -} - -""" -Represents the contribution a user made by committing to a repository. -""" -type CreatedCommitContribution implements Contribution { - """ - How many commits were made on this day to this repository by the user. - """ - commitCount: Int! - - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The repository the user made a commit in. - """ - repository: Repository! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedCommitContribution. -""" -type CreatedCommitContributionConnection { - """ - A list of edges. - """ - edges: [CreatedCommitContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedCommitContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of commits across days and repositories in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedCommitContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedCommitContribution -} - -""" -Represents the contribution a user made on GitHub by opening an issue. -""" -type CreatedIssueContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - The issue that was opened. - """ - issue: Issue! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedIssueContribution. -""" -type CreatedIssueContributionConnection { - """ - A list of edges. - """ - edges: [CreatedIssueContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedIssueContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedIssueContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedIssueContribution -} - -""" -Represents either a issue the viewer can access or a restricted contribution. -""" -union CreatedIssueOrRestrictedContribution = CreatedIssueContribution | RestrictedContribution - -""" -Represents the contribution a user made on GitHub by opening a pull request. -""" -type CreatedPullRequestContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The pull request that was opened. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedPullRequestContribution. -""" -type CreatedPullRequestContributionConnection { - """ - A list of edges. - """ - edges: [CreatedPullRequestContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedPullRequestContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedPullRequestContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedPullRequestContribution -} - -""" -Represents either a pull request the viewer can access or a restricted contribution. -""" -union CreatedPullRequestOrRestrictedContribution = CreatedPullRequestContribution | RestrictedContribution - -""" -Represents the contribution a user made by leaving a review on a pull request. -""" -type CreatedPullRequestReviewContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The pull request the user reviewed. - """ - pullRequest: PullRequest! - - """ - The review the user left on the pull request. - """ - pullRequestReview: PullRequestReview! - - """ - The repository containing the pull request that the user reviewed. - """ - repository: Repository! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedPullRequestReviewContribution. -""" -type CreatedPullRequestReviewContributionConnection { - """ - A list of edges. - """ - edges: [CreatedPullRequestReviewContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedPullRequestReviewContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedPullRequestReviewContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedPullRequestReviewContribution -} - -""" -Represents the contribution a user made on GitHub by creating a repository. -""" -type CreatedRepositoryContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The repository that was created. - """ - repository: Repository! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedRepositoryContribution. -""" -type CreatedRepositoryContributionConnection { - """ - A list of edges. - """ - edges: [CreatedRepositoryContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedRepositoryContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedRepositoryContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedRepositoryContribution -} - -""" -Represents either a repository the viewer can access or a restricted contribution. -""" -union CreatedRepositoryOrRestrictedContribution = CreatedRepositoryContribution | RestrictedContribution - -""" -Represents a mention made by one issue or pull request to another. -""" -type CrossReferencedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reference originated in a different repository. - """ - isCrossRepository: Boolean! - - """ - Identifies when the reference was made. - """ - referencedAt: DateTime! - - """ - The HTTP path for this pull request. - """ - resourcePath: URI! - - """ - Issue or pull request that made the reference. - """ - source: ReferencedSubject! - - """ - Issue or pull request to which the reference was made. - """ - target: ReferencedSubject! - - """ - The HTTP URL for this pull request. - """ - url: URI! - - """ - Checks if the target will be closed when the source is merged. - """ - willCloseTarget: Boolean! -} - -""" -An ISO-8601 encoded date string. -""" -scalar Date - -""" -An ISO-8601 encoded UTC date string. -""" -scalar DateTime - -""" -Autogenerated input type of DeclineTopicSuggestion -""" -input DeclineTopicSuggestionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the suggested topic. - """ - name: String! - - """ - The reason why the suggested topic is declined. - """ - reason: TopicSuggestionDeclineReason! - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of DeclineTopicSuggestion -""" -type DeclineTopicSuggestionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The declined topic. - """ - topic: Topic -} - -""" -The possible default permissions for repositories. -""" -enum DefaultRepositoryPermissionField { - """ - Can read, write, and administrate repos by default - """ - ADMIN - - """ - No access - """ - NONE - - """ - Can read repos by default - """ - READ - - """ - Can read and write repos by default - """ - WRITE -} - -""" -Entities that can be deleted. -""" -interface Deletable { - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! -} - -""" -Autogenerated input type of DeleteBranchProtectionRule -""" -input DeleteBranchProtectionRuleInput { - """ - The global relay id of the branch protection rule to be deleted. - """ - branchProtectionRuleId: ID! @possibleTypes(concreteTypes: ["BranchProtectionRule"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of DeleteBranchProtectionRule -""" -type DeleteBranchProtectionRulePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteDeployment -""" -input DeleteDeploymentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the deployment to be deleted. - """ - id: ID! @possibleTypes(concreteTypes: ["Deployment"]) -} - -""" -Autogenerated return type of DeleteDeployment -""" -type DeleteDeploymentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteIpAllowListEntry -""" -input DeleteIpAllowListEntryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the IP allow list entry to delete. - """ - ipAllowListEntryId: ID! @possibleTypes(concreteTypes: ["IpAllowListEntry"]) -} - -""" -Autogenerated return type of DeleteIpAllowListEntry -""" -type DeleteIpAllowListEntryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The IP allow list entry that was deleted. - """ - ipAllowListEntry: IpAllowListEntry -} - -""" -Autogenerated input type of DeleteIssueComment -""" -input DeleteIssueCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the comment to delete. - """ - id: ID! @possibleTypes(concreteTypes: ["IssueComment"]) -} - -""" -Autogenerated return type of DeleteIssueComment -""" -type DeleteIssueCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteIssue -""" -input DeleteIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the issue to delete. - """ - issueId: ID! @possibleTypes(concreteTypes: ["Issue"]) -} - -""" -Autogenerated return type of DeleteIssue -""" -type DeleteIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The repository the issue belonged to - """ - repository: Repository -} - -""" -Autogenerated input type of DeleteLabel -""" -input DeleteLabelInput @preview(toggledBy: "bane-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the label to be deleted. - """ - id: ID! @possibleTypes(concreteTypes: ["Label"]) -} - -""" -Autogenerated return type of DeleteLabel -""" -type DeleteLabelPayload @preview(toggledBy: "bane-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeletePackageVersion -""" -input DeletePackageVersionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the package version to be deleted. - """ - packageVersionId: ID! @possibleTypes(concreteTypes: ["PackageVersion"]) -} - -""" -Autogenerated return type of DeletePackageVersion -""" -type DeletePackageVersionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Whether or not the operation succeeded. - """ - success: Boolean -} - -""" -Autogenerated input type of DeleteProjectCard -""" -input DeleteProjectCardInput { - """ - The id of the card to delete. - """ - cardId: ID! @possibleTypes(concreteTypes: ["ProjectCard"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of DeleteProjectCard -""" -type DeleteProjectCardPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The column the deleted card was in. - """ - column: ProjectColumn - - """ - The deleted card ID. - """ - deletedCardId: ID -} - -""" -Autogenerated input type of DeleteProjectColumn -""" -input DeleteProjectColumnInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the column to delete. - """ - columnId: ID! @possibleTypes(concreteTypes: ["ProjectColumn"]) -} - -""" -Autogenerated return type of DeleteProjectColumn -""" -type DeleteProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The deleted column ID. - """ - deletedColumnId: ID - - """ - The project the deleted column was in. - """ - project: Project -} - -""" -Autogenerated input type of DeleteProject -""" -input DeleteProjectInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Project ID to update. - """ - projectId: ID! @possibleTypes(concreteTypes: ["Project"]) -} - -""" -Autogenerated return type of DeleteProject -""" -type DeleteProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The repository or organization the project was removed from. - """ - owner: ProjectOwner -} - -""" -Autogenerated input type of DeletePullRequestReviewComment -""" -input DeletePullRequestReviewCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the comment to delete. - """ - id: ID! @possibleTypes(concreteTypes: ["PullRequestReviewComment"]) -} - -""" -Autogenerated return type of DeletePullRequestReviewComment -""" -type DeletePullRequestReviewCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request review the deleted comment belonged to. - """ - pullRequestReview: PullRequestReview -} - -""" -Autogenerated input type of DeletePullRequestReview -""" -input DeletePullRequestReviewInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pull request review to delete. - """ - pullRequestReviewId: ID! @possibleTypes(concreteTypes: ["PullRequestReview"]) -} - -""" -Autogenerated return type of DeletePullRequestReview -""" -type DeletePullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The deleted pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Autogenerated input type of DeleteRef -""" -input DeleteRefInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the Ref to be deleted. - """ - refId: ID! @possibleTypes(concreteTypes: ["Ref"]) -} - -""" -Autogenerated return type of DeleteRef -""" -type DeleteRefPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteTeamDiscussionComment -""" -input DeleteTeamDiscussionCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the comment to delete. - """ - id: ID! @possibleTypes(concreteTypes: ["TeamDiscussionComment"]) -} - -""" -Autogenerated return type of DeleteTeamDiscussionComment -""" -type DeleteTeamDiscussionCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteTeamDiscussion -""" -input DeleteTeamDiscussionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The discussion ID to delete. - """ - id: ID! @possibleTypes(concreteTypes: ["TeamDiscussion"]) -} - -""" -Autogenerated return type of DeleteTeamDiscussion -""" -type DeleteTeamDiscussionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Represents a 'demilestoned' event on a given issue or pull request. -""" -type DemilestonedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the milestone title associated with the 'demilestoned' event. - """ - milestoneTitle: String! - - """ - Object referenced by event. - """ - subject: MilestoneItem! -} - -""" -A dependency manifest entry -""" -type DependencyGraphDependency @preview(toggledBy: "hawkgirl-preview") { - """ - Does the dependency itself have dependencies? - """ - hasDependencies: Boolean! - - """ - The dependency package manager - """ - packageManager: String - - """ - The required package name - """ - packageName: String! - - """ - The repository containing the package - """ - repository: Repository - - """ - The dependency version requirements - """ - requirements: String! -} - -""" -The connection type for DependencyGraphDependency. -""" -type DependencyGraphDependencyConnection @preview(toggledBy: "hawkgirl-preview") { - """ - A list of edges. - """ - edges: [DependencyGraphDependencyEdge] - - """ - A list of nodes. - """ - nodes: [DependencyGraphDependency] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DependencyGraphDependencyEdge @preview(toggledBy: "hawkgirl-preview") { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: DependencyGraphDependency -} - -""" -Dependency manifest for a repository -""" -type DependencyGraphManifest implements Node @preview(toggledBy: "hawkgirl-preview") { - """ - Path to view the manifest file blob - """ - blobPath: String! - - """ - A list of manifest dependencies - """ - dependencies( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): DependencyGraphDependencyConnection - - """ - The number of dependencies listed in the manifest - """ - dependenciesCount: Int - - """ - Is the manifest too big to parse? - """ - exceedsMaxSize: Boolean! - - """ - Fully qualified manifest filename - """ - filename: String! - id: ID! - - """ - Were we able to parse the manifest? - """ - parseable: Boolean! - - """ - The repository containing the manifest - """ - repository: Repository! -} - -""" -The connection type for DependencyGraphManifest. -""" -type DependencyGraphManifestConnection @preview(toggledBy: "hawkgirl-preview") { - """ - A list of edges. - """ - edges: [DependencyGraphManifestEdge] - - """ - A list of nodes. - """ - nodes: [DependencyGraphManifest] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DependencyGraphManifestEdge @preview(toggledBy: "hawkgirl-preview") { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: DependencyGraphManifest -} - -""" -A repository deploy key. -""" -type DeployKey implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The deploy key. - """ - key: String! - - """ - Whether or not the deploy key is read only. - """ - readOnly: Boolean! - - """ - The deploy key title. - """ - title: String! - - """ - Whether or not the deploy key has been verified. - """ - verified: Boolean! -} - -""" -The connection type for DeployKey. -""" -type DeployKeyConnection { - """ - A list of edges. - """ - edges: [DeployKeyEdge] - - """ - A list of nodes. - """ - nodes: [DeployKey] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DeployKeyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: DeployKey -} - -""" -Represents a 'deployed' event on a given pull request. -""" -type DeployedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The deployment associated with the 'deployed' event. - """ - deployment: Deployment! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The ref associated with the 'deployed' event. - """ - ref: Ref -} - -""" -Represents triggered deployment instance. -""" -type Deployment implements Node { - """ - Identifies the commit sha of the deployment. - """ - commit: Commit - - """ - Identifies the oid of the deployment commit, even if the commit has been deleted. - """ - commitOid: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the actor who triggered the deployment. - """ - creator: Actor! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The deployment description. - """ - description: String - - """ - The latest environment to which this deployment was made. - """ - environment: String - id: ID! - - """ - The latest environment to which this deployment was made. - """ - latestEnvironment: String - - """ - The latest status of this deployment. - """ - latestStatus: DeploymentStatus - - """ - The original environment to which this deployment was made. - """ - originalEnvironment: String - - """ - Extra information that a deployment system might need. - """ - payload: String - - """ - Identifies the Ref of the deployment, if the deployment was created by ref. - """ - ref: Ref - - """ - Identifies the repository associated with the deployment. - """ - repository: Repository! - - """ - The current state of the deployment. - """ - state: DeploymentState - - """ - A list of statuses associated with the deployment. - """ - statuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): DeploymentStatusConnection - - """ - The deployment task. - """ - task: String - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for Deployment. -""" -type DeploymentConnection { - """ - A list of edges. - """ - edges: [DeploymentEdge] - - """ - A list of nodes. - """ - nodes: [Deployment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DeploymentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Deployment -} - -""" -Represents a 'deployment_environment_changed' event on a given pull request. -""" -type DeploymentEnvironmentChangedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The deployment status that updated the deployment environment. - """ - deploymentStatus: DeploymentStatus! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Ordering options for deployment connections -""" -input DeploymentOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order deployments by. - """ - field: DeploymentOrderField! -} - -""" -Properties by which deployment connections can be ordered. -""" -enum DeploymentOrderField { - """ - Order collection by creation time - """ - CREATED_AT -} - -""" -The possible states in which a deployment can be. -""" -enum DeploymentState { - """ - The pending deployment was not updated after 30 minutes. - """ - ABANDONED - - """ - The deployment is currently active. - """ - ACTIVE - - """ - An inactive transient deployment. - """ - DESTROYED - - """ - The deployment experienced an error. - """ - ERROR - - """ - The deployment has failed. - """ - FAILURE - - """ - The deployment is inactive. - """ - INACTIVE - - """ - The deployment is in progress. - """ - IN_PROGRESS - - """ - The deployment is pending. - """ - PENDING - - """ - The deployment has queued - """ - QUEUED -} - -""" -Describes the status of a given deployment attempt. -""" -type DeploymentStatus implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the actor who triggered the deployment. - """ - creator: Actor! - - """ - Identifies the deployment associated with status. - """ - deployment: Deployment! - - """ - Identifies the description of the deployment. - """ - description: String - - """ - Identifies the environment of the deployment at the time of this deployment status - """ - environment: String @preview(toggledBy: "flash-preview") - - """ - Identifies the environment URL of the deployment. - """ - environmentUrl: URI - id: ID! - - """ - Identifies the log URL of the deployment. - """ - logUrl: URI - - """ - Identifies the current state of the deployment. - """ - state: DeploymentStatusState! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for DeploymentStatus. -""" -type DeploymentStatusConnection { - """ - A list of edges. - """ - edges: [DeploymentStatusEdge] - - """ - A list of nodes. - """ - nodes: [DeploymentStatus] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DeploymentStatusEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: DeploymentStatus -} - -""" -The possible states for a deployment status. -""" -enum DeploymentStatusState { - """ - The deployment experienced an error. - """ - ERROR - - """ - The deployment has failed. - """ - FAILURE - - """ - The deployment is inactive. - """ - INACTIVE - - """ - The deployment is in progress. - """ - IN_PROGRESS - - """ - The deployment is pending. - """ - PENDING - - """ - The deployment is queued - """ - QUEUED - - """ - The deployment was successful. - """ - SUCCESS -} - -""" -The possible sides of a diff. -""" -enum DiffSide { - """ - The left side of the diff. - """ - LEFT - - """ - The right side of the diff. - """ - RIGHT -} - -""" -Represents a 'disconnected' event on a given issue or pull request. -""" -type DisconnectedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reference originated in a different repository. - """ - isCrossRepository: Boolean! - - """ - Issue or pull request from which the issue was disconnected. - """ - source: ReferencedSubject! - - """ - Issue or pull request which was disconnected. - """ - subject: ReferencedSubject! -} - -""" -Autogenerated input type of DismissPullRequestReview -""" -input DismissPullRequestReviewInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The contents of the pull request review dismissal message. - """ - message: String! - - """ - The Node ID of the pull request review to modify. - """ - pullRequestReviewId: ID! @possibleTypes(concreteTypes: ["PullRequestReview"]) -} - -""" -Autogenerated return type of DismissPullRequestReview -""" -type DismissPullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The dismissed pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Specifies a review comment to be left with a Pull Request Review. -""" -input DraftPullRequestReviewComment { - """ - Body of the comment to leave. - """ - body: String! - - """ - Path to the file being commented on. - """ - path: String! - - """ - Position in the file to leave a comment on. - """ - position: Int! -} - -""" -Specifies a review comment thread to be left with a Pull Request Review. -""" -input DraftPullRequestReviewThread { - """ - Body of the comment to leave. - """ - body: String! - - """ - The line of the blob to which the thread refers. The end of the line range for multi-line comments. - """ - line: Int! - - """ - Path to the file being commented on. - """ - path: String! - - """ - The side of the diff on which the line resides. For multi-line comments, this is the side for the end of the line range. - """ - side: DiffSide = RIGHT - - """ - The first line of the range to which the comment refers. - """ - startLine: Int - - """ - The side of the diff on which the start line resides. - """ - startSide: DiffSide = RIGHT -} - -""" -An account to manage multiple organizations with consolidated policy and billing. -""" -type Enterprise implements Node { - """ - A URL pointing to the enterprise's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Enterprise billing information visible to enterprise billing managers. - """ - billingInfo: EnterpriseBillingInfo - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The description of the enterprise. - """ - description: String - - """ - The description of the enterprise as HTML. - """ - descriptionHTML: HTML! - id: ID! - - """ - The location of the enterprise. - """ - location: String - - """ - A list of users who are members of this enterprise. - """ - members( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Only return members within the selected GitHub Enterprise deployment - """ - deployment: EnterpriseUserDeployment - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for members returned from the connection. - """ - orderBy: EnterpriseMemberOrder = {field: LOGIN, direction: ASC} - - """ - Only return members within the organizations with these logins - """ - organizationLogins: [String!] - - """ - The search string to look for. - """ - query: String - - """ - The role of the user in the enterprise organization or server. - """ - role: EnterpriseUserAccountMembershipRole - ): EnterpriseMemberConnection! - - """ - The name of the enterprise. - """ - name: String! - - """ - A list of organizations that belong to this enterprise. - """ - organizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations returned from the connection. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The search string to look for. - """ - query: String - ): OrganizationConnection! - - """ - Enterprise information only visible to enterprise owners. - """ - ownerInfo: EnterpriseOwnerInfo - - """ - The HTTP path for this enterprise. - """ - resourcePath: URI! - - """ - The URL-friendly identifier for the enterprise. - """ - slug: String! - - """ - The HTTP URL for this enterprise. - """ - url: URI! - - """ - A list of user accounts on this enterprise. - """ - userAccounts( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): EnterpriseUserAccountConnection! - - """ - Is the current viewer an admin of this enterprise? - """ - viewerIsAdmin: Boolean! - - """ - The URL of the enterprise website. - """ - websiteUrl: URI -} - -""" -The connection type for User. -""" -type EnterpriseAdministratorConnection { - """ - A list of edges. - """ - edges: [EnterpriseAdministratorEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A User who is an administrator of an enterprise. -""" -type EnterpriseAdministratorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User - - """ - The role of the administrator. - """ - role: EnterpriseAdministratorRole! -} - -""" -An invitation for a user to become an owner or billing manager of an enterprise. -""" -type EnterpriseAdministratorInvitation implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The email of the person who was invited to the enterprise. - """ - email: String - - """ - The enterprise the invitation is for. - """ - enterprise: Enterprise! - id: ID! - - """ - The user who was invited to the enterprise. - """ - invitee: User - - """ - The user who created the invitation. - """ - inviter: User - - """ - The invitee's pending role in the enterprise (owner or billing_manager). - """ - role: EnterpriseAdministratorRole! -} - -""" -The connection type for EnterpriseAdministratorInvitation. -""" -type EnterpriseAdministratorInvitationConnection { - """ - A list of edges. - """ - edges: [EnterpriseAdministratorInvitationEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseAdministratorInvitation] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseAdministratorInvitationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseAdministratorInvitation -} - -""" -Ordering options for enterprise administrator invitation connections -""" -input EnterpriseAdministratorInvitationOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order enterprise administrator invitations by. - """ - field: EnterpriseAdministratorInvitationOrderField! -} - -""" -Properties by which enterprise administrator invitation connections can be ordered. -""" -enum EnterpriseAdministratorInvitationOrderField { - """ - Order enterprise administrator member invitations by creation time - """ - CREATED_AT -} - -""" -The possible administrator roles in an enterprise account. -""" -enum EnterpriseAdministratorRole { - """ - Represents a billing manager of the enterprise account. - """ - BILLING_MANAGER - - """ - Represents an owner of the enterprise account. - """ - OWNER -} - -""" -Metadata for an audit entry containing enterprise account information. -""" -interface EnterpriseAuditEntryData { - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI -} - -""" -Enterprise billing information visible to enterprise billing managers and owners. -""" -type EnterpriseBillingInfo { - """ - The number of licenseable users/emails across the enterprise. - """ - allLicensableUsersCount: Int! - - """ - The number of data packs used by all organizations owned by the enterprise. - """ - assetPacks: Int! - - """ - The number of available seats across all owned organizations based on the unique number of billable users. - """ - availableSeats: Int! @deprecated(reason: "`availableSeats` will be replaced with `totalAvailableLicenses` to provide more clarity on the value being returned Use EnterpriseBillingInfo.totalAvailableLicenses instead. Removal on 2020-01-01 UTC.") - - """ - The bandwidth quota in GB for all organizations owned by the enterprise. - """ - bandwidthQuota: Float! - - """ - The bandwidth usage in GB for all organizations owned by the enterprise. - """ - bandwidthUsage: Float! - - """ - The bandwidth usage as a percentage of the bandwidth quota. - """ - bandwidthUsagePercentage: Int! - - """ - The total seats across all organizations owned by the enterprise. - """ - seats: Int! @deprecated(reason: "`seats` will be replaced with `totalLicenses` to provide more clarity on the value being returned Use EnterpriseBillingInfo.totalLicenses instead. Removal on 2020-01-01 UTC.") - - """ - The storage quota in GB for all organizations owned by the enterprise. - """ - storageQuota: Float! - - """ - The storage usage in GB for all organizations owned by the enterprise. - """ - storageUsage: Float! - - """ - The storage usage as a percentage of the storage quota. - """ - storageUsagePercentage: Int! - - """ - The number of available licenses across all owned organizations based on the unique number of billable users. - """ - totalAvailableLicenses: Int! - - """ - The total number of licenses allocated. - """ - totalLicenses: Int! -} - -""" -The possible values for the enterprise default repository permission setting. -""" -enum EnterpriseDefaultRepositoryPermissionSettingValue { - """ - Organization members will be able to clone, pull, push, and add new collaborators to all organization repositories. - """ - ADMIN - - """ - Organization members will only be able to clone and pull public repositories. - """ - NONE - - """ - Organizations in the enterprise choose default repository permissions for their members. - """ - NO_POLICY - - """ - Organization members will be able to clone and pull all organization repositories. - """ - READ - - """ - Organization members will be able to clone, pull, and push all organization repositories. - """ - WRITE -} - -""" -The possible values for an enabled/disabled enterprise setting. -""" -enum EnterpriseEnabledDisabledSettingValue { - """ - The setting is disabled for organizations in the enterprise. - """ - DISABLED - - """ - The setting is enabled for organizations in the enterprise. - """ - ENABLED - - """ - There is no policy set for organizations in the enterprise. - """ - NO_POLICY -} - -""" -The possible values for an enabled/no policy enterprise setting. -""" -enum EnterpriseEnabledSettingValue { - """ - The setting is enabled for organizations in the enterprise. - """ - ENABLED - - """ - There is no policy set for organizations in the enterprise. - """ - NO_POLICY -} - -""" -An identity provider configured to provision identities for an enterprise. -""" -type EnterpriseIdentityProvider implements Node { - """ - The digest algorithm used to sign SAML requests for the identity provider. - """ - digestMethod: SamlDigestAlgorithm - - """ - The enterprise this identity provider belongs to. - """ - enterprise: Enterprise - - """ - ExternalIdentities provisioned by this identity provider. - """ - externalIdentities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ExternalIdentityConnection! - id: ID! - - """ - The x509 certificate used by the identity provider to sign assertions and responses. - """ - idpCertificate: X509Certificate - - """ - The Issuer Entity ID for the SAML identity provider. - """ - issuer: String - - """ - Recovery codes that can be used by admins to access the enterprise if the identity provider is unavailable. - """ - recoveryCodes: [String!] - - """ - The signature algorithm used to sign SAML requests for the identity provider. - """ - signatureMethod: SamlSignatureAlgorithm - - """ - The URL endpoint for the identity provider's SAML SSO. - """ - ssoUrl: URI -} - -""" -An object that is a member of an enterprise. -""" -union EnterpriseMember = EnterpriseUserAccount | User - -""" -The connection type for EnterpriseMember. -""" -type EnterpriseMemberConnection { - """ - A list of edges. - """ - edges: [EnterpriseMemberEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseMember] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A User who is a member of an enterprise through one or more organizations. -""" -type EnterpriseMemberEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - Whether the user does not have a license for the enterprise. - """ - isUnlicensed: Boolean! - - """ - The item at the end of the edge. - """ - node: EnterpriseMember -} - -""" -Ordering options for enterprise member connections. -""" -input EnterpriseMemberOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order enterprise members by. - """ - field: EnterpriseMemberOrderField! -} - -""" -Properties by which enterprise member connections can be ordered. -""" -enum EnterpriseMemberOrderField { - """ - Order enterprise members by creation time - """ - CREATED_AT - - """ - Order enterprise members by login - """ - LOGIN -} - -""" -The possible values for the enterprise members can create repositories setting. -""" -enum EnterpriseMembersCanCreateRepositoriesSettingValue { - """ - Members will be able to create public and private repositories. - """ - ALL - - """ - Members will not be able to create public or private repositories. - """ - DISABLED - - """ - Organization administrators choose whether to allow members to create repositories. - """ - NO_POLICY - - """ - Members will be able to create only private repositories. - """ - PRIVATE - - """ - Members will be able to create only public repositories. - """ - PUBLIC -} - -""" -The possible values for the members can make purchases setting. -""" -enum EnterpriseMembersCanMakePurchasesSettingValue { - """ - The setting is disabled for organizations in the enterprise. - """ - DISABLED - - """ - The setting is enabled for organizations in the enterprise. - """ - ENABLED -} - -""" -The connection type for Organization. -""" -type EnterpriseOrganizationMembershipConnection { - """ - A list of edges. - """ - edges: [EnterpriseOrganizationMembershipEdge] - - """ - A list of nodes. - """ - nodes: [Organization] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An enterprise organization that a user is a member of. -""" -type EnterpriseOrganizationMembershipEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Organization - - """ - The role of the user in the enterprise membership. - """ - role: EnterpriseUserAccountMembershipRole! -} - -""" -The connection type for User. -""" -type EnterpriseOutsideCollaboratorConnection { - """ - A list of edges. - """ - edges: [EnterpriseOutsideCollaboratorEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A User who is an outside collaborator of an enterprise through one or more organizations. -""" -type EnterpriseOutsideCollaboratorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - Whether the outside collaborator does not have a license for the enterprise. - """ - isUnlicensed: Boolean! - - """ - The item at the end of the edge. - """ - node: User - - """ - The enterprise organization repositories this user is a member of. - """ - repositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories. - """ - orderBy: RepositoryOrder = {field: NAME, direction: ASC} - ): EnterpriseRepositoryInfoConnection! -} - -""" -Enterprise information only visible to enterprise owners. -""" -type EnterpriseOwnerInfo { - """ - A list of enterprise organizations configured with the provided action execution capabilities setting value. - """ - actionExecutionCapabilitySettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - ): OrganizationConnection! - - """ - A list of all of the administrators for this enterprise. - """ - admins( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for administrators returned from the connection. - """ - orderBy: EnterpriseMemberOrder = {field: LOGIN, direction: ASC} - - """ - The search string to look for. - """ - query: String - - """ - The role to filter by. - """ - role: EnterpriseAdministratorRole - ): EnterpriseAdministratorConnection! - - """ - A list of users in the enterprise who currently have two-factor authentication disabled. - """ - affiliatedUsersWithTwoFactorDisabled( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - Whether or not affiliated users with two-factor authentication disabled exist in the enterprise. - """ - affiliatedUsersWithTwoFactorDisabledExist: Boolean! - - """ - The setting value for whether private repository forking is enabled for repositories in organizations in this enterprise. - """ - allowPrivateRepositoryForkingSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided private repository forking setting value. - """ - allowPrivateRepositoryForkingSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for base repository permissions for organizations in this enterprise. - """ - defaultRepositoryPermissionSetting: EnterpriseDefaultRepositoryPermissionSettingValue! - - """ - A list of enterprise organizations configured with the provided default repository permission. - """ - defaultRepositoryPermissionSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The permission to find organizations for. - """ - value: DefaultRepositoryPermissionField! - ): OrganizationConnection! - - """ - Enterprise Server installations owned by the enterprise. - """ - enterpriseServerInstallations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Whether or not to only return installations discovered via GitHub Connect. - """ - connectedOnly: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for Enterprise Server installations returned. - """ - orderBy: EnterpriseServerInstallationOrder = {field: HOST_NAME, direction: ASC} - ): EnterpriseServerInstallationConnection! - - """ - The setting value for whether the enterprise has an IP allow list enabled. - """ - ipAllowListEnabledSetting: IpAllowListEnabledSettingValue! - - """ - The IP addresses that are allowed to access resources owned by the enterprise. - """ - ipAllowListEntries( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for IP allow list entries returned. - """ - orderBy: IpAllowListEntryOrder = {field: ALLOW_LIST_VALUE, direction: ASC} - ): IpAllowListEntryConnection! - - """ - Whether or not the default repository permission is currently being updated. - """ - isUpdatingDefaultRepositoryPermission: Boolean! - - """ - Whether the two-factor authentication requirement is currently being enforced. - """ - isUpdatingTwoFactorRequirement: Boolean! - - """ - The setting value for whether organization members with admin permissions on a - repository can change repository visibility. - """ - membersCanChangeRepositoryVisibilitySetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided can change repository visibility setting value. - """ - membersCanChangeRepositoryVisibilitySettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for whether members of organizations in the enterprise can create internal repositories. - """ - membersCanCreateInternalRepositoriesSetting: Boolean - - """ - The setting value for whether members of organizations in the enterprise can create private repositories. - """ - membersCanCreatePrivateRepositoriesSetting: Boolean - - """ - The setting value for whether members of organizations in the enterprise can create public repositories. - """ - membersCanCreatePublicRepositoriesSetting: Boolean - - """ - The setting value for whether members of organizations in the enterprise can create repositories. - """ - membersCanCreateRepositoriesSetting: EnterpriseMembersCanCreateRepositoriesSettingValue - - """ - A list of enterprise organizations configured with the provided repository creation setting value. - """ - membersCanCreateRepositoriesSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting to find organizations for. - """ - value: OrganizationMembersCanCreateRepositoriesSettingValue! - ): OrganizationConnection! - - """ - The setting value for whether members with admin permissions for repositories can delete issues. - """ - membersCanDeleteIssuesSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided members can delete issues setting value. - """ - membersCanDeleteIssuesSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for whether members with admin permissions for repositories can delete or transfer repositories. - """ - membersCanDeleteRepositoriesSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided members can delete repositories setting value. - """ - membersCanDeleteRepositoriesSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for whether members of organizations in the enterprise can invite outside collaborators. - """ - membersCanInviteCollaboratorsSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided members can invite collaborators setting value. - """ - membersCanInviteCollaboratorsSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - Indicates whether members of this enterprise's organizations can purchase additional services for those organizations. - """ - membersCanMakePurchasesSetting: EnterpriseMembersCanMakePurchasesSettingValue! - - """ - The setting value for whether members with admin permissions for repositories can update protected branches. - """ - membersCanUpdateProtectedBranchesSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided members can update protected branches setting value. - """ - membersCanUpdateProtectedBranchesSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for whether members can view dependency insights. - """ - membersCanViewDependencyInsightsSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided members can view dependency insights setting value. - """ - membersCanViewDependencyInsightsSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for whether organization projects are enabled for organizations in this enterprise. - """ - organizationProjectsSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided organization projects setting value. - """ - organizationProjectsSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - A list of outside collaborators across the repositories in the enterprise. - """ - outsideCollaborators( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - The login of one specific outside collaborator. - """ - login: String - - """ - Ordering options for outside collaborators returned from the connection. - """ - orderBy: EnterpriseMemberOrder = {field: LOGIN, direction: ASC} - - """ - The search string to look for. - """ - query: String - - """ - Only return outside collaborators on repositories with this visibility. - """ - visibility: RepositoryVisibility - ): EnterpriseOutsideCollaboratorConnection! - - """ - A list of pending administrator invitations for the enterprise. - """ - pendingAdminInvitations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pending enterprise administrator invitations returned from the connection. - """ - orderBy: EnterpriseAdministratorInvitationOrder = {field: CREATED_AT, direction: DESC} - - """ - The search string to look for. - """ - query: String - - """ - The role to filter by. - """ - role: EnterpriseAdministratorRole - ): EnterpriseAdministratorInvitationConnection! - - """ - A list of pending collaborator invitations across the repositories in the enterprise. - """ - pendingCollaboratorInvitations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pending repository collaborator invitations returned from the connection. - """ - orderBy: RepositoryInvitationOrder = {field: CREATED_AT, direction: DESC} - - """ - The search string to look for. - """ - query: String - ): RepositoryInvitationConnection! - - """ - A list of pending collaborators across the repositories in the enterprise. - """ - pendingCollaborators( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pending repository collaborator invitations returned from the connection. - """ - orderBy: RepositoryInvitationOrder = {field: CREATED_AT, direction: DESC} - - """ - The search string to look for. - """ - query: String - ): EnterprisePendingCollaboratorConnection! @deprecated(reason: "Repository invitations can now be associated with an email, not only an invitee. Use the `pendingCollaboratorInvitations` field instead. Removal on 2020-10-01 UTC.") - - """ - A list of pending member invitations for organizations in the enterprise. - """ - pendingMemberInvitations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - The search string to look for. - """ - query: String - ): EnterprisePendingMemberInvitationConnection! - - """ - The setting value for whether repository projects are enabled in this enterprise. - """ - repositoryProjectsSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided repository projects setting value. - """ - repositoryProjectsSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The SAML Identity Provider for the enterprise. - """ - samlIdentityProvider: EnterpriseIdentityProvider - - """ - A list of enterprise organizations configured with the SAML single sign-on setting value. - """ - samlIdentityProviderSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: IdentityProviderConfigurationState! - ): OrganizationConnection! - - """ - The setting value for whether team discussions are enabled for organizations in this enterprise. - """ - teamDiscussionsSetting: EnterpriseEnabledDisabledSettingValue! - - """ - A list of enterprise organizations configured with the provided team discussions setting value. - """ - teamDiscussionsSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! - - """ - The setting value for whether the enterprise requires two-factor authentication for its organizations and users. - """ - twoFactorRequiredSetting: EnterpriseEnabledSettingValue! - - """ - A list of enterprise organizations configured with the two-factor authentication setting value. - """ - twoFactorRequiredSettingOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations with this setting. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The setting value to find organizations for. - """ - value: Boolean! - ): OrganizationConnection! -} - -""" -The connection type for User. -""" -type EnterprisePendingCollaboratorConnection { - """ - A list of edges. - """ - edges: [EnterprisePendingCollaboratorEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A user with an invitation to be a collaborator on a repository owned by an organization in an enterprise. -""" -type EnterprisePendingCollaboratorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - Whether the invited collaborator does not have a license for the enterprise. - """ - isUnlicensed: Boolean! - - """ - The item at the end of the edge. - """ - node: User - - """ - The enterprise organization repositories this user is a member of. - """ - repositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories. - """ - orderBy: RepositoryOrder = {field: NAME, direction: ASC} - ): EnterpriseRepositoryInfoConnection! -} - -""" -The connection type for OrganizationInvitation. -""" -type EnterprisePendingMemberInvitationConnection { - """ - A list of edges. - """ - edges: [EnterprisePendingMemberInvitationEdge] - - """ - A list of nodes. - """ - nodes: [OrganizationInvitation] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Identifies the total count of unique users in the connection. - """ - totalUniqueUserCount: Int! -} - -""" -An invitation to be a member in an enterprise organization. -""" -type EnterprisePendingMemberInvitationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - Whether the invitation has a license for the enterprise. - """ - isUnlicensed: Boolean! - - """ - The item at the end of the edge. - """ - node: OrganizationInvitation -} - -""" -A subset of repository information queryable from an enterprise. -""" -type EnterpriseRepositoryInfo implements Node { - id: ID! - - """ - Identifies if the repository is private. - """ - isPrivate: Boolean! - - """ - The repository's name. - """ - name: String! - - """ - The repository's name with owner. - """ - nameWithOwner: String! -} - -""" -The connection type for EnterpriseRepositoryInfo. -""" -type EnterpriseRepositoryInfoConnection { - """ - A list of edges. - """ - edges: [EnterpriseRepositoryInfoEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseRepositoryInfo] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseRepositoryInfoEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseRepositoryInfo -} - -""" -An Enterprise Server installation. -""" -type EnterpriseServerInstallation implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The customer name to which the Enterprise Server installation belongs. - """ - customerName: String! - - """ - The host name of the Enterprise Server installation. - """ - hostName: String! - id: ID! - - """ - Whether or not the installation is connected to an Enterprise Server installation via GitHub Connect. - """ - isConnected: Boolean! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - User accounts on this Enterprise Server installation. - """ - userAccounts( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for Enterprise Server user accounts returned from the connection. - """ - orderBy: EnterpriseServerUserAccountOrder = {field: LOGIN, direction: ASC} - ): EnterpriseServerUserAccountConnection! - - """ - User accounts uploads for the Enterprise Server installation. - """ - userAccountsUploads( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for Enterprise Server user accounts uploads returned from the connection. - """ - orderBy: EnterpriseServerUserAccountsUploadOrder = {field: CREATED_AT, direction: DESC} - ): EnterpriseServerUserAccountsUploadConnection! -} - -""" -The connection type for EnterpriseServerInstallation. -""" -type EnterpriseServerInstallationConnection { - """ - A list of edges. - """ - edges: [EnterpriseServerInstallationEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseServerInstallation] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseServerInstallationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseServerInstallation -} - -""" -Ordering options for Enterprise Server installation connections. -""" -input EnterpriseServerInstallationOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order Enterprise Server installations by. - """ - field: EnterpriseServerInstallationOrderField! -} - -""" -Properties by which Enterprise Server installation connections can be ordered. -""" -enum EnterpriseServerInstallationOrderField { - """ - Order Enterprise Server installations by creation time - """ - CREATED_AT - - """ - Order Enterprise Server installations by customer name - """ - CUSTOMER_NAME - - """ - Order Enterprise Server installations by host name - """ - HOST_NAME -} - -""" -A user account on an Enterprise Server installation. -""" -type EnterpriseServerUserAccount implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - User emails belonging to this user account. - """ - emails( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for Enterprise Server user account emails returned from the connection. - """ - orderBy: EnterpriseServerUserAccountEmailOrder = {field: EMAIL, direction: ASC} - ): EnterpriseServerUserAccountEmailConnection! - - """ - The Enterprise Server installation on which this user account exists. - """ - enterpriseServerInstallation: EnterpriseServerInstallation! - id: ID! - - """ - Whether the user account is a site administrator on the Enterprise Server installation. - """ - isSiteAdmin: Boolean! - - """ - The login of the user account on the Enterprise Server installation. - """ - login: String! - - """ - The profile name of the user account on the Enterprise Server installation. - """ - profileName: String - - """ - The date and time when the user account was created on the Enterprise Server installation. - """ - remoteCreatedAt: DateTime! - - """ - The ID of the user account on the Enterprise Server installation. - """ - remoteUserId: Int! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for EnterpriseServerUserAccount. -""" -type EnterpriseServerUserAccountConnection { - """ - A list of edges. - """ - edges: [EnterpriseServerUserAccountEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseServerUserAccount] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseServerUserAccountEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseServerUserAccount -} - -""" -An email belonging to a user account on an Enterprise Server installation. -""" -type EnterpriseServerUserAccountEmail implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The email address. - """ - email: String! - id: ID! - - """ - Indicates whether this is the primary email of the associated user account. - """ - isPrimary: Boolean! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The user account to which the email belongs. - """ - userAccount: EnterpriseServerUserAccount! -} - -""" -The connection type for EnterpriseServerUserAccountEmail. -""" -type EnterpriseServerUserAccountEmailConnection { - """ - A list of edges. - """ - edges: [EnterpriseServerUserAccountEmailEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseServerUserAccountEmail] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseServerUserAccountEmailEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseServerUserAccountEmail -} - -""" -Ordering options for Enterprise Server user account email connections. -""" -input EnterpriseServerUserAccountEmailOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order emails by. - """ - field: EnterpriseServerUserAccountEmailOrderField! -} - -""" -Properties by which Enterprise Server user account email connections can be ordered. -""" -enum EnterpriseServerUserAccountEmailOrderField { - """ - Order emails by email - """ - EMAIL -} - -""" -Ordering options for Enterprise Server user account connections. -""" -input EnterpriseServerUserAccountOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order user accounts by. - """ - field: EnterpriseServerUserAccountOrderField! -} - -""" -Properties by which Enterprise Server user account connections can be ordered. -""" -enum EnterpriseServerUserAccountOrderField { - """ - Order user accounts by login - """ - LOGIN - - """ - Order user accounts by creation time on the Enterprise Server installation - """ - REMOTE_CREATED_AT -} - -""" -A user accounts upload from an Enterprise Server installation. -""" -type EnterpriseServerUserAccountsUpload implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The enterprise to which this upload belongs. - """ - enterprise: Enterprise! - - """ - The Enterprise Server installation for which this upload was generated. - """ - enterpriseServerInstallation: EnterpriseServerInstallation! - id: ID! - - """ - The name of the file uploaded. - """ - name: String! - - """ - The synchronization state of the upload - """ - syncState: EnterpriseServerUserAccountsUploadSyncState! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for EnterpriseServerUserAccountsUpload. -""" -type EnterpriseServerUserAccountsUploadConnection { - """ - A list of edges. - """ - edges: [EnterpriseServerUserAccountsUploadEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseServerUserAccountsUpload] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseServerUserAccountsUploadEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseServerUserAccountsUpload -} - -""" -Ordering options for Enterprise Server user accounts upload connections. -""" -input EnterpriseServerUserAccountsUploadOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order user accounts uploads by. - """ - field: EnterpriseServerUserAccountsUploadOrderField! -} - -""" -Properties by which Enterprise Server user accounts upload connections can be ordered. -""" -enum EnterpriseServerUserAccountsUploadOrderField { - """ - Order user accounts uploads by creation time - """ - CREATED_AT -} - -""" -Synchronization state of the Enterprise Server user accounts upload -""" -enum EnterpriseServerUserAccountsUploadSyncState { - """ - The synchronization of the upload failed. - """ - FAILURE - - """ - The synchronization of the upload is pending. - """ - PENDING - - """ - The synchronization of the upload succeeded. - """ - SUCCESS -} - -""" -An account for a user who is an admin of an enterprise or a member of an enterprise through one or more organizations. -""" -type EnterpriseUserAccount implements Actor & Node { - """ - A URL pointing to the enterprise user account's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The enterprise in which this user account exists. - """ - enterprise: Enterprise! - id: ID! - - """ - An identifier for the enterprise user account, a login or email address - """ - login: String! - - """ - The name of the enterprise user account - """ - name: String - - """ - A list of enterprise organizations this user is a member of. - """ - organizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for organizations returned from the connection. - """ - orderBy: OrganizationOrder = {field: LOGIN, direction: ASC} - - """ - The search string to look for. - """ - query: String - - """ - The role of the user in the enterprise organization. - """ - role: EnterpriseUserAccountMembershipRole - ): EnterpriseOrganizationMembershipConnection! - - """ - The HTTP path for this user. - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this user. - """ - url: URI! - - """ - The user within the enterprise. - """ - user: User -} - -""" -The connection type for EnterpriseUserAccount. -""" -type EnterpriseUserAccountConnection { - """ - A list of edges. - """ - edges: [EnterpriseUserAccountEdge] - - """ - A list of nodes. - """ - nodes: [EnterpriseUserAccount] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type EnterpriseUserAccountEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: EnterpriseUserAccount -} - -""" -The possible roles for enterprise membership. -""" -enum EnterpriseUserAccountMembershipRole { - """ - The user is a member of the enterprise membership. - """ - MEMBER - - """ - The user is an owner of the enterprise membership. - """ - OWNER -} - -""" -The possible GitHub Enterprise deployments where this user can exist. -""" -enum EnterpriseUserDeployment { - """ - The user is part of a GitHub Enterprise Cloud deployment. - """ - CLOUD - - """ - The user is part of a GitHub Enterprise Server deployment. - """ - SERVER -} - -""" -An external identity provisioned by SAML SSO or SCIM. -""" -type ExternalIdentity implements Node { - """ - The GUID for this identity - """ - guid: String! - id: ID! - - """ - Organization invitation for this SCIM-provisioned external identity - """ - organizationInvitation: OrganizationInvitation - - """ - SAML Identity attributes - """ - samlIdentity: ExternalIdentitySamlAttributes - - """ - SCIM Identity attributes - """ - scimIdentity: ExternalIdentityScimAttributes - - """ - User linked to this external identity. Will be NULL if this identity has not been claimed by an organization member. - """ - user: User -} - -""" -The connection type for ExternalIdentity. -""" -type ExternalIdentityConnection { - """ - A list of edges. - """ - edges: [ExternalIdentityEdge] - - """ - A list of nodes. - """ - nodes: [ExternalIdentity] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ExternalIdentityEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ExternalIdentity -} - -""" -SAML attributes for the External Identity -""" -type ExternalIdentitySamlAttributes { - """ - The NameID of the SAML identity - """ - nameId: String -} - -""" -SCIM attributes for the External Identity -""" -type ExternalIdentityScimAttributes { - """ - The userName of the SCIM identity - """ - username: String -} - -""" -Autogenerated input type of FollowUser -""" -input FollowUserInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the user to follow. - """ - userId: ID! @possibleTypes(concreteTypes: ["User"]) -} - -""" -Autogenerated return type of FollowUser -""" -type FollowUserPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The user that was followed. - """ - user: User -} - -""" -The connection type for User. -""" -type FollowerConnection { - """ - A list of edges. - """ - edges: [UserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -The connection type for User. -""" -type FollowingConnection { - """ - A list of edges. - """ - edges: [UserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A funding platform link for a repository. -""" -type FundingLink { - """ - The funding platform this link is for. - """ - platform: FundingPlatform! - - """ - The configured URL for this funding link. - """ - url: URI! -} - -""" -The possible funding platforms for repository funding links. -""" -enum FundingPlatform { - """ - Community Bridge funding platform. - """ - COMMUNITY_BRIDGE - - """ - Custom funding platform. - """ - CUSTOM - - """ - GitHub funding platform. - """ - GITHUB - - """ - IssueHunt funding platform. - """ - ISSUEHUNT - - """ - Ko-fi funding platform. - """ - KO_FI - - """ - Liberapay funding platform. - """ - LIBERAPAY - - """ - Open Collective funding platform. - """ - OPEN_COLLECTIVE - - """ - Otechie funding platform. - """ - OTECHIE - - """ - Patreon funding platform. - """ - PATREON - - """ - Tidelift funding platform. - """ - TIDELIFT -} - -""" -A generic hovercard context with a message and icon -""" -type GenericHovercardContext implements HovercardContext { - """ - A string describing this context - """ - message: String! - - """ - An octicon to accompany this context - """ - octicon: String! -} - -""" -A Gist. -""" -type Gist implements Node & Starrable & UniformResourceLocatable { - """ - A list of comments associated with the gist - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): GistCommentConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The gist description. - """ - description: String - - """ - The files in this gist. - """ - files( - """ - The maximum number of files to return. - """ - limit: Int = 10 - - """ - The oid of the files to return - """ - oid: GitObjectID - ): [GistFile] - - """ - A list of forks associated with the gist - """ - forks( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for gists returned from the connection - """ - orderBy: GistOrder - ): GistConnection! - id: ID! - - """ - Identifies if the gist is a fork. - """ - isFork: Boolean! - - """ - Whether the gist is public or not. - """ - isPublic: Boolean! - - """ - The gist name. - """ - name: String! - - """ - The gist owner. - """ - owner: RepositoryOwner - - """ - Identifies when the gist was last pushed to. - """ - pushedAt: DateTime - - """ - The HTML path to this resource. - """ - resourcePath: URI! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this Gist. - """ - url: URI! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! -} - -""" -Represents a comment on an Gist. -""" -type GistComment implements Comment & Deletable & Minimizable & Node & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the gist. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the comment body. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - - """ - The associated gist. - """ - gist: Gist! - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for GistComment. -""" -type GistCommentConnection { - """ - A list of edges. - """ - edges: [GistCommentEdge] - - """ - A list of nodes. - """ - nodes: [GistComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type GistCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: GistComment -} - -""" -The connection type for Gist. -""" -type GistConnection { - """ - A list of edges. - """ - edges: [GistEdge] - - """ - A list of nodes. - """ - nodes: [Gist] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type GistEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Gist -} - -""" -A file in a gist. -""" -type GistFile { - """ - The file name encoded to remove characters that are invalid in URL paths. - """ - encodedName: String - - """ - The gist file encoding. - """ - encoding: String - - """ - The file extension from the file name. - """ - extension: String - - """ - Indicates if this file is an image. - """ - isImage: Boolean! - - """ - Whether the file's contents were truncated. - """ - isTruncated: Boolean! - - """ - The programming language this file is written in. - """ - language: Language - - """ - The gist file name. - """ - name: String - - """ - The gist file size in bytes. - """ - size: Int - - """ - UTF8 text data or null if the file is binary - """ - text( - """ - Optionally truncate the returned file to this length. - """ - truncate: Int - ): String -} - -""" -Ordering options for gist connections -""" -input GistOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repositories by. - """ - field: GistOrderField! -} - -""" -Properties by which gist connections can be ordered. -""" -enum GistOrderField { - """ - Order gists by creation time - """ - CREATED_AT - - """ - Order gists by push time - """ - PUSHED_AT - - """ - Order gists by update time - """ - UPDATED_AT -} - -""" -The privacy of a Gist -""" -enum GistPrivacy { - """ - Gists that are public and secret - """ - ALL - - """ - Public - """ - PUBLIC - - """ - Secret - """ - SECRET -} - -""" -Represents an actor in a Git commit (ie. an author or committer). -""" -type GitActor { - """ - A URL pointing to the author's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - The timestamp of the Git action (authoring or committing). - """ - date: GitTimestamp - - """ - The email in the Git commit. - """ - email: String - - """ - The name in the Git commit. - """ - name: String - - """ - The GitHub user corresponding to the email field. Null if no such user exists. - """ - user: User -} - -""" -Represents information about the GitHub instance. -""" -type GitHubMetadata { - """ - Returns a String that's a SHA of `github-services` - """ - gitHubServicesSha: GitObjectID! - - """ - IP addresses that users connect to for git operations - """ - gitIpAddresses: [String!] - - """ - IP addresses that service hooks are sent from - """ - hookIpAddresses: [String!] - - """ - IP addresses that the importer connects from - """ - importerIpAddresses: [String!] - - """ - Whether or not users are verified - """ - isPasswordAuthenticationVerifiable: Boolean! - - """ - IP addresses for GitHub Pages' A records - """ - pagesIpAddresses: [String!] -} - -""" -Represents a Git object. -""" -interface GitObject { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - id: ID! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! -} - -""" -A Git object ID. -""" -scalar GitObjectID - -""" -A fully qualified reference name (e.g. `refs/heads/master`). -""" -scalar GitRefname @preview(toggledBy: "update-refs-preview") - -""" -Git SSH string -""" -scalar GitSSHRemote - -""" -Information about a signature (GPG or S/MIME) on a Commit or Tag. -""" -interface GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -The state of a Git signature. -""" -enum GitSignatureState { - """ - The signing certificate or its chain could not be verified - """ - BAD_CERT - - """ - Invalid email used for signing - """ - BAD_EMAIL - - """ - Signing key expired - """ - EXPIRED_KEY - - """ - Internal error - the GPG verification service misbehaved - """ - GPGVERIFY_ERROR - - """ - Internal error - the GPG verification service is unavailable at the moment - """ - GPGVERIFY_UNAVAILABLE - - """ - Invalid signature - """ - INVALID - - """ - Malformed signature - """ - MALFORMED_SIG - - """ - The usage flags for the key that signed this don't allow signing - """ - NOT_SIGNING_KEY - - """ - Email used for signing not known to GitHub - """ - NO_USER - - """ - Valid siganture, though certificate revocation check failed - """ - OCSP_ERROR - - """ - Valid signature, pending certificate revocation checking - """ - OCSP_PENDING - - """ - One or more certificates in chain has been revoked - """ - OCSP_REVOKED - - """ - Key used for signing not known to GitHub - """ - UNKNOWN_KEY - - """ - Unknown signature type - """ - UNKNOWN_SIG_TYPE - - """ - Unsigned - """ - UNSIGNED - - """ - Email used for signing unverified on GitHub - """ - UNVERIFIED_EMAIL - - """ - Valid signature and verified by GitHub - """ - VALID -} - -""" -An ISO-8601 encoded date string. Unlike the DateTime type, GitTimestamp is not converted in UTC. -""" -scalar GitTimestamp - -""" -Represents a GPG signature on a Commit or Tag. -""" -type GpgSignature implements GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Hex-encoded ID of the key that signed this object. - """ - keyId: String - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -A string containing HTML code. -""" -scalar HTML - -""" -Represents a 'head_ref_deleted' event on a given pull request. -""" -type HeadRefDeletedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the Ref associated with the `head_ref_deleted` event. - """ - headRef: Ref - - """ - Identifies the name of the Ref associated with the `head_ref_deleted` event. - """ - headRefName: String! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Represents a 'head_ref_force_pushed' event on a given pull request. -""" -type HeadRefForcePushedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the after commit SHA for the 'head_ref_force_pushed' event. - """ - afterCommit: Commit - - """ - Identifies the before commit SHA for the 'head_ref_force_pushed' event. - """ - beforeCommit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the fully qualified ref name for the 'head_ref_force_pushed' event. - """ - ref: Ref -} - -""" -Represents a 'head_ref_restored' event on a given pull request. -""" -type HeadRefRestoredEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Detail needed to display a hovercard for a user -""" -type Hovercard { - """ - Each of the contexts for this hovercard - """ - contexts: [HovercardContext!]! -} - -""" -An individual line of a hovercard -""" -interface HovercardContext { - """ - A string describing this context - """ - message: String! - - """ - An octicon to accompany this context - """ - octicon: String! -} - -""" -The possible states in which authentication can be configured with an identity provider. -""" -enum IdentityProviderConfigurationState { - """ - Authentication with an identity provider is configured but not enforced. - """ - CONFIGURED - - """ - Authentication with an identity provider is configured and enforced. - """ - ENFORCED - - """ - Authentication with an identity provider is not configured. - """ - UNCONFIGURED -} - -""" -Autogenerated input type of ImportProject -""" -input ImportProjectInput { - """ - The description of Project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A list of columns containing issues and pull requests. - """ - columnImports: [ProjectColumnImport!]! - - """ - The name of Project. - """ - name: String! - - """ - The name of the Organization or User to create the Project under. - """ - ownerName: String! - - """ - Whether the Project is public or not. - """ - public: Boolean = false -} - -""" -Autogenerated return type of ImportProject -""" -type ImportProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new Project! - """ - project: Project -} - -""" -Autogenerated input type of InviteEnterpriseAdmin -""" -input InviteEnterpriseAdminInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The email of the person to invite as an administrator. - """ - email: String - - """ - The ID of the enterprise to which you want to invite an administrator. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The login of a user to invite as an administrator. - """ - invitee: String - - """ - The role of the administrator. - """ - role: EnterpriseAdministratorRole -} - -""" -Autogenerated return type of InviteEnterpriseAdmin -""" -type InviteEnterpriseAdminPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The created enterprise administrator invitation. - """ - invitation: EnterpriseAdministratorInvitation -} - -""" -The possible values for the IP allow list enabled setting. -""" -enum IpAllowListEnabledSettingValue { - """ - The setting is disabled for the owner. - """ - DISABLED - - """ - The setting is enabled for the owner. - """ - ENABLED -} - -""" -An IP address or range of addresses that is allowed to access an owner's resources. -""" -type IpAllowListEntry implements Node { - """ - A single IP address or range of IP addresses in CIDR notation. - """ - allowListValue: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Whether the entry is currently active. - """ - isActive: Boolean! - - """ - The name of the IP allow list entry. - """ - name: String - - """ - The owner of the IP allow list entry. - """ - owner: IpAllowListOwner! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for IpAllowListEntry. -""" -type IpAllowListEntryConnection { - """ - A list of edges. - """ - edges: [IpAllowListEntryEdge] - - """ - A list of nodes. - """ - nodes: [IpAllowListEntry] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type IpAllowListEntryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IpAllowListEntry -} - -""" -Ordering options for IP allow list entry connections. -""" -input IpAllowListEntryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order IP allow list entries by. - """ - field: IpAllowListEntryOrderField! -} - -""" -Properties by which IP allow list entry connections can be ordered. -""" -enum IpAllowListEntryOrderField { - """ - Order IP allow list entries by the allow list value. - """ - ALLOW_LIST_VALUE - - """ - Order IP allow list entries by creation time. - """ - CREATED_AT -} - -""" -Types that can own an IP allow list. -""" -union IpAllowListOwner = Enterprise | Organization - -""" -An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project. -""" -type Issue implements Assignable & Closable & Comment & Labelable & Lockable & Node & Reactable & RepositoryNode & Subscribable & UniformResourceLocatable & Updatable & UpdatableComment { - """ - Reason that the conversation was locked. - """ - activeLockReason: LockReason - - """ - A list of Users assigned to this object. - """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the body of the issue. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - Identifies the body of the issue rendered to text. - """ - bodyText: String! - - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - A list of comments associated with the Issue. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): IssueCommentConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - - """ - The hovercard information for this issue - """ - hovercard( - """ - Whether or not to include notification contexts - """ - includeNotificationContexts: Boolean = true - ): Hovercard! - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - A list of labels associated with the object. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for labels returned from the connection. - """ - orderBy: LabelOrder = {field: CREATED_AT, direction: ASC} - ): LabelConnection - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - `true` if the object is locked - """ - locked: Boolean! - - """ - Identifies the milestone associated with the issue. - """ - milestone: Milestone - - """ - Identifies the issue number. - """ - number: Int! - - """ - A list of Users that are participating in the Issue conversation. - """ - participants( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - List of project cards associated with this issue. - """ - projectCards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path for this issue - """ - resourcePath: URI! - - """ - Identifies the state of the issue. - """ - state: IssueState! - - """ - A list of events, comments, commits, etc. associated with the issue. - """ - timeline( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows filtering timeline events by a `since` timestamp. - """ - since: DateTime - ): IssueTimelineConnection! @deprecated(reason: "`timeline` will be removed Use Issue.timelineItems instead. Removal on 2020-10-01 UTC.") - - """ - A list of events, comments, commits, etc. associated with the issue. - """ - timelineItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Filter timeline items by type. - """ - itemTypes: [IssueTimelineItemsItemType!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter timeline items by a `since` timestamp. - """ - since: DateTime - - """ - Skips the first _n_ elements in the list. - """ - skip: Int - ): IssueTimelineItemsConnection! - - """ - Identifies the issue title. - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this issue - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -Represents a comment on an Issue. -""" -type IssueComment implements Comment & Deletable & Minimizable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - Identifies the issue associated with the comment. - """ - issue: Issue! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Returns the pull request associated with the comment, if this comment was made on a - pull request. - """ - pullRequest: PullRequest - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path for this issue comment - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this issue comment - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for IssueComment. -""" -type IssueCommentConnection { - """ - A list of edges. - """ - edges: [IssueCommentEdge] - - """ - A list of nodes. - """ - nodes: [IssueComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type IssueCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueComment -} - -""" -The connection type for Issue. -""" -type IssueConnection { - """ - A list of edges. - """ - edges: [IssueEdge] - - """ - A list of nodes. - """ - nodes: [Issue] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -This aggregates issues opened by a user within one repository. -""" -type IssueContributionsByRepository { - """ - The issue contributions. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedIssueContributionConnection! - - """ - The repository in which the issues were opened. - """ - repository: Repository! -} - -""" -An edge in a connection. -""" -type IssueEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Issue -} - -""" -Ways in which to filter lists of issues. -""" -input IssueFilters { - """ - List issues assigned to given name. Pass in `null` for issues with no assigned - user, and `*` for issues assigned to any user. - """ - assignee: String - - """ - List issues created by given name. - """ - createdBy: String - - """ - List issues where the list of label names exist on the issue. - """ - labels: [String!] - - """ - List issues where the given name is mentioned in the issue. - """ - mentioned: String - - """ - List issues by given milestone argument. If an string representation of an - integer is passed, it should refer to a milestone by its number field. Pass in - `null` for issues with no milestone, and `*` for issues that are assigned to any milestone. - """ - milestone: String - - """ - List issues that have been updated at or after the given date. - """ - since: DateTime - - """ - List issues filtered by the list of states given. - """ - states: [IssueState!] - - """ - List issues subscribed to by viewer. - """ - viewerSubscribed: Boolean = false -} - -""" -Used for return value of Repository.issueOrPullRequest. -""" -union IssueOrPullRequest = Issue | PullRequest - -""" -Ways in which lists of issues can be ordered upon return. -""" -input IssueOrder { - """ - The direction in which to order issues by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order issues by. - """ - field: IssueOrderField! -} - -""" -Properties by which issue connections can be ordered. -""" -enum IssueOrderField { - """ - Order issues by comment count - """ - COMMENTS - - """ - Order issues by creation time - """ - CREATED_AT - - """ - Order issues by update time - """ - UPDATED_AT -} - -""" -The possible states of an issue. -""" -enum IssueState { - """ - An issue that has been closed - """ - CLOSED - - """ - An issue that is still open - """ - OPEN -} - -""" -The connection type for IssueTimelineItem. -""" -type IssueTimelineConnection { - """ - A list of edges. - """ - edges: [IssueTimelineItemEdge] - - """ - A list of nodes. - """ - nodes: [IssueTimelineItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An item in an issue timeline -""" -union IssueTimelineItem = AssignedEvent | ClosedEvent | Commit | CrossReferencedEvent | DemilestonedEvent | IssueComment | LabeledEvent | LockedEvent | MilestonedEvent | ReferencedEvent | RenamedTitleEvent | ReopenedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -An edge in a connection. -""" -type IssueTimelineItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueTimelineItem -} - -""" -An item in an issue timeline -""" -union IssueTimelineItems = AddedToProjectEvent | AssignedEvent | ClosedEvent | CommentDeletedEvent | ConnectedEvent | ConvertedNoteToIssueEvent | CrossReferencedEvent | DemilestonedEvent | DisconnectedEvent | IssueComment | LabeledEvent | LockedEvent | MarkedAsDuplicateEvent | MentionedEvent | MilestonedEvent | MovedColumnsInProjectEvent | PinnedEvent | ReferencedEvent | RemovedFromProjectEvent | RenamedTitleEvent | ReopenedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnmarkedAsDuplicateEvent | UnpinnedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -The connection type for IssueTimelineItems. -""" -type IssueTimelineItemsConnection { - """ - A list of edges. - """ - edges: [IssueTimelineItemsEdge] - - """ - Identifies the count of items after applying `before` and `after` filters. - """ - filteredCount: Int! - - """ - A list of nodes. - """ - nodes: [IssueTimelineItems] - - """ - Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing. - """ - pageCount: Int! - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Identifies the date and time when the timeline was last updated. - """ - updatedAt: DateTime! -} - -""" -An edge in a connection. -""" -type IssueTimelineItemsEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueTimelineItems -} - -""" -The possible item types found in a timeline. -""" -enum IssueTimelineItemsItemType { - """ - Represents a 'added_to_project' event on a given issue or pull request. - """ - ADDED_TO_PROJECT_EVENT - - """ - Represents an 'assigned' event on any assignable object. - """ - ASSIGNED_EVENT - - """ - Represents a 'closed' event on any `Closable`. - """ - CLOSED_EVENT - - """ - Represents a 'comment_deleted' event on a given issue or pull request. - """ - COMMENT_DELETED_EVENT - - """ - Represents a 'connected' event on a given issue or pull request. - """ - CONNECTED_EVENT - - """ - Represents a 'converted_note_to_issue' event on a given issue or pull request. - """ - CONVERTED_NOTE_TO_ISSUE_EVENT - - """ - Represents a mention made by one issue or pull request to another. - """ - CROSS_REFERENCED_EVENT - - """ - Represents a 'demilestoned' event on a given issue or pull request. - """ - DEMILESTONED_EVENT - - """ - Represents a 'disconnected' event on a given issue or pull request. - """ - DISCONNECTED_EVENT - - """ - Represents a comment on an Issue. - """ - ISSUE_COMMENT - - """ - Represents a 'labeled' event on a given issue or pull request. - """ - LABELED_EVENT - - """ - Represents a 'locked' event on a given issue or pull request. - """ - LOCKED_EVENT - - """ - Represents a 'marked_as_duplicate' event on a given issue or pull request. - """ - MARKED_AS_DUPLICATE_EVENT - - """ - Represents a 'mentioned' event on a given issue or pull request. - """ - MENTIONED_EVENT - - """ - Represents a 'milestoned' event on a given issue or pull request. - """ - MILESTONED_EVENT - - """ - Represents a 'moved_columns_in_project' event on a given issue or pull request. - """ - MOVED_COLUMNS_IN_PROJECT_EVENT - - """ - Represents a 'pinned' event on a given issue or pull request. - """ - PINNED_EVENT - - """ - Represents a 'referenced' event on a given `ReferencedSubject`. - """ - REFERENCED_EVENT - - """ - Represents a 'removed_from_project' event on a given issue or pull request. - """ - REMOVED_FROM_PROJECT_EVENT - - """ - Represents a 'renamed' event on a given issue or pull request - """ - RENAMED_TITLE_EVENT - - """ - Represents a 'reopened' event on any `Closable`. - """ - REOPENED_EVENT - - """ - Represents a 'subscribed' event on a given `Subscribable`. - """ - SUBSCRIBED_EVENT - - """ - Represents a 'transferred' event on a given issue or pull request. - """ - TRANSFERRED_EVENT - - """ - Represents an 'unassigned' event on any assignable object. - """ - UNASSIGNED_EVENT - - """ - Represents an 'unlabeled' event on a given issue or pull request. - """ - UNLABELED_EVENT - - """ - Represents an 'unlocked' event on a given issue or pull request. - """ - UNLOCKED_EVENT - - """ - Represents an 'unmarked_as_duplicate' event on a given issue or pull request. - """ - UNMARKED_AS_DUPLICATE_EVENT - - """ - Represents an 'unpinned' event on a given issue or pull request. - """ - UNPINNED_EVENT - - """ - Represents an 'unsubscribed' event on a given `Subscribable`. - """ - UNSUBSCRIBED_EVENT - - """ - Represents a 'user_blocked' event on a given user. - """ - USER_BLOCKED_EVENT -} - -""" -Represents a user signing up for a GitHub account. -""" -type JoinedGitHubContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -A label for categorizing Issues or Milestones with a given Repository. -""" -type Label implements Node { - """ - Identifies the label color. - """ - color: String! - - """ - Identifies the date and time when the label was created. - """ - createdAt: DateTime - - """ - A brief description of this label. - """ - description: String - id: ID! - - """ - Indicates whether or not this is a default label. - """ - isDefault: Boolean! - - """ - A list of issues associated with this label. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Identifies the label name. - """ - name: String! - - """ - A list of pull requests associated with this label. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - The repository associated with this label. - """ - repository: Repository! - - """ - The HTTP path for this label. - """ - resourcePath: URI! - - """ - Identifies the date and time when the label was last updated. - """ - updatedAt: DateTime - - """ - The HTTP URL for this label. - """ - url: URI! -} - -""" -The connection type for Label. -""" -type LabelConnection { - """ - A list of edges. - """ - edges: [LabelEdge] - - """ - A list of nodes. - """ - nodes: [Label] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type LabelEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Label -} - -""" -Ways in which lists of labels can be ordered upon return. -""" -input LabelOrder { - """ - The direction in which to order labels by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order labels by. - """ - field: LabelOrderField! -} - -""" -Properties by which label connections can be ordered. -""" -enum LabelOrderField { - """ - Order labels by creation time - """ - CREATED_AT - - """ - Order labels by name - """ - NAME -} - -""" -An object that can have labels assigned to it. -""" -interface Labelable { - """ - A list of labels associated with the object. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for labels returned from the connection. - """ - orderBy: LabelOrder = {field: CREATED_AT, direction: ASC} - ): LabelConnection -} - -""" -Represents a 'labeled' event on a given issue or pull request. -""" -type LabeledEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the label associated with the 'labeled' event. - """ - label: Label! - - """ - Identifies the `Labelable` associated with the event. - """ - labelable: Labelable! -} - -""" -Represents a given language found in repositories. -""" -type Language implements Node { - """ - The color defined for the current language. - """ - color: String - id: ID! - - """ - The name of the current language. - """ - name: String! -} - -""" -A list of languages associated with the parent. -""" -type LanguageConnection { - """ - A list of edges. - """ - edges: [LanguageEdge] - - """ - A list of nodes. - """ - nodes: [Language] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - The total size in bytes of files written in that language. - """ - totalSize: Int! -} - -""" -Represents the language of a repository. -""" -type LanguageEdge { - cursor: String! - node: Language! - - """ - The number of bytes of code written in the language. - """ - size: Int! -} - -""" -Ordering options for language connections. -""" -input LanguageOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order languages by. - """ - field: LanguageOrderField! -} - -""" -Properties by which language connections can be ordered. -""" -enum LanguageOrderField { - """ - Order languages by the size of all files containing the language - """ - SIZE -} - -""" -A repository's open source license -""" -type License implements Node { - """ - The full text of the license - """ - body: String! - - """ - The conditions set by the license - """ - conditions: [LicenseRule]! - - """ - A human-readable description of the license - """ - description: String - - """ - Whether the license should be featured - """ - featured: Boolean! - - """ - Whether the license should be displayed in license pickers - """ - hidden: Boolean! - id: ID! - - """ - Instructions on how to implement the license - """ - implementation: String - - """ - The lowercased SPDX ID of the license - """ - key: String! - - """ - The limitations set by the license - """ - limitations: [LicenseRule]! - - """ - The license full name specified by - """ - name: String! - - """ - Customary short name if applicable (e.g, GPLv3) - """ - nickname: String - - """ - The permissions set by the license - """ - permissions: [LicenseRule]! - - """ - Whether the license is a pseudo-license placeholder (e.g., other, no-license) - """ - pseudoLicense: Boolean! - - """ - Short identifier specified by - """ - spdxId: String - - """ - URL to the license on - """ - url: URI -} - -""" -Describes a License's conditions, permissions, and limitations -""" -type LicenseRule { - """ - A description of the rule - """ - description: String! - - """ - The machine-readable rule key - """ - key: String! - - """ - The human-readable rule label - """ - label: String! -} - -""" -Autogenerated input type of LinkRepositoryToProject -""" -input LinkRepositoryToProjectInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Project to link to a Repository - """ - projectId: ID! @possibleTypes(concreteTypes: ["Project"]) - - """ - The ID of the Repository to link to a Project. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of LinkRepositoryToProject -""" -type LinkRepositoryToProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The linked Project. - """ - project: Project - - """ - The linked Repository. - """ - repository: Repository -} - -""" -Autogenerated input type of LockLockable -""" -input LockLockableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A reason for why the issue or pull request will be locked. - """ - lockReason: LockReason - - """ - ID of the issue or pull request to be locked. - """ - lockableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Lockable") -} - -""" -Autogenerated return type of LockLockable -""" -type LockLockablePayload { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was locked. - """ - lockedRecord: Lockable -} - -""" -The possible reasons that an issue or pull request was locked. -""" -enum LockReason { - """ - The issue or pull request was locked because the conversation was off-topic. - """ - OFF_TOPIC - - """ - The issue or pull request was locked because the conversation was resolved. - """ - RESOLVED - - """ - The issue or pull request was locked because the conversation was spam. - """ - SPAM - - """ - The issue or pull request was locked because the conversation was too heated. - """ - TOO_HEATED -} - -""" -An object that can be locked. -""" -interface Lockable { - """ - Reason that the conversation was locked. - """ - activeLockReason: LockReason - - """ - `true` if the object is locked - """ - locked: Boolean! -} - -""" -Represents a 'locked' event on a given issue or pull request. -""" -type LockedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reason that the conversation was locked (optional). - """ - lockReason: LockReason - - """ - Object that was locked. - """ - lockable: Lockable! -} - -""" -A placeholder user for attribution of imported data on GitHub. -""" -type Mannequin implements Actor & Node & UniformResourceLocatable { - """ - A URL pointing to the GitHub App's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The mannequin's email on the source instance. - """ - email: String - id: ID! - - """ - The username of the actor. - """ - login: String! - - """ - The HTML path to this resource. - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The URL to this resource. - """ - url: URI! -} - -""" -Autogenerated input type of MarkPullRequestReadyForReview -""" -input MarkPullRequestReadyForReviewInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the pull request to be marked as ready for review. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) -} - -""" -Autogenerated return type of MarkPullRequestReadyForReview -""" -type MarkPullRequestReadyForReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that is ready for review. - """ - pullRequest: PullRequest -} - -""" -Represents a 'marked_as_duplicate' event on a given issue or pull request. -""" -type MarkedAsDuplicateEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! -} - -""" -A public description of a Marketplace category. -""" -type MarketplaceCategory implements Node { - """ - The category's description. - """ - description: String - - """ - The technical description of how apps listed in this category work with GitHub. - """ - howItWorks: String - id: ID! - - """ - The category's name. - """ - name: String! - - """ - How many Marketplace listings have this as their primary category. - """ - primaryListingCount: Int! - - """ - The HTTP path for this Marketplace category. - """ - resourcePath: URI! - - """ - How many Marketplace listings have this as their secondary category. - """ - secondaryListingCount: Int! - - """ - The short name of the category used in its URL. - """ - slug: String! - - """ - The HTTP URL for this Marketplace category. - """ - url: URI! -} - -""" -A listing in the GitHub integration marketplace. -""" -type MarketplaceListing implements Node { - """ - The GitHub App this listing represents. - """ - app: App - - """ - URL to the listing owner's company site. - """ - companyUrl: URI - - """ - The HTTP path for configuring access to the listing's integration or OAuth app - """ - configurationResourcePath: URI! - - """ - The HTTP URL for configuring access to the listing's integration or OAuth app - """ - configurationUrl: URI! - - """ - URL to the listing's documentation. - """ - documentationUrl: URI - - """ - The listing's detailed description. - """ - extendedDescription: String - - """ - The listing's detailed description rendered to HTML. - """ - extendedDescriptionHTML: HTML! - - """ - The listing's introductory description. - """ - fullDescription: String! - - """ - The listing's introductory description rendered to HTML. - """ - fullDescriptionHTML: HTML! - - """ - Does this listing have any plans with a free trial? - """ - hasPublishedFreeTrialPlans: Boolean! - - """ - Does this listing have a terms of service link? - """ - hasTermsOfService: Boolean! - - """ - A technical description of how this app works with GitHub. - """ - howItWorks: String - - """ - The listing's technical description rendered to HTML. - """ - howItWorksHTML: HTML! - id: ID! - - """ - URL to install the product to the viewer's account or organization. - """ - installationUrl: URI - - """ - Whether this listing's app has been installed for the current viewer - """ - installedForViewer: Boolean! - - """ - Whether this listing has been removed from the Marketplace. - """ - isArchived: Boolean! - - """ - Whether this listing is still an editable draft that has not been submitted - for review and is not publicly visible in the Marketplace. - """ - isDraft: Boolean! - - """ - Whether the product this listing represents is available as part of a paid plan. - """ - isPaid: Boolean! - - """ - Whether this listing has been approved for display in the Marketplace. - """ - isPublic: Boolean! - - """ - Whether this listing has been rejected by GitHub for display in the Marketplace. - """ - isRejected: Boolean! - - """ - Whether this listing has been approved for unverified display in the Marketplace. - """ - isUnverified: Boolean! - - """ - Whether this draft listing has been submitted for review for approval to be unverified in the Marketplace. - """ - isUnverifiedPending: Boolean! - - """ - Whether this draft listing has been submitted for review from GitHub for approval to be verified in the Marketplace. - """ - isVerificationPendingFromDraft: Boolean! - - """ - Whether this unverified listing has been submitted for review from GitHub for approval to be verified in the Marketplace. - """ - isVerificationPendingFromUnverified: Boolean! - - """ - Whether this listing has been approved for verified display in the Marketplace. - """ - isVerified: Boolean! - - """ - The hex color code, without the leading '#', for the logo background. - """ - logoBackgroundColor: String! - - """ - URL for the listing's logo image. - """ - logoUrl( - """ - The size in pixels of the resulting square image. - """ - size: Int = 400 - ): URI - - """ - The listing's full name. - """ - name: String! - - """ - The listing's very short description without a trailing period or ampersands. - """ - normalizedShortDescription: String! - - """ - URL to the listing's detailed pricing. - """ - pricingUrl: URI - - """ - The category that best describes the listing. - """ - primaryCategory: MarketplaceCategory! - - """ - URL to the listing's privacy policy, may return an empty string for listings that do not require a privacy policy URL. - """ - privacyPolicyUrl: URI! - - """ - The HTTP path for the Marketplace listing. - """ - resourcePath: URI! - - """ - The URLs for the listing's screenshots. - """ - screenshotUrls: [String]! - - """ - An alternate category that describes the listing. - """ - secondaryCategory: MarketplaceCategory - - """ - The listing's very short description. - """ - shortDescription: String! - - """ - The short name of the listing used in its URL. - """ - slug: String! - - """ - URL to the listing's status page. - """ - statusUrl: URI - - """ - An email address for support for this listing's app. - """ - supportEmail: String - - """ - Either a URL or an email address for support for this listing's app, may - return an empty string for listings that do not require a support URL. - """ - supportUrl: URI! - - """ - URL to the listing's terms of service. - """ - termsOfServiceUrl: URI - - """ - The HTTP URL for the Marketplace listing. - """ - url: URI! - - """ - Can the current viewer add plans for this Marketplace listing. - """ - viewerCanAddPlans: Boolean! - - """ - Can the current viewer approve this Marketplace listing. - """ - viewerCanApprove: Boolean! - - """ - Can the current viewer delist this Marketplace listing. - """ - viewerCanDelist: Boolean! - - """ - Can the current viewer edit this Marketplace listing. - """ - viewerCanEdit: Boolean! - - """ - Can the current viewer edit the primary and secondary category of this - Marketplace listing. - """ - viewerCanEditCategories: Boolean! - - """ - Can the current viewer edit the plans for this Marketplace listing. - """ - viewerCanEditPlans: Boolean! - - """ - Can the current viewer return this Marketplace listing to draft state - so it becomes editable again. - """ - viewerCanRedraft: Boolean! - - """ - Can the current viewer reject this Marketplace listing by returning it to - an editable draft state or rejecting it entirely. - """ - viewerCanReject: Boolean! - - """ - Can the current viewer request this listing be reviewed for display in - the Marketplace as verified. - """ - viewerCanRequestApproval: Boolean! - - """ - Indicates whether the current user has an active subscription to this Marketplace listing. - """ - viewerHasPurchased: Boolean! - - """ - Indicates if the current user has purchased a subscription to this Marketplace listing - for all of the organizations the user owns. - """ - viewerHasPurchasedForAllOrganizations: Boolean! - - """ - Does the current viewer role allow them to administer this Marketplace listing. - """ - viewerIsListingAdmin: Boolean! -} - -""" -Look up Marketplace Listings -""" -type MarketplaceListingConnection { - """ - A list of edges. - """ - edges: [MarketplaceListingEdge] - - """ - A list of nodes. - """ - nodes: [MarketplaceListing] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type MarketplaceListingEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: MarketplaceListing -} - -""" -Entities that have members who can set status messages. -""" -interface MemberStatusable { - """ - Get the status messages members of this entity have set that are either public or visible only to the organization. - """ - memberStatuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for user statuses returned from the connection. - """ - orderBy: UserStatusOrder = {field: UPDATED_AT, direction: DESC} - ): UserStatusConnection! -} - -""" -Audit log entry for a members_can_delete_repos.clear event. -""" -type MembersCanDeleteReposClearAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a members_can_delete_repos.disable event. -""" -type MembersCanDeleteReposDisableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a members_can_delete_repos.enable event. -""" -type MembersCanDeleteReposEnableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Represents a 'mentioned' event on a given issue or pull request. -""" -type MentionedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Autogenerated input type of MergeBranch -""" -input MergeBranchInput { - """ - The name of the base branch that the provided head will be merged into. - """ - base: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Message to use for the merge commit. If omitted, a default will be used. - """ - commitMessage: String - - """ - The head to merge into the base branch. This can be a branch name or a commit GitObjectID. - """ - head: String! - - """ - The Node ID of the Repository containing the base branch that will be modified. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of MergeBranch -""" -type MergeBranchPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The resulting merge Commit. - """ - mergeCommit: Commit -} - -""" -Autogenerated input type of MergePullRequest -""" -input MergePullRequestInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Commit body to use for the merge commit; if omitted, a default message will be used - """ - commitBody: String - - """ - Commit headline to use for the merge commit; if omitted, a default message will be used. - """ - commitHeadline: String - - """ - OID that the pull request head ref must match to allow merge; if omitted, no check is performed. - """ - expectedHeadOid: GitObjectID - - """ - The merge method to use. If omitted, defaults to 'MERGE' - """ - mergeMethod: PullRequestMergeMethod = MERGE - - """ - ID of the pull request to be merged. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) -} - -""" -Autogenerated return type of MergePullRequest -""" -type MergePullRequestPayload { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that was merged. - """ - pullRequest: PullRequest -} - -""" -Detailed status information about a pull request merge. -""" -enum MergeStateStatus { - """ - The head ref is out of date. - """ - BEHIND - - """ - The merge is blocked. - """ - BLOCKED - - """ - Mergeable and passing commit status. - """ - CLEAN - - """ - The merge commit cannot be cleanly created. - """ - DIRTY - - """ - The merge is blocked due to the pull request being a draft. - """ - DRAFT - - """ - Mergeable with passing commit status and pre-receive hooks. - """ - HAS_HOOKS - - """ - The state cannot currently be determined. - """ - UNKNOWN - - """ - Mergeable with non-passing commit status. - """ - UNSTABLE -} - -""" -Whether or not a PullRequest can be merged. -""" -enum MergeableState { - """ - The pull request cannot be merged due to merge conflicts. - """ - CONFLICTING - - """ - The pull request can be merged. - """ - MERGEABLE - - """ - The mergeability of the pull request is still being calculated. - """ - UNKNOWN -} - -""" -Represents a 'merged' event on a given pull request. -""" -type MergedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the commit associated with the `merge` event. - """ - commit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the Ref associated with the `merge` event. - """ - mergeRef: Ref - - """ - Identifies the name of the Ref associated with the `merge` event. - """ - mergeRefName: String! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this merged event. - """ - resourcePath: URI! - - """ - The HTTP URL for this merged event. - """ - url: URI! -} - -""" -Represents a Milestone object on a given repository. -""" -type Milestone implements Closable & Node & UniformResourceLocatable { - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the actor who created the milestone. - """ - creator: Actor - - """ - Identifies the description of the milestone. - """ - description: String - - """ - Identifies the due date of the milestone. - """ - dueOn: DateTime - id: ID! - - """ - Just for debugging on review-lab - """ - issuePrioritiesDebug: String! - - """ - A list of issues associated with the milestone. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Identifies the number of the milestone. - """ - number: Int! - - """ - A list of pull requests associated with the milestone. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - The repository associated with this milestone. - """ - repository: Repository! - - """ - The HTTP path for this milestone - """ - resourcePath: URI! - - """ - Identifies the state of the milestone. - """ - state: MilestoneState! - - """ - Identifies the title of the milestone. - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this milestone - """ - url: URI! -} - -""" -The connection type for Milestone. -""" -type MilestoneConnection { - """ - A list of edges. - """ - edges: [MilestoneEdge] - - """ - A list of nodes. - """ - nodes: [Milestone] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type MilestoneEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Milestone -} - -""" -Types that can be inside a Milestone. -""" -union MilestoneItem = Issue | PullRequest - -""" -Ordering options for milestone connections. -""" -input MilestoneOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order milestones by. - """ - field: MilestoneOrderField! -} - -""" -Properties by which milestone connections can be ordered. -""" -enum MilestoneOrderField { - """ - Order milestones by when they were created. - """ - CREATED_AT - - """ - Order milestones by when they are due. - """ - DUE_DATE - - """ - Order milestones by their number. - """ - NUMBER - - """ - Order milestones by when they were last updated. - """ - UPDATED_AT -} - -""" -The possible states of a milestone. -""" -enum MilestoneState { - """ - A milestone that has been closed. - """ - CLOSED - - """ - A milestone that is still open. - """ - OPEN -} - -""" -Represents a 'milestoned' event on a given issue or pull request. -""" -type MilestonedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the milestone title associated with the 'milestoned' event. - """ - milestoneTitle: String! - - """ - Object referenced by event. - """ - subject: MilestoneItem! -} - -""" -Entities that can be minimized. -""" -interface Minimizable { - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! -} - -""" -Autogenerated input type of MinimizeComment -""" -input MinimizeCommentInput { - """ - The classification of comment - """ - classifier: ReportedContentClassifiers! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! @possibleTypes(concreteTypes: ["CommitComment", "GistComment", "IssueComment", "PullRequestReviewComment"], abstractType: "Minimizable") -} - -""" -Autogenerated return type of MinimizeComment -""" -type MinimizeCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The comment that was minimized. - """ - minimizedComment: Minimizable -} - -""" -Autogenerated input type of MoveProjectCard -""" -input MoveProjectCardInput { - """ - Place the new card after the card with this id. Pass null to place it at the top. - """ - afterCardId: ID @possibleTypes(concreteTypes: ["ProjectCard"]) - - """ - The id of the card to move. - """ - cardId: ID! @possibleTypes(concreteTypes: ["ProjectCard"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the column to move it into. - """ - columnId: ID! @possibleTypes(concreteTypes: ["ProjectColumn"]) -} - -""" -Autogenerated return type of MoveProjectCard -""" -type MoveProjectCardPayload { - """ - The new edge of the moved card. - """ - cardEdge: ProjectCardEdge - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of MoveProjectColumn -""" -input MoveProjectColumnInput { - """ - Place the new column after the column with this id. Pass null to place it at the front. - """ - afterColumnId: ID @possibleTypes(concreteTypes: ["ProjectColumn"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the column to move. - """ - columnId: ID! @possibleTypes(concreteTypes: ["ProjectColumn"]) -} - -""" -Autogenerated return type of MoveProjectColumn -""" -type MoveProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new edge of the moved column. - """ - columnEdge: ProjectColumnEdge -} - -""" -Represents a 'moved_columns_in_project' event on a given issue or pull request. -""" -type MovedColumnsInProjectEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Column name the issue or pull request was moved from. - """ - previousProjectColumnName: String! @preview(toggledBy: "starfox-preview") - - """ - Project referenced by event. - """ - project: Project @preview(toggledBy: "starfox-preview") - - """ - Project card referenced by this project event. - """ - projectCard: ProjectCard @preview(toggledBy: "starfox-preview") - - """ - Column name the issue or pull request was moved to. - """ - projectColumnName: String! @preview(toggledBy: "starfox-preview") -} - -""" -The root query for implementing GraphQL mutations. -""" -type Mutation { - """ - Accepts a pending invitation for a user to become an administrator of an enterprise. - """ - acceptEnterpriseAdministratorInvitation(input: AcceptEnterpriseAdministratorInvitationInput!): AcceptEnterpriseAdministratorInvitationPayload - - """ - Applies a suggested topic to the repository. - """ - acceptTopicSuggestion(input: AcceptTopicSuggestionInput!): AcceptTopicSuggestionPayload - - """ - Adds assignees to an assignable object. - """ - addAssigneesToAssignable(input: AddAssigneesToAssignableInput!): AddAssigneesToAssignablePayload - - """ - Adds a comment to an Issue or Pull Request. - """ - addComment(input: AddCommentInput!): AddCommentPayload - - """ - Adds labels to a labelable object. - """ - addLabelsToLabelable(input: AddLabelsToLabelableInput!): AddLabelsToLabelablePayload - - """ - Adds a card to a ProjectColumn. Either `contentId` or `note` must be provided but **not** both. - """ - addProjectCard(input: AddProjectCardInput!): AddProjectCardPayload - - """ - Adds a column to a Project. - """ - addProjectColumn(input: AddProjectColumnInput!): AddProjectColumnPayload - - """ - Adds a review to a Pull Request. - """ - addPullRequestReview(input: AddPullRequestReviewInput!): AddPullRequestReviewPayload - - """ - Adds a comment to a review. - """ - addPullRequestReviewComment(input: AddPullRequestReviewCommentInput!): AddPullRequestReviewCommentPayload - - """ - Adds a new thread to a pending Pull Request Review. - """ - addPullRequestReviewThread(input: AddPullRequestReviewThreadInput!): AddPullRequestReviewThreadPayload - - """ - Adds a reaction to a subject. - """ - addReaction(input: AddReactionInput!): AddReactionPayload - - """ - Adds a star to a Starrable. - """ - addStar(input: AddStarInput!): AddStarPayload - - """ - Marks a repository as archived. - """ - archiveRepository(input: ArchiveRepositoryInput!): ArchiveRepositoryPayload - - """ - Cancels a pending invitation for an administrator to join an enterprise. - """ - cancelEnterpriseAdminInvitation(input: CancelEnterpriseAdminInvitationInput!): CancelEnterpriseAdminInvitationPayload - - """ - Update your status on GitHub. - """ - changeUserStatus(input: ChangeUserStatusInput!): ChangeUserStatusPayload - - """ - Clears all labels from a labelable object. - """ - clearLabelsFromLabelable(input: ClearLabelsFromLabelableInput!): ClearLabelsFromLabelablePayload - - """ - Creates a new project by cloning configuration from an existing project. - """ - cloneProject(input: CloneProjectInput!): CloneProjectPayload - - """ - Create a new repository with the same files and directory structure as a template repository. - """ - cloneTemplateRepository(input: CloneTemplateRepositoryInput!): CloneTemplateRepositoryPayload - - """ - Close an issue. - """ - closeIssue(input: CloseIssueInput!): CloseIssuePayload - - """ - Close a pull request. - """ - closePullRequest(input: ClosePullRequestInput!): ClosePullRequestPayload - - """ - Convert a project note card to one associated with a newly created issue. - """ - convertProjectCardNoteToIssue(input: ConvertProjectCardNoteToIssueInput!): ConvertProjectCardNoteToIssuePayload - - """ - Create a new branch protection rule - """ - createBranchProtectionRule(input: CreateBranchProtectionRuleInput!): CreateBranchProtectionRulePayload - - """ - Create a check run. - """ - createCheckRun(input: CreateCheckRunInput!): CreateCheckRunPayload @preview(toggledBy: "antiope-preview") - - """ - Create a check suite - """ - createCheckSuite(input: CreateCheckSuiteInput!): CreateCheckSuitePayload @preview(toggledBy: "antiope-preview") - - """ - Create a content attachment. - """ - createContentAttachment(input: CreateContentAttachmentInput!): CreateContentAttachmentPayload @preview(toggledBy: "corsair-preview") - - """ - Creates a new deployment event. - """ - createDeployment(input: CreateDeploymentInput!): CreateDeploymentPayload @preview(toggledBy: "flash-preview") - - """ - Create a deployment status. - """ - createDeploymentStatus(input: CreateDeploymentStatusInput!): CreateDeploymentStatusPayload @preview(toggledBy: "flash-preview") - - """ - Creates an organization as part of an enterprise account. - """ - createEnterpriseOrganization(input: CreateEnterpriseOrganizationInput!): CreateEnterpriseOrganizationPayload - - """ - Creates a new IP allow list entry. - """ - createIpAllowListEntry(input: CreateIpAllowListEntryInput!): CreateIpAllowListEntryPayload - - """ - Creates a new issue. - """ - createIssue(input: CreateIssueInput!): CreateIssuePayload - - """ - Creates a new label. - """ - createLabel(input: CreateLabelInput!): CreateLabelPayload @preview(toggledBy: "bane-preview") - - """ - Creates a new project. - """ - createProject(input: CreateProjectInput!): CreateProjectPayload - - """ - Create a new pull request - """ - createPullRequest(input: CreatePullRequestInput!): CreatePullRequestPayload - - """ - Create a new Git Ref. - """ - createRef(input: CreateRefInput!): CreateRefPayload - - """ - Create a new repository. - """ - createRepository(input: CreateRepositoryInput!): CreateRepositoryPayload - - """ - Creates a new team discussion. - """ - createTeamDiscussion(input: CreateTeamDiscussionInput!): CreateTeamDiscussionPayload - - """ - Creates a new team discussion comment. - """ - createTeamDiscussionComment(input: CreateTeamDiscussionCommentInput!): CreateTeamDiscussionCommentPayload - - """ - Rejects a suggested topic for the repository. - """ - declineTopicSuggestion(input: DeclineTopicSuggestionInput!): DeclineTopicSuggestionPayload - - """ - Delete a branch protection rule - """ - deleteBranchProtectionRule(input: DeleteBranchProtectionRuleInput!): DeleteBranchProtectionRulePayload - - """ - Deletes a deployment. - """ - deleteDeployment(input: DeleteDeploymentInput!): DeleteDeploymentPayload - - """ - Deletes an IP allow list entry. - """ - deleteIpAllowListEntry(input: DeleteIpAllowListEntryInput!): DeleteIpAllowListEntryPayload - - """ - Deletes an Issue object. - """ - deleteIssue(input: DeleteIssueInput!): DeleteIssuePayload - - """ - Deletes an IssueComment object. - """ - deleteIssueComment(input: DeleteIssueCommentInput!): DeleteIssueCommentPayload - - """ - Deletes a label. - """ - deleteLabel(input: DeleteLabelInput!): DeleteLabelPayload @preview(toggledBy: "bane-preview") - - """ - Delete a package version. - """ - deletePackageVersion(input: DeletePackageVersionInput!): DeletePackageVersionPayload @preview(toggledBy: "package-deletes-preview") - - """ - Deletes a project. - """ - deleteProject(input: DeleteProjectInput!): DeleteProjectPayload - - """ - Deletes a project card. - """ - deleteProjectCard(input: DeleteProjectCardInput!): DeleteProjectCardPayload - - """ - Deletes a project column. - """ - deleteProjectColumn(input: DeleteProjectColumnInput!): DeleteProjectColumnPayload - - """ - Deletes a pull request review. - """ - deletePullRequestReview(input: DeletePullRequestReviewInput!): DeletePullRequestReviewPayload - - """ - Deletes a pull request review comment. - """ - deletePullRequestReviewComment(input: DeletePullRequestReviewCommentInput!): DeletePullRequestReviewCommentPayload - - """ - Delete a Git Ref. - """ - deleteRef(input: DeleteRefInput!): DeleteRefPayload - - """ - Deletes a team discussion. - """ - deleteTeamDiscussion(input: DeleteTeamDiscussionInput!): DeleteTeamDiscussionPayload - - """ - Deletes a team discussion comment. - """ - deleteTeamDiscussionComment(input: DeleteTeamDiscussionCommentInput!): DeleteTeamDiscussionCommentPayload - - """ - Dismisses an approved or rejected pull request review. - """ - dismissPullRequestReview(input: DismissPullRequestReviewInput!): DismissPullRequestReviewPayload - - """ - Follow a user. - """ - followUser(input: FollowUserInput!): FollowUserPayload - - """ - Creates a new project by importing columns and a list of issues/PRs. - """ - importProject(input: ImportProjectInput!): ImportProjectPayload @preview(toggledBy: "slothette-preview") - - """ - Invite someone to become an administrator of the enterprise. - """ - inviteEnterpriseAdmin(input: InviteEnterpriseAdminInput!): InviteEnterpriseAdminPayload - - """ - Creates a repository link for a project. - """ - linkRepositoryToProject(input: LinkRepositoryToProjectInput!): LinkRepositoryToProjectPayload - - """ - Lock a lockable object - """ - lockLockable(input: LockLockableInput!): LockLockablePayload - - """ - Marks a pull request ready for review. - """ - markPullRequestReadyForReview(input: MarkPullRequestReadyForReviewInput!): MarkPullRequestReadyForReviewPayload - - """ - Merge a head into a branch. - """ - mergeBranch(input: MergeBranchInput!): MergeBranchPayload - - """ - Merge a pull request. - """ - mergePullRequest(input: MergePullRequestInput!): MergePullRequestPayload - - """ - Minimizes a comment on an Issue, Commit, Pull Request, or Gist - """ - minimizeComment(input: MinimizeCommentInput!): MinimizeCommentPayload - - """ - Moves a project card to another place. - """ - moveProjectCard(input: MoveProjectCardInput!): MoveProjectCardPayload - - """ - Moves a project column to another place. - """ - moveProjectColumn(input: MoveProjectColumnInput!): MoveProjectColumnPayload - - """ - Pin an issue to a repository - """ - pinIssue(input: PinIssueInput!): PinIssuePayload @preview(toggledBy: "elektra-preview") - - """ - Regenerates the identity provider recovery codes for an enterprise - """ - regenerateEnterpriseIdentityProviderRecoveryCodes(input: RegenerateEnterpriseIdentityProviderRecoveryCodesInput!): RegenerateEnterpriseIdentityProviderRecoveryCodesPayload - - """ - Removes assignees from an assignable object. - """ - removeAssigneesFromAssignable(input: RemoveAssigneesFromAssignableInput!): RemoveAssigneesFromAssignablePayload - - """ - Removes an administrator from the enterprise. - """ - removeEnterpriseAdmin(input: RemoveEnterpriseAdminInput!): RemoveEnterpriseAdminPayload - - """ - Removes the identity provider from an enterprise - """ - removeEnterpriseIdentityProvider(input: RemoveEnterpriseIdentityProviderInput!): RemoveEnterpriseIdentityProviderPayload - - """ - Removes an organization from the enterprise - """ - removeEnterpriseOrganization(input: RemoveEnterpriseOrganizationInput!): RemoveEnterpriseOrganizationPayload - - """ - Removes labels from a Labelable object. - """ - removeLabelsFromLabelable(input: RemoveLabelsFromLabelableInput!): RemoveLabelsFromLabelablePayload - - """ - Removes outside collaborator from all repositories in an organization. - """ - removeOutsideCollaborator(input: RemoveOutsideCollaboratorInput!): RemoveOutsideCollaboratorPayload - - """ - Removes a reaction from a subject. - """ - removeReaction(input: RemoveReactionInput!): RemoveReactionPayload - - """ - Removes a star from a Starrable. - """ - removeStar(input: RemoveStarInput!): RemoveStarPayload - - """ - Reopen a issue. - """ - reopenIssue(input: ReopenIssueInput!): ReopenIssuePayload - - """ - Reopen a pull request. - """ - reopenPullRequest(input: ReopenPullRequestInput!): ReopenPullRequestPayload - - """ - Set review requests on a pull request. - """ - requestReviews(input: RequestReviewsInput!): RequestReviewsPayload - - """ - Rerequests an existing check suite. - """ - rerequestCheckSuite(input: RerequestCheckSuiteInput!): RerequestCheckSuitePayload @preview(toggledBy: "antiope-preview") - - """ - Marks a review thread as resolved. - """ - resolveReviewThread(input: ResolveReviewThreadInput!): ResolveReviewThreadPayload - - """ - Creates or updates the identity provider for an enterprise. - """ - setEnterpriseIdentityProvider(input: SetEnterpriseIdentityProviderInput!): SetEnterpriseIdentityProviderPayload - - """ - Submits a pending pull request review. - """ - submitPullRequestReview(input: SubmitPullRequestReviewInput!): SubmitPullRequestReviewPayload - - """ - Transfer an issue to a different repository - """ - transferIssue(input: TransferIssueInput!): TransferIssuePayload - - """ - Unarchives a repository. - """ - unarchiveRepository(input: UnarchiveRepositoryInput!): UnarchiveRepositoryPayload - - """ - Unfollow a user. - """ - unfollowUser(input: UnfollowUserInput!): UnfollowUserPayload - - """ - Deletes a repository link from a project. - """ - unlinkRepositoryFromProject(input: UnlinkRepositoryFromProjectInput!): UnlinkRepositoryFromProjectPayload - - """ - Unlock a lockable object - """ - unlockLockable(input: UnlockLockableInput!): UnlockLockablePayload - - """ - Unmark an issue as a duplicate of another issue. - """ - unmarkIssueAsDuplicate(input: UnmarkIssueAsDuplicateInput!): UnmarkIssueAsDuplicatePayload - - """ - Unminimizes a comment on an Issue, Commit, Pull Request, or Gist - """ - unminimizeComment(input: UnminimizeCommentInput!): UnminimizeCommentPayload - - """ - Unpin a pinned issue from a repository - """ - unpinIssue(input: UnpinIssueInput!): UnpinIssuePayload @preview(toggledBy: "elektra-preview") - - """ - Marks a review thread as unresolved. - """ - unresolveReviewThread(input: UnresolveReviewThreadInput!): UnresolveReviewThreadPayload - - """ - Create a new branch protection rule - """ - updateBranchProtectionRule(input: UpdateBranchProtectionRuleInput!): UpdateBranchProtectionRulePayload - - """ - Update a check run - """ - updateCheckRun(input: UpdateCheckRunInput!): UpdateCheckRunPayload @preview(toggledBy: "antiope-preview") - - """ - Modifies the settings of an existing check suite - """ - updateCheckSuitePreferences(input: UpdateCheckSuitePreferencesInput!): UpdateCheckSuitePreferencesPayload @preview(toggledBy: "antiope-preview") - - """ - Sets the action execution capability setting for an enterprise. - """ - updateEnterpriseActionExecutionCapabilitySetting(input: UpdateEnterpriseActionExecutionCapabilitySettingInput!): UpdateEnterpriseActionExecutionCapabilitySettingPayload - - """ - Updates the role of an enterprise administrator. - """ - updateEnterpriseAdministratorRole(input: UpdateEnterpriseAdministratorRoleInput!): UpdateEnterpriseAdministratorRolePayload - - """ - Sets whether private repository forks are enabled for an enterprise. - """ - updateEnterpriseAllowPrivateRepositoryForkingSetting(input: UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput!): UpdateEnterpriseAllowPrivateRepositoryForkingSettingPayload - - """ - Sets the default repository permission for organizations in an enterprise. - """ - updateEnterpriseDefaultRepositoryPermissionSetting(input: UpdateEnterpriseDefaultRepositoryPermissionSettingInput!): UpdateEnterpriseDefaultRepositoryPermissionSettingPayload - - """ - Sets whether organization members with admin permissions on a repository can change repository visibility. - """ - updateEnterpriseMembersCanChangeRepositoryVisibilitySetting(input: UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingInput!): UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingPayload - - """ - Sets the members can create repositories setting for an enterprise. - """ - updateEnterpriseMembersCanCreateRepositoriesSetting(input: UpdateEnterpriseMembersCanCreateRepositoriesSettingInput!): UpdateEnterpriseMembersCanCreateRepositoriesSettingPayload - - """ - Sets the members can delete issues setting for an enterprise. - """ - updateEnterpriseMembersCanDeleteIssuesSetting(input: UpdateEnterpriseMembersCanDeleteIssuesSettingInput!): UpdateEnterpriseMembersCanDeleteIssuesSettingPayload - - """ - Sets the members can delete repositories setting for an enterprise. - """ - updateEnterpriseMembersCanDeleteRepositoriesSetting(input: UpdateEnterpriseMembersCanDeleteRepositoriesSettingInput!): UpdateEnterpriseMembersCanDeleteRepositoriesSettingPayload - - """ - Sets whether members can invite collaborators are enabled for an enterprise. - """ - updateEnterpriseMembersCanInviteCollaboratorsSetting(input: UpdateEnterpriseMembersCanInviteCollaboratorsSettingInput!): UpdateEnterpriseMembersCanInviteCollaboratorsSettingPayload - - """ - Sets whether or not an organization admin can make purchases. - """ - updateEnterpriseMembersCanMakePurchasesSetting(input: UpdateEnterpriseMembersCanMakePurchasesSettingInput!): UpdateEnterpriseMembersCanMakePurchasesSettingPayload - - """ - Sets the members can update protected branches setting for an enterprise. - """ - updateEnterpriseMembersCanUpdateProtectedBranchesSetting(input: UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingInput!): UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingPayload - - """ - Sets the members can view dependency insights for an enterprise. - """ - updateEnterpriseMembersCanViewDependencyInsightsSetting(input: UpdateEnterpriseMembersCanViewDependencyInsightsSettingInput!): UpdateEnterpriseMembersCanViewDependencyInsightsSettingPayload - - """ - Sets whether organization projects are enabled for an enterprise. - """ - updateEnterpriseOrganizationProjectsSetting(input: UpdateEnterpriseOrganizationProjectsSettingInput!): UpdateEnterpriseOrganizationProjectsSettingPayload - - """ - Updates an enterprise's profile. - """ - updateEnterpriseProfile(input: UpdateEnterpriseProfileInput!): UpdateEnterpriseProfilePayload - - """ - Sets whether repository projects are enabled for a enterprise. - """ - updateEnterpriseRepositoryProjectsSetting(input: UpdateEnterpriseRepositoryProjectsSettingInput!): UpdateEnterpriseRepositoryProjectsSettingPayload - - """ - Sets whether team discussions are enabled for an enterprise. - """ - updateEnterpriseTeamDiscussionsSetting(input: UpdateEnterpriseTeamDiscussionsSettingInput!): UpdateEnterpriseTeamDiscussionsSettingPayload - - """ - Sets whether two factor authentication is required for all users in an enterprise. - """ - updateEnterpriseTwoFactorAuthenticationRequiredSetting(input: UpdateEnterpriseTwoFactorAuthenticationRequiredSettingInput!): UpdateEnterpriseTwoFactorAuthenticationRequiredSettingPayload - - """ - Sets whether an IP allow list is enabled on an owner. - """ - updateIpAllowListEnabledSetting(input: UpdateIpAllowListEnabledSettingInput!): UpdateIpAllowListEnabledSettingPayload - - """ - Updates an IP allow list entry. - """ - updateIpAllowListEntry(input: UpdateIpAllowListEntryInput!): UpdateIpAllowListEntryPayload - - """ - Updates an Issue. - """ - updateIssue(input: UpdateIssueInput!): UpdateIssuePayload - - """ - Updates an IssueComment object. - """ - updateIssueComment(input: UpdateIssueCommentInput!): UpdateIssueCommentPayload - - """ - Updates an existing label. - """ - updateLabel(input: UpdateLabelInput!): UpdateLabelPayload @preview(toggledBy: "bane-preview") - - """ - Updates an existing project. - """ - updateProject(input: UpdateProjectInput!): UpdateProjectPayload - - """ - Updates an existing project card. - """ - updateProjectCard(input: UpdateProjectCardInput!): UpdateProjectCardPayload - - """ - Updates an existing project column. - """ - updateProjectColumn(input: UpdateProjectColumnInput!): UpdateProjectColumnPayload - - """ - Update a pull request - """ - updatePullRequest(input: UpdatePullRequestInput!): UpdatePullRequestPayload - - """ - Updates the body of a pull request review. - """ - updatePullRequestReview(input: UpdatePullRequestReviewInput!): UpdatePullRequestReviewPayload - - """ - Updates a pull request review comment. - """ - updatePullRequestReviewComment(input: UpdatePullRequestReviewCommentInput!): UpdatePullRequestReviewCommentPayload - - """ - Update a Git Ref. - """ - updateRef(input: UpdateRefInput!): UpdateRefPayload - - """ - Creates, updates and/or deletes multiple refs in a repository. - - This mutation takes a list of `RefUpdate`s and performs these updates - on the repository. All updates are performed atomically, meaning that - if one of them is rejected, no other ref will be modified. - - `RefUpdate.beforeOid` specifies that the given reference needs to point - to the given value before performing any updates. A value of - `0000000000000000000000000000000000000000` can be used to verify that - the references should not exist. - - `RefUpdate.afterOid` specifies the value that the given reference - will point to after performing all updates. A value of - `0000000000000000000000000000000000000000` can be used to delete a - reference. - - If `RefUpdate.force` is set to `true`, a non-fast-forward updates - for the given reference will be allowed. - """ - updateRefs(input: UpdateRefsInput!): UpdateRefsPayload @preview(toggledBy: "update-refs-preview") - - """ - Update information about a repository. - """ - updateRepository(input: UpdateRepositoryInput!): UpdateRepositoryPayload - - """ - Updates the state for subscribable subjects. - """ - updateSubscription(input: UpdateSubscriptionInput!): UpdateSubscriptionPayload - - """ - Updates a team discussion. - """ - updateTeamDiscussion(input: UpdateTeamDiscussionInput!): UpdateTeamDiscussionPayload - - """ - Updates a discussion comment. - """ - updateTeamDiscussionComment(input: UpdateTeamDiscussionCommentInput!): UpdateTeamDiscussionCommentPayload - - """ - Updates team review assignment. - """ - updateTeamReviewAssignment(input: UpdateTeamReviewAssignmentInput!): UpdateTeamReviewAssignmentPayload @preview(toggledBy: "stone-crop-preview") - - """ - Replaces the repository's topics with the given topics. - """ - updateTopics(input: UpdateTopicsInput!): UpdateTopicsPayload -} - -""" -An object with an ID. -""" -interface Node { - """ - ID of the object. - """ - id: ID! -} - -""" -Metadata for an audit entry with action oauth_application.* -""" -interface OauthApplicationAuditEntryData { - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI -} - -""" -Audit log entry for a oauth_application.create event. -""" -type OauthApplicationCreateAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The application URL of the OAuth Application. - """ - applicationUrl: URI - - """ - The callback URL of the OAuth Application. - """ - callbackUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The rate limit of the OAuth Application. - """ - rateLimit: Int - - """ - The state of the OAuth Application. - """ - state: OauthApplicationCreateAuditEntryState - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The state of an OAuth Application when it was created. -""" -enum OauthApplicationCreateAuditEntryState { - """ - The OAuth Application was active and allowed to have OAuth Accesses. - """ - ACTIVE - - """ - The OAuth Application was in the process of being deleted. - """ - PENDING_DELETION - - """ - The OAuth Application was suspended from generating OAuth Accesses due to abuse or security concerns. - """ - SUSPENDED -} - -""" -The corresponding operation type for the action -""" -enum OperationType { - """ - An existing resource was accessed - """ - ACCESS - - """ - A resource performed an authentication event - """ - AUTHENTICATION - - """ - A new resource was created - """ - CREATE - - """ - An existing resource was modified - """ - MODIFY - - """ - An existing resource was removed - """ - REMOVE - - """ - An existing resource was restored - """ - RESTORE - - """ - An existing resource was transferred between multiple resources - """ - TRANSFER -} - -""" -Possible directions in which to order a list of items when provided an `orderBy` argument. -""" -enum OrderDirection { - """ - Specifies an ascending order for a given `orderBy` argument. - """ - ASC - - """ - Specifies a descending order for a given `orderBy` argument. - """ - DESC -} - -""" -Audit log entry for a org.add_billing_manager -""" -type OrgAddBillingManagerAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The email address used to invite a billing manager for the organization. - """ - invitationEmail: String - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.add_member -""" -type OrgAddMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The permission level of the member added to the organization. - """ - permission: OrgAddMemberAuditEntryPermission - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The permissions available to members on an Organization. -""" -enum OrgAddMemberAuditEntryPermission { - """ - Can read, clone, push, and add collaborators to repositories. - """ - ADMIN - - """ - Can read and clone repositories. - """ - READ -} - -""" -Audit log entry for a org.block_user -""" -type OrgBlockUserAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The blocked user. - """ - blockedUser: User - - """ - The username of the blocked user. - """ - blockedUserName: String - - """ - The HTTP path for the blocked user. - """ - blockedUserResourcePath: URI - - """ - The HTTP URL for the blocked user. - """ - blockedUserUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.config.disable_collaborators_only event. -""" -type OrgConfigDisableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.config.enable_collaborators_only event. -""" -type OrgConfigEnableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.create event. -""" -type OrgCreateAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The billing plan for the Organization. - """ - billingPlan: OrgCreateAuditEntryBillingPlan - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The billing plans available for organizations. -""" -enum OrgCreateAuditEntryBillingPlan { - """ - Team Plan - """ - BUSINESS - - """ - Enterprise Cloud Plan - """ - BUSINESS_PLUS - - """ - Free Plan - """ - FREE - - """ - Tiered Per Seat Plan - """ - TIERED_PER_SEAT - - """ - Legacy Unlimited Plan - """ - UNLIMITED -} - -""" -Audit log entry for a org.disable_oauth_app_restrictions event. -""" -type OrgDisableOauthAppRestrictionsAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.disable_saml event. -""" -type OrgDisableSamlAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The SAML provider's digest algorithm URL. - """ - digestMethodUrl: URI - id: ID! - - """ - The SAML provider's issuer URL. - """ - issuerUrl: URI - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The SAML provider's signature algorithm URL. - """ - signatureMethodUrl: URI - - """ - The SAML provider's single sign-on URL. - """ - singleSignOnUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.disable_two_factor_requirement event. -""" -type OrgDisableTwoFactorRequirementAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.enable_oauth_app_restrictions event. -""" -type OrgEnableOauthAppRestrictionsAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.enable_saml event. -""" -type OrgEnableSamlAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The SAML provider's digest algorithm URL. - """ - digestMethodUrl: URI - id: ID! - - """ - The SAML provider's issuer URL. - """ - issuerUrl: URI - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The SAML provider's signature algorithm URL. - """ - signatureMethodUrl: URI - - """ - The SAML provider's single sign-on URL. - """ - singleSignOnUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.enable_two_factor_requirement event. -""" -type OrgEnableTwoFactorRequirementAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.invite_member event. -""" -type OrgInviteMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The email address of the organization invitation. - """ - email: String - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The organization invitation. - """ - organizationInvitation: OrganizationInvitation - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.invite_to_business event. -""" -type OrgInviteToBusinessAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.oauth_app_access_approved event. -""" -type OrgOauthAppAccessApprovedAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.oauth_app_access_denied event. -""" -type OrgOauthAppAccessDeniedAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.oauth_app_access_requested event. -""" -type OrgOauthAppAccessRequestedAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.remove_billing_manager event. -""" -type OrgRemoveBillingManagerAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The reason for the billing manager being removed. - """ - reason: OrgRemoveBillingManagerAuditEntryReason - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The reason a billing manager was removed from an Organization. -""" -enum OrgRemoveBillingManagerAuditEntryReason { - """ - SAML external identity missing - """ - SAML_EXTERNAL_IDENTITY_MISSING - - """ - SAML SSO enforcement requires an external identity - """ - SAML_SSO_ENFORCEMENT_REQUIRES_EXTERNAL_IDENTITY - - """ - The organization required 2FA of its billing managers and this user did not have 2FA enabled. - """ - TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE -} - -""" -Audit log entry for a org.remove_member event. -""" -type OrgRemoveMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The types of membership the member has with the organization. - """ - membershipTypes: [OrgRemoveMemberAuditEntryMembershipType!] - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The reason for the member being removed. - """ - reason: OrgRemoveMemberAuditEntryReason - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The type of membership a user has with an Organization. -""" -enum OrgRemoveMemberAuditEntryMembershipType { - """ - Organization administrators have full access and can change several settings, - including the names of repositories that belong to the Organization and Owners - team membership. In addition, organization admins can delete the organization - and all of its repositories. - """ - ADMIN - - """ - A billing manager is a user who manages the billing settings for the Organization, such as updating payment information. - """ - BILLING_MANAGER - - """ - A direct member is a user that is a member of the Organization. - """ - DIRECT_MEMBER - - """ - An outside collaborator is a person who isn't explicitly a member of the - Organization, but who has Read, Write, or Admin permissions to one or more - repositories in the organization. - """ - OUTSIDE_COLLABORATOR - - """ - An unaffiliated collaborator is a person who is not a member of the - Organization and does not have access to any repositories in the Organization. - """ - UNAFFILIATED -} - -""" -The reason a member was removed from an Organization. -""" -enum OrgRemoveMemberAuditEntryReason { - """ - SAML external identity missing - """ - SAML_EXTERNAL_IDENTITY_MISSING - - """ - SAML SSO enforcement requires an external identity - """ - SAML_SSO_ENFORCEMENT_REQUIRES_EXTERNAL_IDENTITY - - """ - User was removed from organization during account recovery - """ - TWO_FACTOR_ACCOUNT_RECOVERY - - """ - The organization required 2FA of its billing managers and this user did not have 2FA enabled. - """ - TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE - - """ - User account has been deleted - """ - USER_ACCOUNT_DELETED -} - -""" -Audit log entry for a org.remove_outside_collaborator event. -""" -type OrgRemoveOutsideCollaboratorAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The types of membership the outside collaborator has with the organization. - """ - membershipTypes: [OrgRemoveOutsideCollaboratorAuditEntryMembershipType!] - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The reason for the outside collaborator being removed from the Organization. - """ - reason: OrgRemoveOutsideCollaboratorAuditEntryReason - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The type of membership a user has with an Organization. -""" -enum OrgRemoveOutsideCollaboratorAuditEntryMembershipType { - """ - A billing manager is a user who manages the billing settings for the Organization, such as updating payment information. - """ - BILLING_MANAGER - - """ - An outside collaborator is a person who isn't explicitly a member of the - Organization, but who has Read, Write, or Admin permissions to one or more - repositories in the organization. - """ - OUTSIDE_COLLABORATOR - - """ - An unaffiliated collaborator is a person who is not a member of the - Organization and does not have access to any repositories in the organization. - """ - UNAFFILIATED -} - -""" -The reason an outside collaborator was removed from an Organization. -""" -enum OrgRemoveOutsideCollaboratorAuditEntryReason { - """ - SAML external identity missing - """ - SAML_EXTERNAL_IDENTITY_MISSING - - """ - The organization required 2FA of its billing managers and this user did not have 2FA enabled. - """ - TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE -} - -""" -Audit log entry for a org.restore_member event. -""" -type OrgRestoreMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The number of custom email routings for the restored member. - """ - restoredCustomEmailRoutingsCount: Int - - """ - The number of issue assignemnts for the restored member. - """ - restoredIssueAssignmentsCount: Int - - """ - Restored organization membership objects. - """ - restoredMemberships: [OrgRestoreMemberAuditEntryMembership!] - - """ - The number of restored memberships. - """ - restoredMembershipsCount: Int - - """ - The number of repositories of the restored member. - """ - restoredRepositoriesCount: Int - - """ - The number of starred repositories for the restored member. - """ - restoredRepositoryStarsCount: Int - - """ - The number of watched repositories for the restored member. - """ - restoredRepositoryWatchesCount: Int - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Types of memberships that can be restored for an Organization member. -""" -union OrgRestoreMemberAuditEntryMembership = OrgRestoreMemberMembershipOrganizationAuditEntryData | OrgRestoreMemberMembershipRepositoryAuditEntryData | OrgRestoreMemberMembershipTeamAuditEntryData - -""" -Metadata for an organization membership for org.restore_member actions -""" -type OrgRestoreMemberMembershipOrganizationAuditEntryData implements OrganizationAuditEntryData { - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI -} - -""" -Metadata for a repository membership for org.restore_member actions -""" -type OrgRestoreMemberMembershipRepositoryAuditEntryData implements RepositoryAuditEntryData { - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI -} - -""" -Metadata for a team membership for org.restore_member actions -""" -type OrgRestoreMemberMembershipTeamAuditEntryData implements TeamAuditEntryData { - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI -} - -""" -Audit log entry for a org.unblock_user -""" -type OrgUnblockUserAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The user being unblocked by the organization. - """ - blockedUser: User - - """ - The username of the blocked user. - """ - blockedUserName: String - - """ - The HTTP path for the blocked user. - """ - blockedUserResourcePath: URI - - """ - The HTTP URL for the blocked user. - """ - blockedUserUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.update_default_repository_permission -""" -type OrgUpdateDefaultRepositoryPermissionAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The new default repository permission level for the organization. - """ - permission: OrgUpdateDefaultRepositoryPermissionAuditEntryPermission - - """ - The former default repository permission level for the organization. - """ - permissionWas: OrgUpdateDefaultRepositoryPermissionAuditEntryPermission - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The default permission a repository can have in an Organization. -""" -enum OrgUpdateDefaultRepositoryPermissionAuditEntryPermission { - """ - Can read, clone, push, and add collaborators to repositories. - """ - ADMIN - - """ - No default permission value. - """ - NONE - - """ - Can read and clone repositories. - """ - READ - - """ - Can read, clone and push to repositories. - """ - WRITE -} - -""" -Audit log entry for a org.update_member event. -""" -type OrgUpdateMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The new member permission level for the organization. - """ - permission: OrgUpdateMemberAuditEntryPermission - - """ - The former member permission level for the organization. - """ - permissionWas: OrgUpdateMemberAuditEntryPermission - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The permissions available to members on an Organization. -""" -enum OrgUpdateMemberAuditEntryPermission { - """ - Can read, clone, push, and add collaborators to repositories. - """ - ADMIN - - """ - Can read and clone repositories. - """ - READ -} - -""" -Audit log entry for a org.update_member_repository_creation_permission event. -""" -type OrgUpdateMemberRepositoryCreationPermissionAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - Can members create repositories in the organization. - """ - canCreateRepositories: Boolean - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The permission for visibility level of repositories for this organization. - """ - visibility: OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility -} - -""" -The permissions available for repository creation on an Organization. -""" -enum OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility { - """ - All organization members are restricted from creating any repositories. - """ - ALL - - """ - All organization members are restricted from creating public repositories. - """ - PUBLIC -} - -""" -Audit log entry for a org.update_member_repository_invitation_permission event. -""" -type OrgUpdateMemberRepositoryInvitationPermissionAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - Can outside collaborators be invited to repositories in the organization. - """ - canInviteOutsideCollaboratorsToRepositories: Boolean - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -An account on GitHub, with one or more owners, that has repositories, members and teams. -""" -type Organization implements Actor & MemberStatusable & Node & PackageOwner & ProfileOwner & ProjectOwner & RepositoryOwner & Sponsorable & UniformResourceLocatable { - """ - Determine if this repository owner has any items that can be pinned to their profile. - """ - anyPinnableItems( - """ - Filter to only a particular kind of pinnable item. - """ - type: PinnableItemType - ): Boolean! - - """ - Audit log entries of the organization - """ - auditLog( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned audit log entries. - """ - orderBy: AuditLogOrder = {field: CREATED_AT, direction: DESC} - - """ - The query string to filter audit entries - """ - query: String - ): OrganizationAuditEntryConnection! - - """ - A URL pointing to the organization's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The organization's public profile description. - """ - description: String - - """ - The organization's public profile description rendered to HTML. - """ - descriptionHTML: String - - """ - The organization's public email. - """ - email: String - id: ID! - - """ - The setting value for whether the organization has an IP allow list enabled. - """ - ipAllowListEnabledSetting: IpAllowListEnabledSettingValue! - - """ - The IP addresses that are allowed to access resources owned by the organization. - """ - ipAllowListEntries( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for IP allow list entries returned. - """ - orderBy: IpAllowListEntryOrder = {field: ALLOW_LIST_VALUE, direction: ASC} - ): IpAllowListEntryConnection! - - """ - Whether the organization has verified its profile email and website. - """ - isVerified: Boolean! - - """ - Showcases a selection of repositories and gists that the profile owner has - either curated or that have been selected automatically based on popularity. - """ - itemShowcase: ProfileItemShowcase! - - """ - The organization's public profile location. - """ - location: String - - """ - The organization's login name. - """ - login: String! - - """ - Get the status messages members of this entity have set that are either public or visible only to the organization. - """ - memberStatuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for user statuses returned from the connection. - """ - orderBy: UserStatusOrder = {field: UPDATED_AT, direction: DESC} - ): UserStatusConnection! - - """ - A list of users who are members of this organization. - """ - membersWithRole( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationMemberConnection! - - """ - The organization's public profile name. - """ - name: String - - """ - The HTTP path creating a new team - """ - newTeamResourcePath: URI! - - """ - The HTTP URL creating a new team - """ - newTeamUrl: URI! - - """ - The billing email for the organization. - """ - organizationBillingEmail: String - - """ - A list of packages under the owner. - """ - packages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find packages by their names. - """ - names: [String] - - """ - Ordering of the returned packages. - """ - orderBy: PackageOrder = {field: CREATED_AT, direction: DESC} - - """ - Filter registry package by type. - """ - packageType: PackageType - - """ - Find packages in a repository by ID. - """ - repositoryId: ID - ): PackageConnection! - - """ - A list of users who have been invited to join this organization. - """ - pendingMembers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - A list of repositories and gists this profile owner can pin to their profile. - """ - pinnableItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinnable items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - A list of repositories and gists this profile owner has pinned to their profile - """ - pinnedItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinned items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - Returns how many more items this profile owner can pin to their profile. - """ - pinnedItemsRemaining: Int! - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing organization's projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing organization's projects - """ - projectsUrl: URI! - - """ - A list of repositories that the user owns. - """ - repositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they are forks of another repository - """ - isFork: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Find Repository. - """ - repository( - """ - Name of Repository to find. - """ - name: String! - ): Repository - - """ - When true the organization requires all members, billing managers, and outside - collaborators to enable two-factor authentication. - """ - requiresTwoFactorAuthentication: Boolean - - """ - The HTTP path for this organization. - """ - resourcePath: URI! - - """ - The Organization's SAML identity providers - """ - samlIdentityProvider: OrganizationIdentityProvider - - """ - The GitHub Sponsors listing for this user. - """ - sponsorsListing: SponsorsListing - - """ - This object's sponsorships as the maintainer. - """ - sponsorshipsAsMaintainer( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether or not to include private sponsorships in the result set - """ - includePrivate: Boolean = false - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - This object's sponsorships as the sponsor. - """ - sponsorshipsAsSponsor( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - Find an organization's team by its slug. - """ - team( - """ - The name or slug of the team to find. - """ - slug: String! - ): Team - - """ - A list of teams in this organization. - """ - teams( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - If true, filters teams that are mapped to an LDAP Group (Enterprise only) - """ - ldapMapped: Boolean - - """ - Ordering options for teams returned from the connection - """ - orderBy: TeamOrder - - """ - If non-null, filters teams according to privacy - """ - privacy: TeamPrivacy - - """ - If non-null, filters teams with query on team name and team slug - """ - query: String - - """ - If non-null, filters teams according to whether the viewer is an admin or member on team - """ - role: TeamRole - - """ - If true, restrict to only root teams - """ - rootTeamsOnly: Boolean = false - - """ - User logins to filter by - """ - userLogins: [String!] - ): TeamConnection! - - """ - The HTTP path listing organization's teams - """ - teamsResourcePath: URI! - - """ - The HTTP URL listing organization's teams - """ - teamsUrl: URI! - - """ - The organization's Twitter username. - """ - twitterUsername: String - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this organization. - """ - url: URI! - - """ - Organization is adminable by the viewer. - """ - viewerCanAdminister: Boolean! - - """ - Can the viewer pin repositories and gists to the profile? - """ - viewerCanChangePinnedItems: Boolean! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! - - """ - Viewer can create repositories on this organization - """ - viewerCanCreateRepositories: Boolean! - - """ - Viewer can create teams on this organization. - """ - viewerCanCreateTeams: Boolean! - - """ - Viewer is an active member of this organization. - """ - viewerIsAMember: Boolean! - - """ - The organization's public profile URL. - """ - websiteUrl: URI -} - -""" -An audit entry in an organization audit log. -""" -union OrganizationAuditEntry = MembersCanDeleteReposClearAuditEntry | MembersCanDeleteReposDisableAuditEntry | MembersCanDeleteReposEnableAuditEntry | OauthApplicationCreateAuditEntry | OrgAddBillingManagerAuditEntry | OrgAddMemberAuditEntry | OrgBlockUserAuditEntry | OrgConfigDisableCollaboratorsOnlyAuditEntry | OrgConfigEnableCollaboratorsOnlyAuditEntry | OrgCreateAuditEntry | OrgDisableOauthAppRestrictionsAuditEntry | OrgDisableSamlAuditEntry | OrgDisableTwoFactorRequirementAuditEntry | OrgEnableOauthAppRestrictionsAuditEntry | OrgEnableSamlAuditEntry | OrgEnableTwoFactorRequirementAuditEntry | OrgInviteMemberAuditEntry | OrgInviteToBusinessAuditEntry | OrgOauthAppAccessApprovedAuditEntry | OrgOauthAppAccessDeniedAuditEntry | OrgOauthAppAccessRequestedAuditEntry | OrgRemoveBillingManagerAuditEntry | OrgRemoveMemberAuditEntry | OrgRemoveOutsideCollaboratorAuditEntry | OrgRestoreMemberAuditEntry | OrgUnblockUserAuditEntry | OrgUpdateDefaultRepositoryPermissionAuditEntry | OrgUpdateMemberAuditEntry | OrgUpdateMemberRepositoryCreationPermissionAuditEntry | OrgUpdateMemberRepositoryInvitationPermissionAuditEntry | PrivateRepositoryForkingDisableAuditEntry | PrivateRepositoryForkingEnableAuditEntry | RepoAccessAuditEntry | RepoAddMemberAuditEntry | RepoAddTopicAuditEntry | RepoArchivedAuditEntry | RepoChangeMergeSettingAuditEntry | RepoConfigDisableAnonymousGitAccessAuditEntry | RepoConfigDisableCollaboratorsOnlyAuditEntry | RepoConfigDisableContributorsOnlyAuditEntry | RepoConfigDisableSockpuppetDisallowedAuditEntry | RepoConfigEnableAnonymousGitAccessAuditEntry | RepoConfigEnableCollaboratorsOnlyAuditEntry | RepoConfigEnableContributorsOnlyAuditEntry | RepoConfigEnableSockpuppetDisallowedAuditEntry | RepoConfigLockAnonymousGitAccessAuditEntry | RepoConfigUnlockAnonymousGitAccessAuditEntry | RepoCreateAuditEntry | RepoDestroyAuditEntry | RepoRemoveMemberAuditEntry | RepoRemoveTopicAuditEntry | RepositoryVisibilityChangeDisableAuditEntry | RepositoryVisibilityChangeEnableAuditEntry | TeamAddMemberAuditEntry | TeamAddRepositoryAuditEntry | TeamChangeParentTeamAuditEntry | TeamRemoveMemberAuditEntry | TeamRemoveRepositoryAuditEntry - -""" -The connection type for OrganizationAuditEntry. -""" -type OrganizationAuditEntryConnection { - """ - A list of edges. - """ - edges: [OrganizationAuditEntryEdge] - - """ - A list of nodes. - """ - nodes: [OrganizationAuditEntry] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Metadata for an audit entry with action org.* -""" -interface OrganizationAuditEntryData { - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI -} - -""" -An edge in a connection. -""" -type OrganizationAuditEntryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: OrganizationAuditEntry -} - -""" -The connection type for Organization. -""" -type OrganizationConnection { - """ - A list of edges. - """ - edges: [OrganizationEdge] - - """ - A list of nodes. - """ - nodes: [Organization] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type OrganizationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Organization -} - -""" -An Identity Provider configured to provision SAML and SCIM identities for Organizations -""" -type OrganizationIdentityProvider implements Node { - """ - The digest algorithm used to sign SAML requests for the Identity Provider. - """ - digestMethod: URI - - """ - External Identities provisioned by this Identity Provider - """ - externalIdentities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ExternalIdentityConnection! - id: ID! - - """ - The x509 certificate used by the Identity Provder to sign assertions and responses. - """ - idpCertificate: X509Certificate - - """ - The Issuer Entity ID for the SAML Identity Provider - """ - issuer: String - - """ - Organization this Identity Provider belongs to - """ - organization: Organization - - """ - The signature algorithm used to sign SAML requests for the Identity Provider. - """ - signatureMethod: URI - - """ - The URL endpoint for the Identity Provider's SAML SSO. - """ - ssoUrl: URI -} - -""" -An Invitation for a user to an organization. -""" -type OrganizationInvitation implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The email address of the user invited to the organization. - """ - email: String - id: ID! - - """ - The type of invitation that was sent (e.g. email, user). - """ - invitationType: OrganizationInvitationType! - - """ - The user who was invited to the organization. - """ - invitee: User - - """ - The user who created the invitation. - """ - inviter: User! - - """ - The organization the invite is for - """ - organization: Organization! - - """ - The user's pending role in the organization (e.g. member, owner). - """ - role: OrganizationInvitationRole! -} - -""" -The connection type for OrganizationInvitation. -""" -type OrganizationInvitationConnection { - """ - A list of edges. - """ - edges: [OrganizationInvitationEdge] - - """ - A list of nodes. - """ - nodes: [OrganizationInvitation] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type OrganizationInvitationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: OrganizationInvitation -} - -""" -The possible organization invitation roles. -""" -enum OrganizationInvitationRole { - """ - The user is invited to be an admin of the organization. - """ - ADMIN - - """ - The user is invited to be a billing manager of the organization. - """ - BILLING_MANAGER - - """ - The user is invited to be a direct member of the organization. - """ - DIRECT_MEMBER - - """ - The user's previous role will be reinstated. - """ - REINSTATE -} - -""" -The possible organization invitation types. -""" -enum OrganizationInvitationType { - """ - The invitation was to an email address. - """ - EMAIL - - """ - The invitation was to an existing user. - """ - USER -} - -""" -The connection type for User. -""" -type OrganizationMemberConnection { - """ - A list of edges. - """ - edges: [OrganizationMemberEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user within an organization. -""" -type OrganizationMemberEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - Whether the organization member has two factor enabled or not. Returns null if information is not available to viewer. - """ - hasTwoFactorEnabled: Boolean - - """ - The item at the end of the edge. - """ - node: User - - """ - The role this user has in the organization. - """ - role: OrganizationMemberRole -} - -""" -The possible roles within an organization for its members. -""" -enum OrganizationMemberRole { - """ - The user is an administrator of the organization. - """ - ADMIN - - """ - The user is a member of the organization. - """ - MEMBER -} - -""" -The possible values for the members can create repositories setting on an organization. -""" -enum OrganizationMembersCanCreateRepositoriesSettingValue { - """ - Members will be able to create public and private repositories. - """ - ALL - - """ - Members will not be able to create public or private repositories. - """ - DISABLED - - """ - Members will be able to create only private repositories. - """ - PRIVATE -} - -""" -Ordering options for organization connections. -""" -input OrganizationOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order organizations by. - """ - field: OrganizationOrderField! -} - -""" -Properties by which organization connections can be ordered. -""" -enum OrganizationOrderField { - """ - Order organizations by creation time - """ - CREATED_AT - - """ - Order organizations by login - """ - LOGIN -} - -""" -An organization teams hovercard context -""" -type OrganizationTeamsHovercardContext implements HovercardContext { - """ - A string describing this context - """ - message: String! - - """ - An octicon to accompany this context - """ - octicon: String! - - """ - Teams in this organization the user is a member of that are relevant - """ - relevantTeams( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): TeamConnection! - - """ - The path for the full team list for this user - """ - teamsResourcePath: URI! - - """ - The URL for the full team list for this user - """ - teamsUrl: URI! - - """ - The total number of teams the user is on in the organization - """ - totalTeamCount: Int! -} - -""" -An organization list hovercard context -""" -type OrganizationsHovercardContext implements HovercardContext { - """ - A string describing this context - """ - message: String! - - """ - An octicon to accompany this context - """ - octicon: String! - - """ - Organizations this user is a member of that are relevant - """ - relevantOrganizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationConnection! - - """ - The total number of organizations this user is in - """ - totalOrganizationCount: Int! -} - -""" -Information for an uploaded package. -""" -type Package implements Node { - id: ID! - - """ - Find the latest version for the package. - """ - latestVersion: PackageVersion - - """ - Identifies the name of the package. - """ - name: String! - - """ - Identifies the type of the package. - """ - packageType: PackageType! - - """ - The repository this package belongs to. - """ - repository: Repository - - """ - Statistics about package activity. - """ - statistics: PackageStatistics - - """ - Find package version by version string. - """ - version( - """ - The package version. - """ - version: String! - ): PackageVersion - - """ - list of versions for this package - """ - versions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering of the returned packages. - """ - orderBy: PackageVersionOrder = {field: CREATED_AT, direction: DESC} - ): PackageVersionConnection! -} - -""" -The connection type for Package. -""" -type PackageConnection { - """ - A list of edges. - """ - edges: [PackageEdge] - - """ - A list of nodes. - """ - nodes: [Package] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PackageEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Package -} - -""" -A file in a package version. -""" -type PackageFile implements Node { - id: ID! - - """ - MD5 hash of the file. - """ - md5: String - - """ - Name of the file. - """ - name: String! - - """ - The package version this file belongs to. - """ - packageVersion: PackageVersion - - """ - SHA1 hash of the file. - """ - sha1: String - - """ - SHA256 hash of the file. - """ - sha256: String - - """ - Size of the file in bytes. - """ - size: Int - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - URL to download the asset. - """ - url: URI -} - -""" -The connection type for PackageFile. -""" -type PackageFileConnection { - """ - A list of edges. - """ - edges: [PackageFileEdge] - - """ - A list of nodes. - """ - nodes: [PackageFile] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PackageFileEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PackageFile -} - -""" -Ways in which lists of package files can be ordered upon return. -""" -input PackageFileOrder { - """ - The direction in which to order package files by the specified field. - """ - direction: OrderDirection - - """ - The field in which to order package files by. - """ - field: PackageFileOrderField -} - -""" -Properties by which package file connections can be ordered. -""" -enum PackageFileOrderField { - """ - Order package files by creation time - """ - CREATED_AT -} - -""" -Ways in which lists of packages can be ordered upon return. -""" -input PackageOrder { - """ - The direction in which to order packages by the specified field. - """ - direction: OrderDirection - - """ - The field in which to order packages by. - """ - field: PackageOrderField -} - -""" -Properties by which package connections can be ordered. -""" -enum PackageOrderField { - """ - Order packages by creation time - """ - CREATED_AT -} - -""" -Represents an owner of a package. -""" -interface PackageOwner { - id: ID! - - """ - A list of packages under the owner. - """ - packages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find packages by their names. - """ - names: [String] - - """ - Ordering of the returned packages. - """ - orderBy: PackageOrder = {field: CREATED_AT, direction: DESC} - - """ - Filter registry package by type. - """ - packageType: PackageType - - """ - Find packages in a repository by ID. - """ - repositoryId: ID - ): PackageConnection! -} - -""" -Represents a object that contains package activity statistics such as downloads. -""" -type PackageStatistics { - """ - Number of times the package was downloaded since it was created. - """ - downloadsTotalCount: Int! -} - -""" -A version tag contains the mapping between a tag name and a version. -""" -type PackageTag implements Node { - id: ID! - - """ - Identifies the tag name of the version. - """ - name: String! - - """ - Version that the tag is associated with. - """ - version: PackageVersion -} - -""" -The possible types of a package. -""" -enum PackageType { - """ - A debian package. - """ - DEBIAN - - """ - A docker image. - """ - DOCKER - - """ - A maven package. - """ - MAVEN - - """ - An npm package. - """ - NPM - - """ - A nuget package. - """ - NUGET - - """ - A python package. - """ - PYPI - - """ - A rubygems package. - """ - RUBYGEMS -} - -""" -Information about a specific package version. -""" -type PackageVersion implements Node { - """ - List of files associated with this package version - """ - files( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering of the returned package files. - """ - orderBy: PackageFileOrder = {field: CREATED_AT, direction: ASC} - ): PackageFileConnection! - id: ID! - - """ - The package associated with this version. - """ - package: Package - - """ - The platform this version was built for. - """ - platform: String - - """ - Whether or not this version is a pre-release. - """ - preRelease: Boolean! - - """ - The README of this package version. - """ - readme: String - - """ - The release associated with this package version. - """ - release: Release - - """ - Statistics about package activity. - """ - statistics: PackageVersionStatistics - - """ - The package version summary. - """ - summary: String - - """ - The version string. - """ - version: String! -} - -""" -The connection type for PackageVersion. -""" -type PackageVersionConnection { - """ - A list of edges. - """ - edges: [PackageVersionEdge] - - """ - A list of nodes. - """ - nodes: [PackageVersion] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PackageVersionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PackageVersion -} - -""" -Ways in which lists of package versions can be ordered upon return. -""" -input PackageVersionOrder { - """ - The direction in which to order package versions by the specified field. - """ - direction: OrderDirection - - """ - The field in which to order package versions by. - """ - field: PackageVersionOrderField -} - -""" -Properties by which package version connections can be ordered. -""" -enum PackageVersionOrderField { - """ - Order package versions by creation time - """ - CREATED_AT -} - -""" -Represents a object that contains package version activity statistics such as downloads. -""" -type PackageVersionStatistics { - """ - Number of times the package was downloaded since it was created. - """ - downloadsTotalCount: Int! -} - -""" -Information about pagination in a connection. -""" -type PageInfo { - """ - When paginating forwards, the cursor to continue. - """ - endCursor: String - - """ - When paginating forwards, are there more items? - """ - hasNextPage: Boolean! - - """ - When paginating backwards, are there more items? - """ - hasPreviousPage: Boolean! - - """ - When paginating backwards, the cursor to continue. - """ - startCursor: String -} - -""" -Types that can grant permissions on a repository to a user -""" -union PermissionGranter = Organization | Repository | Team - -""" -A level of permission and source for a user's access to a repository. -""" -type PermissionSource { - """ - The organization the repository belongs to. - """ - organization: Organization! - - """ - The level of access this source has granted to the user. - """ - permission: DefaultRepositoryPermissionField! - - """ - The source of this permission. - """ - source: PermissionGranter! -} - -""" -Autogenerated input type of PinIssue -""" -input PinIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the issue to be pinned - """ - issueId: ID! @possibleTypes(concreteTypes: ["Issue"]) -} - -""" -Autogenerated return type of PinIssue -""" -type PinIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was pinned - """ - issue: Issue -} - -""" -Types that can be pinned to a profile page. -""" -union PinnableItem = Gist | Repository - -""" -The connection type for PinnableItem. -""" -type PinnableItemConnection { - """ - A list of edges. - """ - edges: [PinnableItemEdge] - - """ - A list of nodes. - """ - nodes: [PinnableItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PinnableItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PinnableItem -} - -""" -Represents items that can be pinned to a profile page or dashboard. -""" -enum PinnableItemType { - """ - A gist. - """ - GIST - - """ - An issue. - """ - ISSUE - - """ - An organization. - """ - ORGANIZATION - - """ - A project. - """ - PROJECT - - """ - A pull request. - """ - PULL_REQUEST - - """ - A repository. - """ - REPOSITORY - - """ - A team. - """ - TEAM - - """ - A user. - """ - USER -} - -""" -Represents a 'pinned' event on a given issue or pull request. -""" -type PinnedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the issue associated with the event. - """ - issue: Issue! -} - -""" -A Pinned Issue is a issue pinned to a repository's index page. -""" -type PinnedIssue implements Node @preview(toggledBy: "elektra-preview") { - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The issue that was pinned. - """ - issue: Issue! - - """ - The actor that pinned this issue. - """ - pinnedBy: Actor! - - """ - The repository that this issue was pinned to. - """ - repository: Repository! -} - -""" -The connection type for PinnedIssue. -""" -type PinnedIssueConnection @preview(toggledBy: "elektra-preview") { - """ - A list of edges. - """ - edges: [PinnedIssueEdge] - - """ - A list of nodes. - """ - nodes: [PinnedIssue] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PinnedIssueEdge @preview(toggledBy: "elektra-preview") { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PinnedIssue -} - -""" -An ISO-8601 encoded UTC date string with millisecond precison. -""" -scalar PreciseDateTime - -""" -Audit log entry for a private_repository_forking.disable event. -""" -type PrivateRepositoryForkingDisableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a private_repository_forking.enable event. -""" -type PrivateRepositoryForkingEnableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -A curatable list of repositories relating to a repository owner, which defaults -to showing the most popular repositories they own. -""" -type ProfileItemShowcase { - """ - Whether or not the owner has pinned any repositories or gists. - """ - hasPinnedItems: Boolean! - - """ - The repositories and gists in the showcase. If the profile owner has any - pinned items, those will be returned. Otherwise, the profile owner's popular - repositories will be returned. - """ - items( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PinnableItemConnection! -} - -""" -Represents any entity on GitHub that has a profile page. -""" -interface ProfileOwner { - """ - Determine if this repository owner has any items that can be pinned to their profile. - """ - anyPinnableItems( - """ - Filter to only a particular kind of pinnable item. - """ - type: PinnableItemType - ): Boolean! - - """ - The public profile email. - """ - email: String - id: ID! - - """ - Showcases a selection of repositories and gists that the profile owner has - either curated or that have been selected automatically based on popularity. - """ - itemShowcase: ProfileItemShowcase! - - """ - The public profile location. - """ - location: String - - """ - The username used to login. - """ - login: String! - - """ - The public profile name. - """ - name: String - - """ - A list of repositories and gists this profile owner can pin to their profile. - """ - pinnableItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinnable items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - A list of repositories and gists this profile owner has pinned to their profile - """ - pinnedItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinned items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - Returns how many more items this profile owner can pin to their profile. - """ - pinnedItemsRemaining: Int! - - """ - Can the viewer pin repositories and gists to the profile? - """ - viewerCanChangePinnedItems: Boolean! - - """ - The public profile website URL. - """ - websiteUrl: URI -} - -""" -Projects manage issues, pull requests and notes within a project owner. -""" -type Project implements Closable & Node & Updatable { - """ - The project's description body. - """ - body: String - - """ - The projects description body rendered to HTML. - """ - bodyHTML: HTML! - - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - List of columns in the project - """ - columns( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectColumnConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The actor who originally created the project. - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The project's name. - """ - name: String! - - """ - The project's number. - """ - number: Int! - - """ - The project's owner. Currently limited to repositories, organizations, and users. - """ - owner: ProjectOwner! - - """ - List of pending cards in this project - """ - pendingCards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - The HTTP path for this project - """ - resourcePath: URI! - - """ - Whether the project is open or closed. - """ - state: ProjectState! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this project - """ - url: URI! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! -} - -""" -A card in a project. -""" -type ProjectCard implements Node { - """ - The project column this card is associated under. A card may only belong to one - project column at a time. The column field will be null if the card is created - in a pending state and has yet to be associated with a column. Once cards are - associated with a column, they will not become pending in the future. - """ - column: ProjectColumn - - """ - The card content item - """ - content: ProjectCardItem - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The actor who created this card - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Whether the card is archived - """ - isArchived: Boolean! - - """ - The card note - """ - note: String - - """ - The project that contains this card. - """ - project: Project! - - """ - The HTTP path for this card - """ - resourcePath: URI! - - """ - The state of ProjectCard - """ - state: ProjectCardState - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this card - """ - url: URI! -} - -""" -The possible archived states of a project card. -""" -enum ProjectCardArchivedState { - """ - A project card that is archived - """ - ARCHIVED - - """ - A project card that is not archived - """ - NOT_ARCHIVED -} - -""" -The connection type for ProjectCard. -""" -type ProjectCardConnection { - """ - A list of edges. - """ - edges: [ProjectCardEdge] - - """ - A list of nodes. - """ - nodes: [ProjectCard] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ProjectCardEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ProjectCard -} - -""" -An issue or PR and its owning repository to be used in a project card. -""" -input ProjectCardImport { - """ - The issue or pull request number. - """ - number: Int! - - """ - Repository name with owner (owner/repository). - """ - repository: String! -} - -""" -Types that can be inside Project Cards. -""" -union ProjectCardItem = Issue | PullRequest - -""" -Various content states of a ProjectCard -""" -enum ProjectCardState { - """ - The card has content only. - """ - CONTENT_ONLY - - """ - The card has a note only. - """ - NOTE_ONLY - - """ - The card is redacted. - """ - REDACTED -} - -""" -A column inside a project. -""" -type ProjectColumn implements Node { - """ - List of cards in the column - """ - cards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The project column's name. - """ - name: String! - - """ - The project that contains this column. - """ - project: Project! - - """ - The semantic purpose of the column - """ - purpose: ProjectColumnPurpose - - """ - The HTTP path for this project column - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this project column - """ - url: URI! -} - -""" -The connection type for ProjectColumn. -""" -type ProjectColumnConnection { - """ - A list of edges. - """ - edges: [ProjectColumnEdge] - - """ - A list of nodes. - """ - nodes: [ProjectColumn] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ProjectColumnEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ProjectColumn -} - -""" -A project column and a list of its issues and PRs. -""" -input ProjectColumnImport { - """ - The name of the column. - """ - columnName: String! - - """ - A list of issues and pull requests in the column. - """ - issues: [ProjectCardImport!] - - """ - The position of the column, starting from 0. - """ - position: Int! -} - -""" -The semantic purpose of the column - todo, in progress, or done. -""" -enum ProjectColumnPurpose { - """ - The column contains cards which are complete - """ - DONE - - """ - The column contains cards which are currently being worked on - """ - IN_PROGRESS - - """ - The column contains cards still to be worked on - """ - TODO -} - -""" -A list of projects associated with the owner. -""" -type ProjectConnection { - """ - A list of edges. - """ - edges: [ProjectEdge] - - """ - A list of nodes. - """ - nodes: [Project] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ProjectEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Project -} - -""" -Ways in which lists of projects can be ordered upon return. -""" -input ProjectOrder { - """ - The direction in which to order projects by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order projects by. - """ - field: ProjectOrderField! -} - -""" -Properties by which project connections can be ordered. -""" -enum ProjectOrderField { - """ - Order projects by creation time - """ - CREATED_AT - - """ - Order projects by name - """ - NAME - - """ - Order projects by update time - """ - UPDATED_AT -} - -""" -Represents an owner of a Project. -""" -interface ProjectOwner { - id: ID! - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing owners projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing owners projects - """ - projectsUrl: URI! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! -} - -""" -State of the project; either 'open' or 'closed' -""" -enum ProjectState { - """ - The project is closed. - """ - CLOSED - - """ - The project is open. - """ - OPEN -} - -""" -GitHub-provided templates for Projects -""" -enum ProjectTemplate { - """ - Create a board with v2 triggers to automatically move cards across To do, In progress and Done columns. - """ - AUTOMATED_KANBAN_V2 - - """ - Create a board with triggers to automatically move cards across columns with review automation. - """ - AUTOMATED_REVIEWS_KANBAN - - """ - Create a board with columns for To do, In progress and Done. - """ - BASIC_KANBAN - - """ - Create a board to triage and prioritize bugs with To do, priority, and Done columns. - """ - BUG_TRIAGE -} - -""" -A user's public key. -""" -type PublicKey implements Node { - """ - The last time this authorization was used to perform an action. Values will be null for keys not owned by the user. - """ - accessedAt: DateTime - - """ - Identifies the date and time when the key was created. Keys created before - March 5th, 2014 have inaccurate values. Values will be null for keys not owned by the user. - """ - createdAt: DateTime - - """ - The fingerprint for this PublicKey. - """ - fingerprint: String! - id: ID! - - """ - Whether this PublicKey is read-only or not. Values will be null for keys not owned by the user. - """ - isReadOnly: Boolean - - """ - The public key string. - """ - key: String! - - """ - Identifies the date and time when the key was updated. Keys created before - March 5th, 2014 may have inaccurate values. Values will be null for keys not - owned by the user. - """ - updatedAt: DateTime -} - -""" -The connection type for PublicKey. -""" -type PublicKeyConnection { - """ - A list of edges. - """ - edges: [PublicKeyEdge] - - """ - A list of nodes. - """ - nodes: [PublicKey] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PublicKeyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PublicKey -} - -""" -A repository pull request. -""" -type PullRequest implements Assignable & Closable & Comment & Labelable & Lockable & Node & Reactable & RepositoryNode & Subscribable & UniformResourceLocatable & Updatable & UpdatableComment { - """ - Reason that the conversation was locked. - """ - activeLockReason: LockReason - - """ - The number of additions in this pull request. - """ - additions: Int! - - """ - A list of Users assigned to this object. - """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the base Ref associated with the pull request. - """ - baseRef: Ref - - """ - Identifies the name of the base Ref associated with the pull request, even if the ref has been deleted. - """ - baseRefName: String! - - """ - Identifies the oid of the base ref associated with the pull request, even if the ref has been deleted. - """ - baseRefOid: GitObjectID! - - """ - The repository associated with this pull request's base Ref. - """ - baseRepository: Repository - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Whether or not the pull request is rebaseable. - """ - canBeRebased: Boolean! @preview(toggledBy: "merge-info-preview") - - """ - The number of changed files in this pull request. - """ - changedFiles: Int! - - """ - The HTTP path for the checks of this pull request. - """ - checksResourcePath: URI! - - """ - The HTTP URL for the checks of this pull request. - """ - checksUrl: URI! - - """ - `true` if the pull request is closed - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - A list of comments associated with the pull request. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): IssueCommentConnection! - - """ - A list of commits present in this pull request's head branch not present in the base branch. - """ - commits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestCommitConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The number of deletions in this pull request. - """ - deletions: Int! - - """ - The actor who edited this pull request's body. - """ - editor: Actor - - """ - Lists the files changed within this pull request. - """ - files( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestChangedFileConnection - - """ - Identifies the head Ref associated with the pull request. - """ - headRef: Ref - - """ - Identifies the name of the head Ref associated with the pull request, even if the ref has been deleted. - """ - headRefName: String! - - """ - Identifies the oid of the head ref associated with the pull request, even if the ref has been deleted. - """ - headRefOid: GitObjectID! - - """ - The repository associated with this pull request's head Ref. - """ - headRepository: Repository - - """ - The owner of the repository associated with this pull request's head Ref. - """ - headRepositoryOwner: RepositoryOwner - - """ - The hovercard information for this issue - """ - hovercard( - """ - Whether or not to include notification contexts - """ - includeNotificationContexts: Boolean = true - ): Hovercard! - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The head and base repositories are different. - """ - isCrossRepository: Boolean! - - """ - Identifies if the pull request is a draft. - """ - isDraft: Boolean! - - """ - A list of labels associated with the object. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for labels returned from the connection. - """ - orderBy: LabelOrder = {field: CREATED_AT, direction: ASC} - ): LabelConnection - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - `true` if the pull request is locked - """ - locked: Boolean! - - """ - Indicates whether maintainers can modify the pull request. - """ - maintainerCanModify: Boolean! - - """ - The commit that was created when this pull request was merged. - """ - mergeCommit: Commit - - """ - Detailed information about the current pull request merge state status. - """ - mergeStateStatus: MergeStateStatus! @preview(toggledBy: "merge-info-preview") - - """ - Whether or not the pull request can be merged based on the existence of merge conflicts. - """ - mergeable: MergeableState! - - """ - Whether or not the pull request was merged. - """ - merged: Boolean! - - """ - The date and time that the pull request was merged. - """ - mergedAt: DateTime - - """ - The actor who merged the pull request. - """ - mergedBy: Actor - - """ - Identifies the milestone associated with the pull request. - """ - milestone: Milestone - - """ - Identifies the pull request number. - """ - number: Int! - - """ - A list of Users that are participating in the Pull Request conversation. - """ - participants( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - The permalink to the pull request. - """ - permalink: URI! - - """ - The commit that GitHub automatically generated to test if this pull request - could be merged. This field will not return a value if the pull request is - merged, or if the test merge commit is still being generated. See the - `mergeable` field for more details on the mergeability of the pull request. - """ - potentialMergeCommit: Commit - - """ - List of project cards associated with this pull request. - """ - projectCards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path for this pull request. - """ - resourcePath: URI! - - """ - The HTTP path for reverting this pull request. - """ - revertResourcePath: URI! - - """ - The HTTP URL for reverting this pull request. - """ - revertUrl: URI! - - """ - The current status of this pull request with respect to code review. - """ - reviewDecision: PullRequestReviewDecision - - """ - A list of review requests associated with the pull request. - """ - reviewRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ReviewRequestConnection - - """ - The list of all review threads for this pull request. - """ - reviewThreads( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestReviewThreadConnection! - - """ - A list of reviews associated with the pull request. - """ - reviews( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Filter by author of the review. - """ - author: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - A list of states to filter the reviews. - """ - states: [PullRequestReviewState!] - ): PullRequestReviewConnection - - """ - Identifies the state of the pull request. - """ - state: PullRequestState! - - """ - A list of reviewer suggestions based on commit history and past review comments. - """ - suggestedReviewers: [SuggestedReviewer]! - - """ - A list of events, comments, commits, etc. associated with the pull request. - """ - timeline( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows filtering timeline events by a `since` timestamp. - """ - since: DateTime - ): PullRequestTimelineConnection! @deprecated(reason: "`timeline` will be removed Use PullRequest.timelineItems instead. Removal on 2020-10-01 UTC.") - - """ - A list of events, comments, commits, etc. associated with the pull request. - """ - timelineItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Filter timeline items by type. - """ - itemTypes: [PullRequestTimelineItemsItemType!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter timeline items by a `since` timestamp. - """ - since: DateTime - - """ - Skips the first _n_ elements in the list. - """ - skip: Int - ): PullRequestTimelineItemsConnection! - - """ - Identifies the pull request title. - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this pull request. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Whether or not the viewer can apply suggestion. - """ - viewerCanApplySuggestion: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -A file changed in a pull request. -""" -type PullRequestChangedFile { - """ - The number of additions to the file. - """ - additions: Int! - - """ - The number of deletions to the file. - """ - deletions: Int! - - """ - The path of the file. - """ - path: String! -} - -""" -The connection type for PullRequestChangedFile. -""" -type PullRequestChangedFileConnection { - """ - A list of edges. - """ - edges: [PullRequestChangedFileEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestChangedFile] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestChangedFileEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestChangedFile -} - -""" -Represents a Git commit part of a pull request. -""" -type PullRequestCommit implements Node & UniformResourceLocatable { - """ - The Git commit object - """ - commit: Commit! - id: ID! - - """ - The pull request this commit belongs to - """ - pullRequest: PullRequest! - - """ - The HTTP path for this pull request commit - """ - resourcePath: URI! - - """ - The HTTP URL for this pull request commit - """ - url: URI! -} - -""" -Represents a commit comment thread part of a pull request. -""" -type PullRequestCommitCommentThread implements Node & RepositoryNode { - """ - The comments that exist in this thread. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The commit the comments were made on. - """ - commit: Commit! - id: ID! - - """ - The file the comments were made on. - """ - path: String - - """ - The position in the diff for the commit that the comment was made on. - """ - position: Int - - """ - The pull request this commit comment thread belongs to - """ - pullRequest: PullRequest! - - """ - The repository associated with this node. - """ - repository: Repository! -} - -""" -The connection type for PullRequestCommit. -""" -type PullRequestCommitConnection { - """ - A list of edges. - """ - edges: [PullRequestCommitEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestCommit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestCommitEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestCommit -} - -""" -The connection type for PullRequest. -""" -type PullRequestConnection { - """ - A list of edges. - """ - edges: [PullRequestEdge] - - """ - A list of nodes. - """ - nodes: [PullRequest] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -This aggregates pull requests opened by a user within one repository. -""" -type PullRequestContributionsByRepository { - """ - The pull request contributions. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedPullRequestContributionConnection! - - """ - The repository in which the pull requests were opened. - """ - repository: Repository! -} - -""" -An edge in a connection. -""" -type PullRequestEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequest -} - -""" -Represents available types of methods to use when merging a pull request. -""" -enum PullRequestMergeMethod { - """ - Add all commits from the head branch to the base branch with a merge commit. - """ - MERGE - - """ - Add all commits from the head branch onto the base branch individually. - """ - REBASE - - """ - Combine all commits from the head branch into a single commit in the base branch. - """ - SQUASH -} - -""" -Ways in which lists of issues can be ordered upon return. -""" -input PullRequestOrder { - """ - The direction in which to order pull requests by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order pull requests by. - """ - field: PullRequestOrderField! -} - -""" -Properties by which pull_requests connections can be ordered. -""" -enum PullRequestOrderField { - """ - Order pull_requests by creation time - """ - CREATED_AT - - """ - Order pull_requests by update time - """ - UPDATED_AT -} - -""" -A review object for a given pull request. -""" -type PullRequestReview implements Comment & Deletable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the pull request review body. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body of this review rendered as plain text. - """ - bodyText: String! - - """ - A list of review comments for the current pull request review. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestReviewCommentConnection! - - """ - Identifies the commit associated with this pull request review. - """ - commit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - A list of teams that this review was made on behalf of. - """ - onBehalfOf( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): TeamConnection! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Identifies the pull request associated with this pull request review. - """ - pullRequest: PullRequest! - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path permalink for this PullRequestReview. - """ - resourcePath: URI! - - """ - Identifies the current state of the pull request review. - """ - state: PullRequestReviewState! - - """ - Identifies when the Pull Request Review was submitted - """ - submittedAt: DateTime - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL permalink for this PullRequestReview. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -A review comment associated with a given repository pull request. -""" -type PullRequestReviewComment implements Comment & Deletable & Minimizable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The comment body of this review comment. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The comment body of this review comment rendered as plain text. - """ - bodyText: String! - - """ - Identifies the commit associated with the comment. - """ - commit: Commit - - """ - Identifies when the comment was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The diff hunk to which the comment applies. - """ - diffHunk: String! - - """ - Identifies when the comment was created in a draft state. - """ - draftedAt: DateTime! - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies the original commit associated with the comment. - """ - originalCommit: Commit - - """ - The original line index in the diff to which the comment applies. - """ - originalPosition: Int! - - """ - Identifies when the comment body is outdated - """ - outdated: Boolean! - - """ - The path to which the comment applies. - """ - path: String! - - """ - The line index in the diff to which the comment applies. - """ - position: Int - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - The pull request associated with this review comment. - """ - pullRequest: PullRequest! - - """ - The pull request review associated with this review comment. - """ - pullRequestReview: PullRequestReview - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The comment this is a reply to. - """ - replyTo: PullRequestReviewComment - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path permalink for this review comment. - """ - resourcePath: URI! - - """ - Identifies the state of the comment. - """ - state: PullRequestReviewCommentState! - - """ - Identifies when the comment was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL permalink for this review comment. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for PullRequestReviewComment. -""" -type PullRequestReviewCommentConnection { - """ - A list of edges. - """ - edges: [PullRequestReviewCommentEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestReviewComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestReviewCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestReviewComment -} - -""" -The possible states of a pull request review comment. -""" -enum PullRequestReviewCommentState { - """ - A comment that is part of a pending review - """ - PENDING - - """ - A comment that is part of a submitted review - """ - SUBMITTED -} - -""" -The connection type for PullRequestReview. -""" -type PullRequestReviewConnection { - """ - A list of edges. - """ - edges: [PullRequestReviewEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestReview] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -This aggregates pull request reviews made by a user within one repository. -""" -type PullRequestReviewContributionsByRepository { - """ - The pull request review contributions. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {direction: DESC} - ): CreatedPullRequestReviewContributionConnection! - - """ - The repository in which the pull request reviews were made. - """ - repository: Repository! -} - -""" -The review status of a pull request. -""" -enum PullRequestReviewDecision { - """ - The pull request has received an approving review. - """ - APPROVED - - """ - Changes have been requested on the pull request. - """ - CHANGES_REQUESTED - - """ - A review is required before the pull request can be merged. - """ - REVIEW_REQUIRED -} - -""" -An edge in a connection. -""" -type PullRequestReviewEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestReview -} - -""" -The possible events to perform on a pull request review. -""" -enum PullRequestReviewEvent { - """ - Submit feedback and approve merging these changes. - """ - APPROVE - - """ - Submit general feedback without explicit approval. - """ - COMMENT - - """ - Dismiss review so it now longer effects merging. - """ - DISMISS - - """ - Submit feedback that must be addressed before merging. - """ - REQUEST_CHANGES -} - -""" -The possible states of a pull request review. -""" -enum PullRequestReviewState { - """ - A review allowing the pull request to merge. - """ - APPROVED - - """ - A review blocking the pull request from merging. - """ - CHANGES_REQUESTED - - """ - An informational review. - """ - COMMENTED - - """ - A review that has been dismissed. - """ - DISMISSED - - """ - A review that has not yet been submitted. - """ - PENDING -} - -""" -A threaded list of comments for a given pull request. -""" -type PullRequestReviewThread implements Node { - """ - A list of pull request comments associated with the thread. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Skips the first _n_ elements in the list. - """ - skip: Int - ): PullRequestReviewCommentConnection! - - """ - The side of the diff on which this thread was placed. - """ - diffSide: DiffSide! - id: ID! - - """ - Whether this thread has been resolved - """ - isResolved: Boolean! - - """ - The line in the file to which this thread refers - """ - line: Int - - """ - The original line in the file to which this thread refers. - """ - originalLine: Int - - """ - The original start line in the file to which this thread refers (multi-line only). - """ - originalStartLine: Int - - """ - Identifies the pull request associated with this thread. - """ - pullRequest: PullRequest! - - """ - Identifies the repository associated with this thread. - """ - repository: Repository! - - """ - The user who resolved this thread - """ - resolvedBy: User - - """ - The side of the diff that the first line of the thread starts on (multi-line only) - """ - startDiffSide: DiffSide - - """ - The start line in the file to which this thread refers (multi-line only) - """ - startLine: Int - - """ - Whether or not the viewer can resolve this thread - """ - viewerCanResolve: Boolean! - - """ - Whether or not the viewer can unresolve this thread - """ - viewerCanUnresolve: Boolean! -} - -""" -Review comment threads for a pull request review. -""" -type PullRequestReviewThreadConnection { - """ - A list of edges. - """ - edges: [PullRequestReviewThreadEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestReviewThread] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestReviewThreadEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestReviewThread -} - -""" -Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. -""" -type PullRequestRevisionMarker { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The last commit the viewer has seen. - """ - lastSeenCommit: Commit! - - """ - The pull request to which the marker belongs. - """ - pullRequest: PullRequest! -} - -""" -The possible states of a pull request. -""" -enum PullRequestState { - """ - A pull request that has been closed without being merged. - """ - CLOSED - - """ - A pull request that has been closed by being merged. - """ - MERGED - - """ - A pull request that is still open. - """ - OPEN -} - -""" -The connection type for PullRequestTimelineItem. -""" -type PullRequestTimelineConnection { - """ - A list of edges. - """ - edges: [PullRequestTimelineItemEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestTimelineItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An item in an pull request timeline -""" -union PullRequestTimelineItem = AssignedEvent | BaseRefForcePushedEvent | ClosedEvent | Commit | CommitCommentThread | CrossReferencedEvent | DemilestonedEvent | DeployedEvent | DeploymentEnvironmentChangedEvent | HeadRefDeletedEvent | HeadRefForcePushedEvent | HeadRefRestoredEvent | IssueComment | LabeledEvent | LockedEvent | MergedEvent | MilestonedEvent | PullRequestReview | PullRequestReviewComment | PullRequestReviewThread | ReferencedEvent | RenamedTitleEvent | ReopenedEvent | ReviewDismissedEvent | ReviewRequestRemovedEvent | ReviewRequestedEvent | SubscribedEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -An edge in a connection. -""" -type PullRequestTimelineItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestTimelineItem -} - -""" -An item in a pull request timeline -""" -union PullRequestTimelineItems = AddedToProjectEvent | AssignedEvent | AutomaticBaseChangeFailedEvent | AutomaticBaseChangeSucceededEvent | BaseRefChangedEvent | BaseRefForcePushedEvent | ClosedEvent | CommentDeletedEvent | ConnectedEvent | ConvertToDraftEvent | ConvertedNoteToIssueEvent | CrossReferencedEvent | DemilestonedEvent | DeployedEvent | DeploymentEnvironmentChangedEvent | DisconnectedEvent | HeadRefDeletedEvent | HeadRefForcePushedEvent | HeadRefRestoredEvent | IssueComment | LabeledEvent | LockedEvent | MarkedAsDuplicateEvent | MentionedEvent | MergedEvent | MilestonedEvent | MovedColumnsInProjectEvent | PinnedEvent | PullRequestCommit | PullRequestCommitCommentThread | PullRequestReview | PullRequestReviewThread | PullRequestRevisionMarker | ReadyForReviewEvent | ReferencedEvent | RemovedFromProjectEvent | RenamedTitleEvent | ReopenedEvent | ReviewDismissedEvent | ReviewRequestRemovedEvent | ReviewRequestedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnmarkedAsDuplicateEvent | UnpinnedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -The connection type for PullRequestTimelineItems. -""" -type PullRequestTimelineItemsConnection { - """ - A list of edges. - """ - edges: [PullRequestTimelineItemsEdge] - - """ - Identifies the count of items after applying `before` and `after` filters. - """ - filteredCount: Int! - - """ - A list of nodes. - """ - nodes: [PullRequestTimelineItems] - - """ - Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing. - """ - pageCount: Int! - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Identifies the date and time when the timeline was last updated. - """ - updatedAt: DateTime! -} - -""" -An edge in a connection. -""" -type PullRequestTimelineItemsEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestTimelineItems -} - -""" -The possible item types found in a timeline. -""" -enum PullRequestTimelineItemsItemType { - """ - Represents a 'added_to_project' event on a given issue or pull request. - """ - ADDED_TO_PROJECT_EVENT - - """ - Represents an 'assigned' event on any assignable object. - """ - ASSIGNED_EVENT - - """ - Represents a 'automatic_base_change_failed' event on a given pull request. - """ - AUTOMATIC_BASE_CHANGE_FAILED_EVENT - - """ - Represents a 'automatic_base_change_succeeded' event on a given pull request. - """ - AUTOMATIC_BASE_CHANGE_SUCCEEDED_EVENT - - """ - Represents a 'base_ref_changed' event on a given issue or pull request. - """ - BASE_REF_CHANGED_EVENT - - """ - Represents a 'base_ref_force_pushed' event on a given pull request. - """ - BASE_REF_FORCE_PUSHED_EVENT - - """ - Represents a 'closed' event on any `Closable`. - """ - CLOSED_EVENT - - """ - Represents a 'comment_deleted' event on a given issue or pull request. - """ - COMMENT_DELETED_EVENT - - """ - Represents a 'connected' event on a given issue or pull request. - """ - CONNECTED_EVENT - - """ - Represents a 'converted_note_to_issue' event on a given issue or pull request. - """ - CONVERTED_NOTE_TO_ISSUE_EVENT - - """ - Represents a 'convert_to_draft' event on a given pull request. - """ - CONVERT_TO_DRAFT_EVENT - - """ - Represents a mention made by one issue or pull request to another. - """ - CROSS_REFERENCED_EVENT - - """ - Represents a 'demilestoned' event on a given issue or pull request. - """ - DEMILESTONED_EVENT - - """ - Represents a 'deployed' event on a given pull request. - """ - DEPLOYED_EVENT - - """ - Represents a 'deployment_environment_changed' event on a given pull request. - """ - DEPLOYMENT_ENVIRONMENT_CHANGED_EVENT - - """ - Represents a 'disconnected' event on a given issue or pull request. - """ - DISCONNECTED_EVENT - - """ - Represents a 'head_ref_deleted' event on a given pull request. - """ - HEAD_REF_DELETED_EVENT - - """ - Represents a 'head_ref_force_pushed' event on a given pull request. - """ - HEAD_REF_FORCE_PUSHED_EVENT - - """ - Represents a 'head_ref_restored' event on a given pull request. - """ - HEAD_REF_RESTORED_EVENT - - """ - Represents a comment on an Issue. - """ - ISSUE_COMMENT - - """ - Represents a 'labeled' event on a given issue or pull request. - """ - LABELED_EVENT - - """ - Represents a 'locked' event on a given issue or pull request. - """ - LOCKED_EVENT - - """ - Represents a 'marked_as_duplicate' event on a given issue or pull request. - """ - MARKED_AS_DUPLICATE_EVENT - - """ - Represents a 'mentioned' event on a given issue or pull request. - """ - MENTIONED_EVENT - - """ - Represents a 'merged' event on a given pull request. - """ - MERGED_EVENT - - """ - Represents a 'milestoned' event on a given issue or pull request. - """ - MILESTONED_EVENT - - """ - Represents a 'moved_columns_in_project' event on a given issue or pull request. - """ - MOVED_COLUMNS_IN_PROJECT_EVENT - - """ - Represents a 'pinned' event on a given issue or pull request. - """ - PINNED_EVENT - - """ - Represents a Git commit part of a pull request. - """ - PULL_REQUEST_COMMIT - - """ - Represents a commit comment thread part of a pull request. - """ - PULL_REQUEST_COMMIT_COMMENT_THREAD - - """ - A review object for a given pull request. - """ - PULL_REQUEST_REVIEW - - """ - A threaded list of comments for a given pull request. - """ - PULL_REQUEST_REVIEW_THREAD - - """ - Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. - """ - PULL_REQUEST_REVISION_MARKER - - """ - Represents a 'ready_for_review' event on a given pull request. - """ - READY_FOR_REVIEW_EVENT - - """ - Represents a 'referenced' event on a given `ReferencedSubject`. - """ - REFERENCED_EVENT - - """ - Represents a 'removed_from_project' event on a given issue or pull request. - """ - REMOVED_FROM_PROJECT_EVENT - - """ - Represents a 'renamed' event on a given issue or pull request - """ - RENAMED_TITLE_EVENT - - """ - Represents a 'reopened' event on any `Closable`. - """ - REOPENED_EVENT - - """ - Represents a 'review_dismissed' event on a given issue or pull request. - """ - REVIEW_DISMISSED_EVENT - - """ - Represents an 'review_requested' event on a given pull request. - """ - REVIEW_REQUESTED_EVENT - - """ - Represents an 'review_request_removed' event on a given pull request. - """ - REVIEW_REQUEST_REMOVED_EVENT - - """ - Represents a 'subscribed' event on a given `Subscribable`. - """ - SUBSCRIBED_EVENT - - """ - Represents a 'transferred' event on a given issue or pull request. - """ - TRANSFERRED_EVENT - - """ - Represents an 'unassigned' event on any assignable object. - """ - UNASSIGNED_EVENT - - """ - Represents an 'unlabeled' event on a given issue or pull request. - """ - UNLABELED_EVENT - - """ - Represents an 'unlocked' event on a given issue or pull request. - """ - UNLOCKED_EVENT - - """ - Represents an 'unmarked_as_duplicate' event on a given issue or pull request. - """ - UNMARKED_AS_DUPLICATE_EVENT - - """ - Represents an 'unpinned' event on a given issue or pull request. - """ - UNPINNED_EVENT - - """ - Represents an 'unsubscribed' event on a given `Subscribable`. - """ - UNSUBSCRIBED_EVENT - - """ - Represents a 'user_blocked' event on a given user. - """ - USER_BLOCKED_EVENT -} - -""" -The possible target states when updating a pull request. -""" -enum PullRequestUpdateState { - """ - A pull request that has been closed without being merged. - """ - CLOSED - - """ - A pull request that is still open. - """ - OPEN -} - -""" -A Git push. -""" -type Push implements Node @preview(toggledBy: "antiope-preview") { - id: ID! - - """ - The SHA after the push - """ - nextSha: GitObjectID - - """ - The permalink for this push. - """ - permalink: URI! - - """ - The SHA before the push - """ - previousSha: GitObjectID - - """ - The user who pushed - """ - pusher: User! - - """ - The repository that was pushed to - """ - repository: Repository! -} - -""" -A team, user or app who has the ability to push to a protected branch. -""" -type PushAllowance implements Node { - """ - The actor that can push. - """ - actor: PushAllowanceActor - - """ - Identifies the branch protection rule associated with the allowed user or team. - """ - branchProtectionRule: BranchProtectionRule - id: ID! -} - -""" -Types that can be an actor. -""" -union PushAllowanceActor = App | Team | User - -""" -The connection type for PushAllowance. -""" -type PushAllowanceConnection { - """ - A list of edges. - """ - edges: [PushAllowanceEdge] - - """ - A list of nodes. - """ - nodes: [PushAllowance] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PushAllowanceEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PushAllowance -} - -""" -The query root of GitHub's GraphQL interface. -""" -type Query { - """ - Look up a code of conduct by its key - """ - codeOfConduct( - """ - The code of conduct's key - """ - key: String! - ): CodeOfConduct - - """ - Look up a code of conduct by its key - """ - codesOfConduct: [CodeOfConduct] - - """ - Look up an enterprise by URL slug. - """ - enterprise( - """ - The enterprise invitation token. - """ - invitationToken: String - - """ - The enterprise URL slug. - """ - slug: String! - ): Enterprise - - """ - Look up a pending enterprise administrator invitation by invitee, enterprise and role. - """ - enterpriseAdministratorInvitation( - """ - The slug of the enterprise the user was invited to join. - """ - enterpriseSlug: String! - - """ - The role for the business member invitation. - """ - role: EnterpriseAdministratorRole! - - """ - The login of the user invited to join the business. - """ - userLogin: String! - ): EnterpriseAdministratorInvitation - - """ - Look up a pending enterprise administrator invitation by invitation token. - """ - enterpriseAdministratorInvitationByToken( - """ - The invitation token sent with the invitation email. - """ - invitationToken: String! - ): EnterpriseAdministratorInvitation - - """ - Look up an open source license by its key - """ - license( - """ - The license's downcased SPDX ID - """ - key: String! - ): License - - """ - Return a list of known open source licenses - """ - licenses: [License]! - - """ - Get alphabetically sorted list of Marketplace categories - """ - marketplaceCategories( - """ - Exclude categories with no listings. - """ - excludeEmpty: Boolean - - """ - Returns top level categories only, excluding any subcategories. - """ - excludeSubcategories: Boolean - - """ - Return only the specified categories. - """ - includeCategories: [String!] - ): [MarketplaceCategory!]! - - """ - Look up a Marketplace category by its slug. - """ - marketplaceCategory( - """ - The URL slug of the category. - """ - slug: String! - - """ - Also check topic aliases for the category slug - """ - useTopicAliases: Boolean - ): MarketplaceCategory - - """ - Look up a single Marketplace listing - """ - marketplaceListing( - """ - Select the listing that matches this slug. It's the short name of the listing used in its URL. - """ - slug: String! - ): MarketplaceListing - - """ - Look up Marketplace listings - """ - marketplaceListings( - """ - Select listings that can be administered by the specified user. - """ - adminId: ID - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Select listings visible to the viewer even if they are not approved. If omitted or - false, only approved listings will be returned. - """ - allStates: Boolean - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Select only listings with the given category. - """ - categorySlug: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Select listings for products owned by the specified organization. - """ - organizationId: ID - - """ - Select only listings where the primary category matches the given category slug. - """ - primaryCategoryOnly: Boolean = false - - """ - Select the listings with these slugs, if they are visible to the viewer. - """ - slugs: [String] - - """ - Also check topic aliases for the category slug - """ - useTopicAliases: Boolean - - """ - Select listings to which user has admin access. If omitted, listings visible to the - viewer are returned. - """ - viewerCanAdmin: Boolean - - """ - Select only listings that offer a free trial. - """ - withFreeTrialsOnly: Boolean = false - ): MarketplaceListingConnection! - - """ - Return information about the GitHub instance - """ - meta: GitHubMetadata! - - """ - Fetches an object given its ID. - """ - node( - """ - ID of the object. - """ - id: ID! - ): Node - - """ - Lookup nodes by a list of IDs. - """ - nodes( - """ - The list of node IDs. - """ - ids: [ID!]! - ): [Node]! - - """ - Lookup a organization by login. - """ - organization( - """ - The organization's login. - """ - login: String! - ): Organization - - """ - The client's rate limit information. - """ - rateLimit( - """ - If true, calculate the cost for the query without evaluating it - """ - dryRun: Boolean = false - ): RateLimit - - """ - Hack to workaround https://github.com/facebook/relay/issues/112 re-exposing the root query object - """ - relay: Query! - - """ - Lookup a given repository by the owner and repository name. - """ - repository( - """ - The name of the repository - """ - name: String! - - """ - The login field of a user or organization - """ - owner: String! - ): Repository - - """ - Lookup a repository owner (ie. either a User or an Organization) by login. - """ - repositoryOwner( - """ - The username to lookup the owner by. - """ - login: String! - ): RepositoryOwner - - """ - Lookup resource by a URL. - """ - resource( - """ - The URL. - """ - url: URI! - ): UniformResourceLocatable - - """ - Perform a search across resources. - """ - search( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - The search string to look for. - """ - query: String! - - """ - The types of search items to search within. - """ - type: SearchType! - ): SearchResultItemConnection! - - """ - GitHub Security Advisories - """ - securityAdvisories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Filter advisories by identifier, e.g. GHSA or CVE. - """ - identifier: SecurityAdvisoryIdentifierFilter - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned topics. - """ - orderBy: SecurityAdvisoryOrder = {field: UPDATED_AT, direction: DESC} - - """ - Filter advisories to those published since a time in the past. - """ - publishedSince: DateTime - - """ - Filter advisories to those updated since a time in the past. - """ - updatedSince: DateTime - ): SecurityAdvisoryConnection! - - """ - Fetch a Security Advisory by its GHSA ID - """ - securityAdvisory( - """ - GitHub Security Advisory ID. - """ - ghsaId: String! - ): SecurityAdvisory - - """ - Software Vulnerabilities documented by GitHub Security Advisories - """ - securityVulnerabilities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - An ecosystem to filter vulnerabilities by. - """ - ecosystem: SecurityAdvisoryEcosystem - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned topics. - """ - orderBy: SecurityVulnerabilityOrder = {field: UPDATED_AT, direction: DESC} - - """ - A package name to filter vulnerabilities by. - """ - package: String - - """ - A list of severities to filter vulnerabilities by. - """ - severities: [SecurityAdvisorySeverity!] - ): SecurityVulnerabilityConnection! - - """ - Look up a single Sponsors Listing - """ - sponsorsListing( - """ - Select the Sponsors listing which matches this slug - """ - slug: String! - ): SponsorsListing @deprecated(reason: "`Query.sponsorsListing` will be removed. Use `Sponsorable.sponsorsListing` instead. Removal on 2020-04-01 UTC.") - - """ - Look up a topic by name. - """ - topic( - """ - The topic's name. - """ - name: String! - ): Topic - - """ - Lookup a user by login. - """ - user( - """ - The user's login. - """ - login: String! - ): User - - """ - The currently authenticated user. - """ - viewer: User! -} - -""" -Represents the client's rate limit. -""" -type RateLimit { - """ - The point cost for the current query counting against the rate limit. - """ - cost: Int! - - """ - The maximum number of points the client is permitted to consume in a 60 minute window. - """ - limit: Int! - - """ - The maximum number of nodes this query may return - """ - nodeCount: Int! - - """ - The number of points remaining in the current rate limit window. - """ - remaining: Int! - - """ - The time at which the current rate limit window resets in UTC epoch seconds. - """ - resetAt: DateTime! -} - -""" -Represents a subject that can be reacted on. -""" -interface Reactable { - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! -} - -""" -The connection type for User. -""" -type ReactingUserConnection { - """ - A list of edges. - """ - edges: [ReactingUserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user that's made a reaction. -""" -type ReactingUserEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: User! - - """ - The moment when the user made the reaction. - """ - reactedAt: DateTime! -} - -""" -An emoji reaction to a particular piece of content. -""" -type Reaction implements Node { - """ - Identifies the emoji reaction. - """ - content: ReactionContent! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The reactable piece of content - """ - reactable: Reactable! - - """ - Identifies the user who created this reaction. - """ - user: User -} - -""" -A list of reactions that have been left on the subject. -""" -type ReactionConnection { - """ - A list of edges. - """ - edges: [ReactionEdge] - - """ - A list of nodes. - """ - nodes: [Reaction] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Whether or not the authenticated user has left a reaction on the subject. - """ - viewerHasReacted: Boolean! -} - -""" -Emojis that can be attached to Issues, Pull Requests and Comments. -""" -enum ReactionContent { - """ - Represents the `:confused:` emoji. - """ - CONFUSED - - """ - Represents the `:eyes:` emoji. - """ - EYES - - """ - Represents the `:heart:` emoji. - """ - HEART - - """ - Represents the `:hooray:` emoji. - """ - HOORAY - - """ - Represents the `:laugh:` emoji. - """ - LAUGH - - """ - Represents the `:rocket:` emoji. - """ - ROCKET - - """ - Represents the `:-1:` emoji. - """ - THUMBS_DOWN - - """ - Represents the `:+1:` emoji. - """ - THUMBS_UP -} - -""" -An edge in a connection. -""" -type ReactionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Reaction -} - -""" -A group of emoji reactions to a particular piece of content. -""" -type ReactionGroup { - """ - Identifies the emoji reaction. - """ - content: ReactionContent! - - """ - Identifies when the reaction was created. - """ - createdAt: DateTime - - """ - The subject that was reacted to. - """ - subject: Reactable! - - """ - Users who have reacted to the reaction subject with the emotion represented by this reaction group - """ - users( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ReactingUserConnection! - - """ - Whether or not the authenticated user has left a reaction on the subject. - """ - viewerHasReacted: Boolean! -} - -""" -Ways in which lists of reactions can be ordered upon return. -""" -input ReactionOrder { - """ - The direction in which to order reactions by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order reactions by. - """ - field: ReactionOrderField! -} - -""" -A list of fields that reactions can be ordered by. -""" -enum ReactionOrderField { - """ - Allows ordering a list of reactions by when they were created. - """ - CREATED_AT -} - -""" -Represents a 'ready_for_review' event on a given pull request. -""" -type ReadyForReviewEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this ready for review event. - """ - resourcePath: URI! - - """ - The HTTP URL for this ready for review event. - """ - url: URI! -} - -""" -Represents a Git reference. -""" -type Ref implements Node { - """ - A list of pull requests with this ref as the head ref. - """ - associatedPullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - id: ID! - - """ - The ref name. - """ - name: String! - - """ - The ref's prefix, such as `refs/heads/` or `refs/tags/`. - """ - prefix: String! - - """ - The repository the ref belongs to. - """ - repository: Repository! - - """ - The object the ref points to. - - **Upcoming Change on 2019-07-01 UTC** - **Description:** Type for `target` will change from `GitObject!` to `GitObject`. - **Reason:** The `target` field may return `null` values and is changing to nullable - """ - target: GitObject! -} - -""" -The connection type for Ref. -""" -type RefConnection { - """ - A list of edges. - """ - edges: [RefEdge] - - """ - A list of nodes. - """ - nodes: [Ref] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RefEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Ref -} - -""" -Ways in which lists of git refs can be ordered upon return. -""" -input RefOrder { - """ - The direction in which to order refs by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order refs by. - """ - field: RefOrderField! -} - -""" -Properties by which ref connections can be ordered. -""" -enum RefOrderField { - """ - Order refs by their alphanumeric name - """ - ALPHABETICAL - - """ - Order refs by underlying commit date if the ref prefix is refs/tags/ - """ - TAG_COMMIT_DATE -} - -""" -A ref update -""" -input RefUpdate @preview(toggledBy: "update-refs-preview") { - """ - The value this ref should be updated to. - """ - afterOid: GitObjectID! - - """ - The value this ref needs to point to before the update. - """ - beforeOid: GitObjectID - - """ - Force a non fast-forward update. - """ - force: Boolean = false - - """ - The fully qualified name of the ref to be update. For example `refs/heads/branch-name` - """ - name: GitRefname! -} - -""" -Represents a 'referenced' event on a given `ReferencedSubject`. -""" -type ReferencedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the commit associated with the 'referenced' event. - """ - commit: Commit - - """ - Identifies the repository associated with the 'referenced' event. - """ - commitRepository: Repository! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reference originated in a different repository. - """ - isCrossRepository: Boolean! - - """ - Checks if the commit message itself references the subject. Can be false in the case of a commit comment reference. - """ - isDirectReference: Boolean! - - """ - Object referenced by event. - """ - subject: ReferencedSubject! -} - -""" -Any referencable object -""" -union ReferencedSubject = Issue | PullRequest - -""" -Autogenerated input type of RegenerateEnterpriseIdentityProviderRecoveryCodes -""" -input RegenerateEnterpriseIdentityProviderRecoveryCodesInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set an identity provider. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) -} - -""" -Autogenerated return type of RegenerateEnterpriseIdentityProviderRecoveryCodes -""" -type RegenerateEnterpriseIdentityProviderRecoveryCodesPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The identity provider for the enterprise. - """ - identityProvider: EnterpriseIdentityProvider -} - -""" -A release contains the content for a release. -""" -type Release implements Node & UniformResourceLocatable { - """ - The author of the release - """ - author: User - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The description of the release. - """ - description: String - - """ - The description of this release rendered to HTML. - """ - descriptionHTML: HTML - id: ID! - - """ - Whether or not the release is a draft - """ - isDraft: Boolean! - - """ - Whether or not the release is a prerelease - """ - isPrerelease: Boolean! - - """ - The title of the release. - """ - name: String - - """ - Identifies the date and time when the release was created. - """ - publishedAt: DateTime - - """ - List of releases assets which are dependent on this release. - """ - releaseAssets( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - A list of names to filter the assets by. - """ - name: String - ): ReleaseAssetConnection! - - """ - The HTTP path for this issue - """ - resourcePath: URI! - - """ - A description of the release, rendered to HTML without any links in it. - """ - shortDescriptionHTML( - """ - How many characters to return. - """ - limit: Int = 200 - ): HTML - - """ - The Git tag the release points to - """ - tag: Ref - - """ - The name of the release's Git tag - """ - tagName: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this issue - """ - url: URI! -} - -""" -A release asset contains the content for a release asset. -""" -type ReleaseAsset implements Node { - """ - The asset's content-type - """ - contentType: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The number of times this asset was downloaded - """ - downloadCount: Int! - - """ - Identifies the URL where you can download the release asset via the browser. - """ - downloadUrl: URI! - id: ID! - - """ - Identifies the title of the release asset. - """ - name: String! - - """ - Release that the asset is associated with - """ - release: Release - - """ - The size (in bytes) of the asset - """ - size: Int! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The user that performed the upload - """ - uploadedBy: User! - - """ - Identifies the URL of the release asset. - """ - url: URI! -} - -""" -The connection type for ReleaseAsset. -""" -type ReleaseAssetConnection { - """ - A list of edges. - """ - edges: [ReleaseAssetEdge] - - """ - A list of nodes. - """ - nodes: [ReleaseAsset] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReleaseAssetEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ReleaseAsset -} - -""" -The connection type for Release. -""" -type ReleaseConnection { - """ - A list of edges. - """ - edges: [ReleaseEdge] - - """ - A list of nodes. - """ - nodes: [Release] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReleaseEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Release -} - -""" -Ways in which lists of releases can be ordered upon return. -""" -input ReleaseOrder { - """ - The direction in which to order releases by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order releases by. - """ - field: ReleaseOrderField! -} - -""" -Properties by which release connections can be ordered. -""" -enum ReleaseOrderField { - """ - Order releases by creation time - """ - CREATED_AT - - """ - Order releases alphabetically by name - """ - NAME -} - -""" -Autogenerated input type of RemoveAssigneesFromAssignable -""" -input RemoveAssigneesFromAssignableInput { - """ - The id of the assignable object to remove assignees from. - """ - assignableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Assignable") - - """ - The id of users to remove as assignees. - """ - assigneeIds: [ID!]! @possibleTypes(concreteTypes: ["User"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of RemoveAssigneesFromAssignable -""" -type RemoveAssigneesFromAssignablePayload { - """ - The item that was unassigned. - """ - assignable: Assignable - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of RemoveEnterpriseAdmin -""" -input RemoveEnterpriseAdminInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Enterprise ID from which to remove the administrator. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The login of the user to remove as an administrator. - """ - login: String! -} - -""" -Autogenerated return type of RemoveEnterpriseAdmin -""" -type RemoveEnterpriseAdminPayload { - """ - The user who was removed as an administrator. - """ - admin: User - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated enterprise. - """ - enterprise: Enterprise - - """ - A message confirming the result of removing an administrator. - """ - message: String - - """ - The viewer performing the mutation. - """ - viewer: User -} - -""" -Autogenerated input type of RemoveEnterpriseIdentityProvider -""" -input RemoveEnterpriseIdentityProviderInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise from which to remove the identity provider. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) -} - -""" -Autogenerated return type of RemoveEnterpriseIdentityProvider -""" -type RemoveEnterpriseIdentityProviderPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The identity provider that was removed from the enterprise. - """ - identityProvider: EnterpriseIdentityProvider -} - -""" -Autogenerated input type of RemoveEnterpriseOrganization -""" -input RemoveEnterpriseOrganizationInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise from which the organization should be removed. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The ID of the organization to remove from the enterprise. - """ - organizationId: ID! @possibleTypes(concreteTypes: ["Organization"]) -} - -""" -Autogenerated return type of RemoveEnterpriseOrganization -""" -type RemoveEnterpriseOrganizationPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated enterprise. - """ - enterprise: Enterprise - - """ - The organization that was removed from the enterprise. - """ - organization: Organization - - """ - The viewer performing the mutation. - """ - viewer: User -} - -""" -Autogenerated input type of RemoveLabelsFromLabelable -""" -input RemoveLabelsFromLabelableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ids of labels to remove. - """ - labelIds: [ID!]! @possibleTypes(concreteTypes: ["Label"]) - - """ - The id of the Labelable to remove labels from. - """ - labelableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Labelable") -} - -""" -Autogenerated return type of RemoveLabelsFromLabelable -""" -type RemoveLabelsFromLabelablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Labelable the labels were removed from. - """ - labelable: Labelable -} - -""" -Autogenerated input type of RemoveOutsideCollaborator -""" -input RemoveOutsideCollaboratorInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the organization to remove the outside collaborator from. - """ - organizationId: ID! @possibleTypes(concreteTypes: ["Organization"]) - - """ - The ID of the outside collaborator to remove. - """ - userId: ID! @possibleTypes(concreteTypes: ["User"]) -} - -""" -Autogenerated return type of RemoveOutsideCollaborator -""" -type RemoveOutsideCollaboratorPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The user that was removed as an outside collaborator. - """ - removedUser: User -} - -""" -Autogenerated input type of RemoveReaction -""" -input RemoveReactionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the emoji reaction to remove. - """ - content: ReactionContent! - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! @possibleTypes(concreteTypes: ["CommitComment", "Issue", "IssueComment", "PullRequest", "PullRequestReview", "PullRequestReviewComment", "TeamDiscussion", "TeamDiscussionComment"], abstractType: "Reactable") -} - -""" -Autogenerated return type of RemoveReaction -""" -type RemoveReactionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The reaction object. - """ - reaction: Reaction - - """ - The reactable subject. - """ - subject: Reactable -} - -""" -Autogenerated input type of RemoveStar -""" -input RemoveStarInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Starrable ID to unstar. - """ - starrableId: ID! @possibleTypes(concreteTypes: ["Gist", "Repository", "Topic"], abstractType: "Starrable") -} - -""" -Autogenerated return type of RemoveStar -""" -type RemoveStarPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The starrable. - """ - starrable: Starrable -} - -""" -Represents a 'removed_from_project' event on a given issue or pull request. -""" -type RemovedFromProjectEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Project referenced by event. - """ - project: Project @preview(toggledBy: "starfox-preview") - - """ - Column name referenced by this project event. - """ - projectColumnName: String! @preview(toggledBy: "starfox-preview") -} - -""" -Represents a 'renamed' event on a given issue or pull request -""" -type RenamedTitleEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the current title of the issue or pull request. - """ - currentTitle: String! - id: ID! - - """ - Identifies the previous title of the issue or pull request. - """ - previousTitle: String! - - """ - Subject that was renamed. - """ - subject: RenamedTitleSubject! -} - -""" -An object which has a renamable title -""" -union RenamedTitleSubject = Issue | PullRequest - -""" -Autogenerated input type of ReopenIssue -""" -input ReopenIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue to be opened. - """ - issueId: ID! @possibleTypes(concreteTypes: ["Issue"]) -} - -""" -Autogenerated return type of ReopenIssue -""" -type ReopenIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was opened. - """ - issue: Issue -} - -""" -Autogenerated input type of ReopenPullRequest -""" -input ReopenPullRequestInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the pull request to be reopened. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) -} - -""" -Autogenerated return type of ReopenPullRequest -""" -type ReopenPullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that was reopened. - """ - pullRequest: PullRequest -} - -""" -Represents a 'reopened' event on any `Closable`. -""" -type ReopenedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Object that was reopened. - """ - closable: Closable! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! -} - -""" -Audit log entry for a repo.access event. -""" -type RepoAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoAccessAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoAccessAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.add_member event. -""" -type RepoAddMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoAddMemberAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoAddMemberAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.add_topic event. -""" -type RepoAddTopicAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TopicAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The name of the topic added to the repository - """ - topic: Topic - - """ - The name of the topic added to the repository - """ - topicName: String - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.archived event. -""" -type RepoArchivedAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoArchivedAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoArchivedAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.change_merge_setting event. -""" -type RepoChangeMergeSettingAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the change was to enable (true) or disable (false) the merge type - """ - isEnabled: Boolean - - """ - The merge method affected by the change - """ - mergeType: RepoChangeMergeSettingAuditEntryMergeType - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The merge options available for pull requests to this repository. -""" -enum RepoChangeMergeSettingAuditEntryMergeType { - """ - The pull request is added to the base branch in a merge commit. - """ - MERGE - - """ - Commits from the pull request are added onto the base branch individually without a merge commit. - """ - REBASE - - """ - The pull request's commits are squashed into a single commit before they are merged to the base branch. - """ - SQUASH -} - -""" -Audit log entry for a repo.config.disable_anonymous_git_access event. -""" -type RepoConfigDisableAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.disable_collaborators_only event. -""" -type RepoConfigDisableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.disable_contributors_only event. -""" -type RepoConfigDisableContributorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.disable_sockpuppet_disallowed event. -""" -type RepoConfigDisableSockpuppetDisallowedAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_anonymous_git_access event. -""" -type RepoConfigEnableAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_collaborators_only event. -""" -type RepoConfigEnableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_contributors_only event. -""" -type RepoConfigEnableContributorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_sockpuppet_disallowed event. -""" -type RepoConfigEnableSockpuppetDisallowedAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.lock_anonymous_git_access event. -""" -type RepoConfigLockAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.unlock_anonymous_git_access event. -""" -type RepoConfigUnlockAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.create event. -""" -type RepoCreateAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The name of the parent repository for this forked repository. - """ - forkParentName: String - - """ - The name of the root repository for this netork. - """ - forkSourceName: String - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoCreateAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoCreateAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.destroy event. -""" -type RepoDestroyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoDestroyAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoDestroyAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.remove_member event. -""" -type RepoRemoveMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoRemoveMemberAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoRemoveMemberAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.remove_topic event. -""" -type RepoRemoveTopicAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TopicAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The name of the topic added to the repository - """ - topic: Topic - - """ - The name of the topic added to the repository - """ - topicName: String - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The reasons a piece of content can be reported or minimized. -""" -enum ReportedContentClassifiers { - """ - An abusive or harassing piece of content - """ - ABUSE - - """ - A duplicated piece of content - """ - DUPLICATE - - """ - An irrelevant piece of content - """ - OFF_TOPIC - - """ - An outdated piece of content - """ - OUTDATED - - """ - The content has been resolved - """ - RESOLVED - - """ - A spammy piece of content - """ - SPAM -} - -""" -A repository contains the content for a project. -""" -type Repository implements Node & PackageOwner & ProjectOwner & RepositoryInfo & Starrable & Subscribable & UniformResourceLocatable { - """ - A list of users that can be assigned to issues in this repository. - """ - assignableUsers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filters users with query on user name and login - """ - query: String - ): UserConnection! - - """ - A list of branch protection rules for this repository. - """ - branchProtectionRules( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): BranchProtectionRuleConnection! - - """ - Returns the code of conduct for this repository - """ - codeOfConduct: CodeOfConduct - - """ - A list of collaborators associated with the repository. - """ - collaborators( - """ - Collaborators affiliation level with a repository. - """ - affiliation: CollaboratorAffiliation - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filters users with query on user name and login - """ - query: String - ): RepositoryCollaboratorConnection - - """ - A list of commit comments associated with the repository. - """ - commitComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The Ref associated with the repository's default branch. - """ - defaultBranchRef: Ref - - """ - Whether or not branches are automatically deleted when merged in this repository. - """ - deleteBranchOnMerge: Boolean! - - """ - A list of dependency manifests contained in the repository - """ - dependencyGraphManifests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Cursor to paginate dependencies - """ - dependenciesAfter: String - - """ - Number of dependencies to fetch - """ - dependenciesFirst: Int - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Flag to scope to only manifests with dependencies - """ - withDependencies: Boolean - ): DependencyGraphManifestConnection @preview(toggledBy: "hawkgirl-preview") - - """ - A list of deploy keys that are on this repository. - """ - deployKeys( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): DeployKeyConnection! - - """ - Deployments associated with the repository - """ - deployments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Environments to list deployments for - """ - environments: [String!] - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for deployments returned from the connection. - """ - orderBy: DeploymentOrder = {field: CREATED_AT, direction: ASC} - ): DeploymentConnection! - - """ - The description of the repository. - """ - description: String - - """ - The description of the repository rendered to HTML. - """ - descriptionHTML: HTML! - - """ - The number of kilobytes this repository occupies on disk. - """ - diskUsage: Int - - """ - Returns how many forks there are of this repository in the whole network. - """ - forkCount: Int! - - """ - A list of direct forked repositories. - """ - forks( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - The funding links for this repository - """ - fundingLinks: [FundingLink!]! - - """ - Indicates if the repository has issues feature enabled. - """ - hasIssuesEnabled: Boolean! - - """ - Indicates if the repository has the Projects feature enabled. - """ - hasProjectsEnabled: Boolean! - - """ - Indicates if the repository has wiki feature enabled. - """ - hasWikiEnabled: Boolean! - - """ - The repository's URL. - """ - homepageUrl: URI - id: ID! - - """ - Indicates if the repository is unmaintained. - """ - isArchived: Boolean! - - """ - Returns whether or not this repository disabled. - """ - isDisabled: Boolean! - - """ - Identifies if the repository is a fork. - """ - isFork: Boolean! - - """ - Indicates if the repository has been locked or not. - """ - isLocked: Boolean! - - """ - Identifies if the repository is a mirror. - """ - isMirror: Boolean! - - """ - Identifies if the repository is private. - """ - isPrivate: Boolean! - - """ - Identifies if the repository is a template that can be used to generate new repositories. - """ - isTemplate: Boolean! - - """ - Returns a single issue from the current repository by number. - """ - issue( - """ - The number for the issue to be returned. - """ - number: Int! - ): Issue - - """ - Returns a single issue-like object from the current repository by number. - """ - issueOrPullRequest( - """ - The number for the issue to be returned. - """ - number: Int! - ): IssueOrPullRequest - - """ - A list of issues that have been opened in the repository. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Returns a single label by name - """ - label( - """ - Label name - """ - name: String! - ): Label - - """ - A list of labels associated with the repository. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for labels returned from the connection. - """ - orderBy: LabelOrder = {field: CREATED_AT, direction: ASC} - - """ - If provided, searches labels by name and description. - """ - query: String - ): LabelConnection - - """ - A list containing a breakdown of the language composition of the repository. - """ - languages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: LanguageOrder - ): LanguageConnection - - """ - The license associated with the repository - """ - licenseInfo: License - - """ - The reason the repository has been locked. - """ - lockReason: RepositoryLockReason - - """ - A list of Users that can be mentioned in the context of the repository. - """ - mentionableUsers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filters users with query on user name and login - """ - query: String - ): UserConnection! - - """ - Whether or not PRs are merged with a merge commit on this repository. - """ - mergeCommitAllowed: Boolean! - - """ - Returns a single milestone from the current repository by number. - """ - milestone( - """ - The number for the milestone to be returned. - """ - number: Int! - ): Milestone - - """ - A list of milestones associated with the repository. - """ - milestones( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for milestones. - """ - orderBy: MilestoneOrder - - """ - Filter by the state of the milestones. - """ - states: [MilestoneState!] - ): MilestoneConnection - - """ - The repository's original mirror URL. - """ - mirrorUrl: URI - - """ - The name of the repository. - """ - name: String! - - """ - The repository's name with owner. - """ - nameWithOwner: String! - - """ - A Git object in the repository - """ - object( - """ - A Git revision expression suitable for rev-parse - """ - expression: String - - """ - The Git object ID - """ - oid: GitObjectID - ): GitObject - - """ - The image used to represent this repository in Open Graph data. - """ - openGraphImageUrl: URI! - - """ - The User owner of the repository. - """ - owner: RepositoryOwner! - - """ - A list of packages under the owner. - """ - packages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find packages by their names. - """ - names: [String] - - """ - Ordering of the returned packages. - """ - orderBy: PackageOrder = {field: CREATED_AT, direction: DESC} - - """ - Filter registry package by type. - """ - packageType: PackageType - - """ - Find packages in a repository by ID. - """ - repositoryId: ID - ): PackageConnection! - - """ - The repository parent, if this is a fork. - """ - parent: Repository - - """ - A list of pinned issues for this repository. - """ - pinnedIssues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PinnedIssueConnection @preview(toggledBy: "elektra-preview") - - """ - The primary language of the repository's code. - """ - primaryLanguage: Language - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing the repository's projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing the repository's projects - """ - projectsUrl: URI! - - """ - Returns a single pull request from the current repository by number. - """ - pullRequest( - """ - The number for the pull request to be returned. - """ - number: Int! - ): PullRequest - - """ - A list of pull requests that have been opened in the repository. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - Identifies when the repository was last pushed to. - """ - pushedAt: DateTime - - """ - Whether or not rebase-merging is enabled on this repository. - """ - rebaseMergeAllowed: Boolean! - - """ - Fetch a given ref from the repository - """ - ref( - """ - The ref to retrieve. Fully qualified matches are checked in order - (`refs/heads/master`) before falling back onto checks for short name matches (`master`). - """ - qualifiedName: String! - ): Ref - - """ - Fetch a list of refs from the repository - """ - refs( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - DEPRECATED: use orderBy. The ordering direction. - """ - direction: OrderDirection - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for refs returned from the connection. - """ - orderBy: RefOrder - - """ - Filters refs with query on name - """ - query: String - - """ - A ref name prefix like `refs/heads/`, `refs/tags/`, etc. - """ - refPrefix: String! - ): RefConnection - - """ - Lookup a single release given various criteria. - """ - release( - """ - The name of the Tag the Release was created from - """ - tagName: String! - ): Release - - """ - List of releases which are dependent on this repository. - """ - releases( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: ReleaseOrder - ): ReleaseConnection! - - """ - A list of applied repository-topic associations for this repository. - """ - repositoryTopics( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RepositoryTopicConnection! - - """ - The HTTP path for this repository - """ - resourcePath: URI! - - """ - A description of the repository, rendered to HTML without any links in it. - """ - shortDescriptionHTML( - """ - How many characters to return. - """ - limit: Int = 200 - ): HTML! - - """ - Whether or not squash-merging is enabled on this repository. - """ - squashMergeAllowed: Boolean! - - """ - The SSH URL to clone this repository - """ - sshUrl: GitSSHRemote! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Returns a list of all submodules in this repository parsed from the - .gitmodules file as of the default branch's HEAD commit. - """ - submodules( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): SubmoduleConnection! - - """ - Temporary authentication token for cloning this repository. - """ - tempCloneToken: String - - """ - The repository from which this repository was generated, if any. - """ - templateRepository: Repository - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this repository - """ - url: URI! - - """ - Whether this repository has a custom image to use with Open Graph as opposed to being represented by the owner's avatar. - """ - usesCustomOpenGraphImage: Boolean! - - """ - Indicates whether the viewer has admin permissions on this repository. - """ - viewerCanAdminister: Boolean! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Indicates whether the viewer can update the topics of this repository. - """ - viewerCanUpdateTopics: Boolean! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! - - """ - The users permission level on the repository. Will return null if authenticated as an GitHub App. - """ - viewerPermission: RepositoryPermission - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState - - """ - A list of vulnerability alerts that are on this repository. - """ - vulnerabilityAlerts( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RepositoryVulnerabilityAlertConnection - - """ - A list of users watching the repository. - """ - watchers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! -} - -""" -The affiliation of a user to a repository -""" -enum RepositoryAffiliation { - """ - Repositories that the user has been added to as a collaborator. - """ - COLLABORATOR - - """ - Repositories that the user has access to through being a member of an - organization. This includes every repository on every team that the user is on. - """ - ORGANIZATION_MEMBER - - """ - Repositories that are owned by the authenticated user. - """ - OWNER -} - -""" -Metadata for an audit entry with action repo.* -""" -interface RepositoryAuditEntryData { - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI -} - -""" -The connection type for User. -""" -type RepositoryCollaboratorConnection { - """ - A list of edges. - """ - edges: [RepositoryCollaboratorEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user who is a collaborator of a repository. -""" -type RepositoryCollaboratorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: User! - - """ - The permission the user has on the repository. - - **Upcoming Change on 2020-10-01 UTC** - **Description:** Type for `permission` will change from `RepositoryPermission!` to `String`. - **Reason:** This field may return additional values - """ - permission: RepositoryPermission! - - """ - A list of sources for the user's access to the repository. - """ - permissionSources: [PermissionSource!] -} - -""" -A list of repositories owned by the subject. -""" -type RepositoryConnection { - """ - A list of edges. - """ - edges: [RepositoryEdge] - - """ - A list of nodes. - """ - nodes: [Repository] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - The total size in kilobytes of all repositories in the connection. - """ - totalDiskUsage: Int! -} - -""" -The reason a repository is listed as 'contributed'. -""" -enum RepositoryContributionType { - """ - Created a commit - """ - COMMIT - - """ - Created an issue - """ - ISSUE - - """ - Created a pull request - """ - PULL_REQUEST - - """ - Reviewed a pull request - """ - PULL_REQUEST_REVIEW - - """ - Created the repository - """ - REPOSITORY -} - -""" -An edge in a connection. -""" -type RepositoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Repository -} - -""" -A subset of repository info. -""" -interface RepositoryInfo { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The description of the repository. - """ - description: String - - """ - The description of the repository rendered to HTML. - """ - descriptionHTML: HTML! - - """ - Returns how many forks there are of this repository in the whole network. - """ - forkCount: Int! - - """ - Indicates if the repository has issues feature enabled. - """ - hasIssuesEnabled: Boolean! - - """ - Indicates if the repository has the Projects feature enabled. - """ - hasProjectsEnabled: Boolean! - - """ - Indicates if the repository has wiki feature enabled. - """ - hasWikiEnabled: Boolean! - - """ - The repository's URL. - """ - homepageUrl: URI - - """ - Indicates if the repository is unmaintained. - """ - isArchived: Boolean! - - """ - Identifies if the repository is a fork. - """ - isFork: Boolean! - - """ - Indicates if the repository has been locked or not. - """ - isLocked: Boolean! - - """ - Identifies if the repository is a mirror. - """ - isMirror: Boolean! - - """ - Identifies if the repository is private. - """ - isPrivate: Boolean! - - """ - Identifies if the repository is a template that can be used to generate new repositories. - """ - isTemplate: Boolean! - - """ - The license associated with the repository - """ - licenseInfo: License - - """ - The reason the repository has been locked. - """ - lockReason: RepositoryLockReason - - """ - The repository's original mirror URL. - """ - mirrorUrl: URI - - """ - The name of the repository. - """ - name: String! - - """ - The repository's name with owner. - """ - nameWithOwner: String! - - """ - The image used to represent this repository in Open Graph data. - """ - openGraphImageUrl: URI! - - """ - The User owner of the repository. - """ - owner: RepositoryOwner! - - """ - Identifies when the repository was last pushed to. - """ - pushedAt: DateTime - - """ - The HTTP path for this repository - """ - resourcePath: URI! - - """ - A description of the repository, rendered to HTML without any links in it. - """ - shortDescriptionHTML( - """ - How many characters to return. - """ - limit: Int = 200 - ): HTML! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this repository - """ - url: URI! - - """ - Whether this repository has a custom image to use with Open Graph as opposed to being represented by the owner's avatar. - """ - usesCustomOpenGraphImage: Boolean! -} - -""" -An invitation for a user to be added to a repository. -""" -type RepositoryInvitation implements Node { - """ - The email address that received the invitation. - """ - email: String - id: ID! - - """ - The user who received the invitation. - """ - invitee: User - - """ - The user who created the invitation. - """ - inviter: User! - - """ - The permission granted on this repository by this invitation. - - **Upcoming Change on 2020-10-01 UTC** - **Description:** Type for `permission` will change from `RepositoryPermission!` to `String`. - **Reason:** This field may return additional values - """ - permission: RepositoryPermission! - - """ - The Repository the user is invited to. - """ - repository: RepositoryInfo -} - -""" -The connection type for RepositoryInvitation. -""" -type RepositoryInvitationConnection { - """ - A list of edges. - """ - edges: [RepositoryInvitationEdge] - - """ - A list of nodes. - """ - nodes: [RepositoryInvitation] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RepositoryInvitationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RepositoryInvitation -} - -""" -Ordering options for repository invitation connections. -""" -input RepositoryInvitationOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repository invitations by. - """ - field: RepositoryInvitationOrderField! -} - -""" -Properties by which repository invitation connections can be ordered. -""" -enum RepositoryInvitationOrderField { - """ - Order repository invitations by creation time - """ - CREATED_AT - - """ - Order repository invitations by invitee login - """ - INVITEE_LOGIN @deprecated(reason: "`INVITEE_LOGIN` is no longer a valid field value. Repository invitations can now be associated with an email, not only an invitee. Removal on 2020-10-01 UTC.") -} - -""" -The possible reasons a given repository could be in a locked state. -""" -enum RepositoryLockReason { - """ - The repository is locked due to a billing related reason. - """ - BILLING - - """ - The repository is locked due to a migration. - """ - MIGRATING - - """ - The repository is locked due to a move. - """ - MOVING - - """ - The repository is locked due to a rename. - """ - RENAME -} - -""" -Represents a object that belongs to a repository. -""" -interface RepositoryNode { - """ - The repository associated with this node. - """ - repository: Repository! -} - -""" -Ordering options for repository connections -""" -input RepositoryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repositories by. - """ - field: RepositoryOrderField! -} - -""" -Properties by which repository connections can be ordered. -""" -enum RepositoryOrderField { - """ - Order repositories by creation time - """ - CREATED_AT - - """ - Order repositories by name - """ - NAME - - """ - Order repositories by push time - """ - PUSHED_AT - - """ - Order repositories by number of stargazers - """ - STARGAZERS - - """ - Order repositories by update time - """ - UPDATED_AT -} - -""" -Represents an owner of a Repository. -""" -interface RepositoryOwner { - """ - A URL pointing to the owner's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - id: ID! - - """ - The username used to login. - """ - login: String! - - """ - A list of repositories that the user owns. - """ - repositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they are forks of another repository - """ - isFork: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Find Repository. - """ - repository( - """ - Name of Repository to find. - """ - name: String! - ): Repository - - """ - The HTTP URL for the owner. - """ - resourcePath: URI! - - """ - The HTTP URL for the owner. - """ - url: URI! -} - -""" -The access level to a repository -""" -enum RepositoryPermission { - """ - Can read, clone, and push to this repository. Can also manage issues, pull - requests, and repository settings, including adding collaborators - """ - ADMIN - - """ - Can read, clone, and push to this repository. They can also manage issues, pull requests, and some repository settings - """ - MAINTAIN - - """ - Can read and clone this repository. Can also open and comment on issues and pull requests - """ - READ - - """ - Can read and clone this repository. Can also manage issues and pull requests - """ - TRIAGE - - """ - Can read, clone, and push to this repository. Can also manage issues and pull requests - """ - WRITE -} - -""" -The privacy of a repository -""" -enum RepositoryPrivacy { - """ - Private - """ - PRIVATE - - """ - Public - """ - PUBLIC -} - -""" -A repository-topic connects a repository to a topic. -""" -type RepositoryTopic implements Node & UniformResourceLocatable { - id: ID! - - """ - The HTTP path for this repository-topic. - """ - resourcePath: URI! - - """ - The topic. - """ - topic: Topic! - - """ - The HTTP URL for this repository-topic. - """ - url: URI! -} - -""" -The connection type for RepositoryTopic. -""" -type RepositoryTopicConnection { - """ - A list of edges. - """ - edges: [RepositoryTopicEdge] - - """ - A list of nodes. - """ - nodes: [RepositoryTopic] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RepositoryTopicEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RepositoryTopic -} - -""" -The repository's visibility level. -""" -enum RepositoryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repository_visibility_change.disable event. -""" -type RepositoryVisibilityChangeDisableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repository_visibility_change.enable event. -""" -type RepositoryVisibilityChangeEnableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -A alert for a repository with an affected vulnerability. -""" -type RepositoryVulnerabilityAlert implements Node & RepositoryNode { - """ - When was the alert created? - """ - createdAt: DateTime! - - """ - The reason the alert was dismissed - """ - dismissReason: String - - """ - When was the alert dimissed? - """ - dismissedAt: DateTime - - """ - The user who dismissed the alert - """ - dismisser: User - id: ID! - - """ - The associated repository - """ - repository: Repository! - - """ - The associated security advisory - """ - securityAdvisory: SecurityAdvisory - - """ - The associated security vulnerablity - """ - securityVulnerability: SecurityVulnerability - - """ - The vulnerable manifest filename - """ - vulnerableManifestFilename: String! - - """ - The vulnerable manifest path - """ - vulnerableManifestPath: String! - - """ - The vulnerable requirements - """ - vulnerableRequirements: String -} - -""" -The connection type for RepositoryVulnerabilityAlert. -""" -type RepositoryVulnerabilityAlertConnection { - """ - A list of edges. - """ - edges: [RepositoryVulnerabilityAlertEdge] - - """ - A list of nodes. - """ - nodes: [RepositoryVulnerabilityAlert] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RepositoryVulnerabilityAlertEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RepositoryVulnerabilityAlert -} - -""" -Autogenerated input type of RequestReviews -""" -input RequestReviewsInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pull request to modify. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) - - """ - The Node IDs of the team to request. - """ - teamIds: [ID!] @possibleTypes(concreteTypes: ["Team"]) - - """ - Add users to the set rather than replace. - """ - union: Boolean - - """ - The Node IDs of the user to request. - """ - userIds: [ID!] @possibleTypes(concreteTypes: ["User"]) -} - -""" -Autogenerated return type of RequestReviews -""" -type RequestReviewsPayload { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that is getting requests. - """ - pullRequest: PullRequest - - """ - The edge from the pull request to the requested reviewers. - """ - requestedReviewersEdge: UserEdge -} - -""" -The possible states that can be requested when creating a check run. -""" -enum RequestableCheckStatusState @preview(toggledBy: "antiope-preview") { - """ - The check suite or run has been completed. - """ - COMPLETED - - """ - The check suite or run is in progress. - """ - IN_PROGRESS - - """ - The check suite or run has been queued. - """ - QUEUED -} - -""" -Types that can be requested reviewers. -""" -union RequestedReviewer = Mannequin | Team | User - -""" -Autogenerated input type of RerequestCheckSuite -""" -input RerequestCheckSuiteInput @preview(toggledBy: "antiope-preview") { - """ - The Node ID of the check suite. - """ - checkSuiteId: ID! @possibleTypes(concreteTypes: ["CheckSuite"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of RerequestCheckSuite -""" -type RerequestCheckSuitePayload @preview(toggledBy: "antiope-preview") { - """ - The requested check suite. - """ - checkSuite: CheckSuite - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of ResolveReviewThread -""" -input ResolveReviewThreadInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the thread to resolve - """ - threadId: ID! @possibleTypes(concreteTypes: ["PullRequestReviewThread"]) -} - -""" -Autogenerated return type of ResolveReviewThread -""" -type ResolveReviewThreadPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The thread to resolve. - """ - thread: PullRequestReviewThread -} - -""" -Represents a private contribution a user made on GitHub. -""" -type RestrictedContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -A team or user who has the ability to dismiss a review on a protected branch. -""" -type ReviewDismissalAllowance implements Node { - """ - The actor that can dismiss. - """ - actor: ReviewDismissalAllowanceActor - - """ - Identifies the branch protection rule associated with the allowed user or team. - """ - branchProtectionRule: BranchProtectionRule - id: ID! -} - -""" -Types that can be an actor. -""" -union ReviewDismissalAllowanceActor = Team | User - -""" -The connection type for ReviewDismissalAllowance. -""" -type ReviewDismissalAllowanceConnection { - """ - A list of edges. - """ - edges: [ReviewDismissalAllowanceEdge] - - """ - A list of nodes. - """ - nodes: [ReviewDismissalAllowance] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReviewDismissalAllowanceEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ReviewDismissalAllowance -} - -""" -Represents a 'review_dismissed' event on a given issue or pull request. -""" -type ReviewDismissedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - Identifies the optional message associated with the 'review_dismissed' event. - """ - dismissalMessage: String - - """ - Identifies the optional message associated with the event, rendered to HTML. - """ - dismissalMessageHTML: String - id: ID! - - """ - Identifies the previous state of the review with the 'review_dismissed' event. - """ - previousReviewState: PullRequestReviewState! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the commit which caused the review to become stale. - """ - pullRequestCommit: PullRequestCommit - - """ - The HTTP path for this review dismissed event. - """ - resourcePath: URI! - - """ - Identifies the review associated with the 'review_dismissed' event. - """ - review: PullRequestReview - - """ - The HTTP URL for this review dismissed event. - """ - url: URI! -} - -""" -A request for a user to review a pull request. -""" -type ReviewRequest implements Node { - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Identifies the pull request associated with this review request. - """ - pullRequest: PullRequest! - - """ - The reviewer that is requested. - """ - requestedReviewer: RequestedReviewer -} - -""" -The connection type for ReviewRequest. -""" -type ReviewRequestConnection { - """ - A list of edges. - """ - edges: [ReviewRequestEdge] - - """ - A list of nodes. - """ - nodes: [ReviewRequest] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReviewRequestEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ReviewRequest -} - -""" -Represents an 'review_request_removed' event on a given pull request. -""" -type ReviewRequestRemovedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the reviewer whose review request was removed. - """ - requestedReviewer: RequestedReviewer -} - -""" -Represents an 'review_requested' event on a given pull request. -""" -type ReviewRequestedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the reviewer whose review was requested. - """ - requestedReviewer: RequestedReviewer -} - -""" -A hovercard context with a message describing the current code review state of the pull -request. -""" -type ReviewStatusHovercardContext implements HovercardContext { - """ - A string describing this context - """ - message: String! - - """ - An octicon to accompany this context - """ - octicon: String! - - """ - The current status of the pull request with respect to code review. - """ - reviewDecision: PullRequestReviewDecision -} - -""" -The possible digest algorithms used to sign SAML requests for an identity provider. -""" -enum SamlDigestAlgorithm { - """ - SHA1 - """ - SHA1 - - """ - SHA256 - """ - SHA256 - - """ - SHA384 - """ - SHA384 - - """ - SHA512 - """ - SHA512 -} - -""" -The possible signature algorithms used to sign SAML requests for a Identity Provider. -""" -enum SamlSignatureAlgorithm { - """ - RSA-SHA1 - """ - RSA_SHA1 - - """ - RSA-SHA256 - """ - RSA_SHA256 - - """ - RSA-SHA384 - """ - RSA_SHA384 - - """ - RSA-SHA512 - """ - RSA_SHA512 -} - -""" -A Saved Reply is text a user can use to reply quickly. -""" -type SavedReply implements Node { - """ - The body of the saved reply. - """ - body: String! - - """ - The saved reply body rendered to HTML. - """ - bodyHTML: HTML! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The title of the saved reply. - """ - title: String! - - """ - The user that saved this reply. - """ - user: Actor -} - -""" -The connection type for SavedReply. -""" -type SavedReplyConnection { - """ - A list of edges. - """ - edges: [SavedReplyEdge] - - """ - A list of nodes. - """ - nodes: [SavedReply] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SavedReplyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SavedReply -} - -""" -Ordering options for saved reply connections. -""" -input SavedReplyOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order saved replies by. - """ - field: SavedReplyOrderField! -} - -""" -Properties by which saved reply connections can be ordered. -""" -enum SavedReplyOrderField { - """ - Order saved reply by when they were updated. - """ - UPDATED_AT -} - -""" -The results of a search. -""" -union SearchResultItem = App | Issue | MarketplaceListing | Organization | PullRequest | Repository | User - -""" -A list of results that matched against a search query. -""" -type SearchResultItemConnection { - """ - The number of pieces of code that matched the search query. - """ - codeCount: Int! - - """ - A list of edges. - """ - edges: [SearchResultItemEdge] - - """ - The number of issues that matched the search query. - """ - issueCount: Int! - - """ - A list of nodes. - """ - nodes: [SearchResultItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - The number of repositories that matched the search query. - """ - repositoryCount: Int! - - """ - The number of users that matched the search query. - """ - userCount: Int! - - """ - The number of wiki pages that matched the search query. - """ - wikiCount: Int! -} - -""" -An edge in a connection. -""" -type SearchResultItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SearchResultItem - - """ - Text matches on the result found. - """ - textMatches: [TextMatch] -} - -""" -Represents the individual results of a search. -""" -enum SearchType { - """ - Returns results matching issues in repositories. - """ - ISSUE - - """ - Returns results matching repositories. - """ - REPOSITORY - - """ - Returns results matching users and organizations on GitHub. - """ - USER -} - -""" -A GitHub Security Advisory -""" -type SecurityAdvisory implements Node { - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - This is a long plaintext description of the advisory - """ - description: String! - - """ - The GitHub Security Advisory ID - """ - ghsaId: String! - id: ID! - - """ - A list of identifiers for this advisory - """ - identifiers: [SecurityAdvisoryIdentifier!]! - - """ - The organization that originated the advisory - """ - origin: String! - - """ - The permalink for the advisory - """ - permalink: URI - - """ - When the advisory was published - """ - publishedAt: DateTime! - - """ - A list of references for this advisory - """ - references: [SecurityAdvisoryReference!]! - - """ - The severity of the advisory - """ - severity: SecurityAdvisorySeverity! - - """ - A short plaintext summary of the advisory - """ - summary: String! - - """ - When the advisory was last updated - """ - updatedAt: DateTime! - - """ - Vulnerabilities associated with this Advisory - """ - vulnerabilities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - An ecosystem to filter vulnerabilities by. - """ - ecosystem: SecurityAdvisoryEcosystem - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned topics. - """ - orderBy: SecurityVulnerabilityOrder = {field: UPDATED_AT, direction: DESC} - - """ - A package name to filter vulnerabilities by. - """ - package: String - - """ - A list of severities to filter vulnerabilities by. - """ - severities: [SecurityAdvisorySeverity!] - ): SecurityVulnerabilityConnection! - - """ - When the advisory was withdrawn, if it has been withdrawn - """ - withdrawnAt: DateTime -} - -""" -The connection type for SecurityAdvisory. -""" -type SecurityAdvisoryConnection { - """ - A list of edges. - """ - edges: [SecurityAdvisoryEdge] - - """ - A list of nodes. - """ - nodes: [SecurityAdvisory] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -The possible ecosystems of a security vulnerability's package. -""" -enum SecurityAdvisoryEcosystem { - """ - PHP packages hosted at packagist.org - """ - COMPOSER - - """ - Java artifacts hosted at the Maven central repository - """ - MAVEN - - """ - JavaScript packages hosted at npmjs.com - """ - NPM - - """ - .NET packages hosted at the NuGet Gallery - """ - NUGET - - """ - Python packages hosted at PyPI.org - """ - PIP - - """ - Ruby gems hosted at RubyGems.org - """ - RUBYGEMS -} - -""" -An edge in a connection. -""" -type SecurityAdvisoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SecurityAdvisory -} - -""" -A GitHub Security Advisory Identifier -""" -type SecurityAdvisoryIdentifier { - """ - The identifier type, e.g. GHSA, CVE - """ - type: String! - - """ - The identifier - """ - value: String! -} - -""" -An advisory identifier to filter results on. -""" -input SecurityAdvisoryIdentifierFilter { - """ - The identifier type. - """ - type: SecurityAdvisoryIdentifierType! - - """ - The identifier string. Supports exact or partial matching. - """ - value: String! -} - -""" -Identifier formats available for advisories. -""" -enum SecurityAdvisoryIdentifierType { - """ - Common Vulnerabilities and Exposures Identifier. - """ - CVE - - """ - GitHub Security Advisory ID. - """ - GHSA -} - -""" -Ordering options for security advisory connections -""" -input SecurityAdvisoryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order security advisories by. - """ - field: SecurityAdvisoryOrderField! -} - -""" -Properties by which security advisory connections can be ordered. -""" -enum SecurityAdvisoryOrderField { - """ - Order advisories by publication time - """ - PUBLISHED_AT - - """ - Order advisories by update time - """ - UPDATED_AT -} - -""" -An individual package -""" -type SecurityAdvisoryPackage { - """ - The ecosystem the package belongs to, e.g. RUBYGEMS, NPM - """ - ecosystem: SecurityAdvisoryEcosystem! - - """ - The package name - """ - name: String! -} - -""" -An individual package version -""" -type SecurityAdvisoryPackageVersion { - """ - The package name or version - """ - identifier: String! -} - -""" -A GitHub Security Advisory Reference -""" -type SecurityAdvisoryReference { - """ - A publicly accessible reference - """ - url: URI! -} - -""" -Severity of the vulnerability. -""" -enum SecurityAdvisorySeverity { - """ - Critical. - """ - CRITICAL - - """ - High. - """ - HIGH - - """ - Low. - """ - LOW - - """ - Moderate. - """ - MODERATE -} - -""" -An individual vulnerability within an Advisory -""" -type SecurityVulnerability { - """ - The Advisory associated with this Vulnerability - """ - advisory: SecurityAdvisory! - - """ - The first version containing a fix for the vulnerability - """ - firstPatchedVersion: SecurityAdvisoryPackageVersion - - """ - A description of the vulnerable package - """ - package: SecurityAdvisoryPackage! - - """ - The severity of the vulnerability within this package - """ - severity: SecurityAdvisorySeverity! - - """ - When the vulnerability was last updated - """ - updatedAt: DateTime! - - """ - A string that describes the vulnerable package versions. - This string follows a basic syntax with a few forms. - + `= 0.2.0` denotes a single vulnerable version. - + `<= 1.0.8` denotes a version range up to and including the specified version - + `< 0.1.11` denotes a version range up to, but excluding, the specified version - + `>= 4.3.0, < 4.3.5` denotes a version range with a known minimum and maximum version. - + `>= 0.0.1` denotes a version range with a known minimum, but no known maximum - """ - vulnerableVersionRange: String! -} - -""" -The connection type for SecurityVulnerability. -""" -type SecurityVulnerabilityConnection { - """ - A list of edges. - """ - edges: [SecurityVulnerabilityEdge] - - """ - A list of nodes. - """ - nodes: [SecurityVulnerability] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SecurityVulnerabilityEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SecurityVulnerability -} - -""" -Ordering options for security vulnerability connections -""" -input SecurityVulnerabilityOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order security vulnerabilities by. - """ - field: SecurityVulnerabilityOrderField! -} - -""" -Properties by which security vulnerability connections can be ordered. -""" -enum SecurityVulnerabilityOrderField { - """ - Order vulnerability by update time - """ - UPDATED_AT -} - -""" -Autogenerated input type of SetEnterpriseIdentityProvider -""" -input SetEnterpriseIdentityProviderInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The digest algorithm used to sign SAML requests for the identity provider. - """ - digestMethod: SamlDigestAlgorithm! - - """ - The ID of the enterprise on which to set an identity provider. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The x509 certificate used by the identity provider to sign assertions and responses. - """ - idpCertificate: String! - - """ - The Issuer Entity ID for the SAML identity provider - """ - issuer: String - - """ - The signature algorithm used to sign SAML requests for the identity provider. - """ - signatureMethod: SamlSignatureAlgorithm! - - """ - The URL endpoint for the identity provider's SAML SSO. - """ - ssoUrl: URI! -} - -""" -Autogenerated return type of SetEnterpriseIdentityProvider -""" -type SetEnterpriseIdentityProviderPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The identity provider for the enterprise. - """ - identityProvider: EnterpriseIdentityProvider -} - -""" -Represents an S/MIME signature on a Commit or Tag. -""" -type SmimeSignature implements GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -Entites that can sponsor others via GitHub Sponsors -""" -union Sponsor = Organization | User - -""" -Entities that can be sponsored through GitHub Sponsors -""" -interface Sponsorable { - """ - The GitHub Sponsors listing for this user. - """ - sponsorsListing: SponsorsListing - - """ - This object's sponsorships as the maintainer. - """ - sponsorshipsAsMaintainer( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether or not to include private sponsorships in the result set - """ - includePrivate: Boolean = false - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - This object's sponsorships as the sponsor. - """ - sponsorshipsAsSponsor( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! -} - -""" -A GitHub Sponsors listing. -""" -type SponsorsListing implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The full description of the listing. - """ - fullDescription: String! - - """ - The full description of the listing rendered to HTML. - """ - fullDescriptionHTML: HTML! - id: ID! - - """ - The listing's full name. - """ - name: String! - - """ - The short description of the listing. - """ - shortDescription: String! - - """ - The short name of the listing. - """ - slug: String! - - """ - The published tiers for this GitHub Sponsors listing. - """ - tiers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for Sponsors tiers returned from the connection. - """ - orderBy: SponsorsTierOrder = {field: MONTHLY_PRICE_IN_CENTS, direction: ASC} - ): SponsorsTierConnection -} - -""" -A GitHub Sponsors tier associated with a GitHub Sponsors listing. -""" -type SponsorsTier implements Node { - """ - SponsorsTier information only visible to users that can administer the associated Sponsors listing. - """ - adminInfo: SponsorsTierAdminInfo - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The description of the tier. - """ - description: String! - - """ - The tier description rendered to HTML - """ - descriptionHTML: HTML! - id: ID! - - """ - How much this tier costs per month in cents. - """ - monthlyPriceInCents: Int! - - """ - How much this tier costs per month in dollars. - """ - monthlyPriceInDollars: Int! - - """ - The name of the tier. - """ - name: String! - - """ - The sponsors listing that this tier belongs to. - """ - sponsorsListing: SponsorsListing! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -SponsorsTier information only visible to users that can administer the associated Sponsors listing. -""" -type SponsorsTierAdminInfo { - """ - The sponsorships associated with this tier. - """ - sponsorships( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether or not to include private sponsorships in the result set - """ - includePrivate: Boolean = false - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! -} - -""" -The connection type for SponsorsTier. -""" -type SponsorsTierConnection { - """ - A list of edges. - """ - edges: [SponsorsTierEdge] - - """ - A list of nodes. - """ - nodes: [SponsorsTier] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SponsorsTierEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SponsorsTier -} - -""" -Ordering options for Sponsors tiers connections. -""" -input SponsorsTierOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order tiers by. - """ - field: SponsorsTierOrderField! -} - -""" -Properties by which Sponsors tiers connections can be ordered. -""" -enum SponsorsTierOrderField { - """ - Order tiers by creation time. - """ - CREATED_AT - - """ - Order tiers by their monthly price in cents - """ - MONTHLY_PRICE_IN_CENTS -} - -""" -A sponsorship relationship between a sponsor and a maintainer -""" -type Sponsorship implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The entity that is being sponsored - """ - maintainer: User! @deprecated(reason: "`Sponsorship.maintainer` will be removed. Use `Sponsorship.sponsorable` instead. Removal on 2020-04-01 UTC.") - - """ - The privacy level for this sponsorship. - """ - privacyLevel: SponsorshipPrivacy! - - """ - The user that is sponsoring. Returns null if the sponsorship is private or if sponsor is not a user. - """ - sponsor: User @deprecated(reason: "`Sponsorship.sponsor` will be removed. Use `Sponsorship.sponsorEntity` instead. Removal on 2020-10-01 UTC.") - - """ - The user or organization that is sponsoring. Returns null if the sponsorship is private. - """ - sponsorEntity: Sponsor - - """ - The entity that is being sponsored - """ - sponsorable: Sponsorable! - - """ - The associated sponsorship tier - """ - tier: SponsorsTier -} - -""" -The connection type for Sponsorship. -""" -type SponsorshipConnection { - """ - A list of edges. - """ - edges: [SponsorshipEdge] - - """ - A list of nodes. - """ - nodes: [Sponsorship] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SponsorshipEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Sponsorship -} - -""" -Ordering options for sponsorship connections. -""" -input SponsorshipOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order sponsorship by. - """ - field: SponsorshipOrderField! -} - -""" -Properties by which sponsorship connections can be ordered. -""" -enum SponsorshipOrderField { - """ - Order sponsorship by creation time. - """ - CREATED_AT -} - -""" -The privacy of a sponsorship -""" -enum SponsorshipPrivacy { - """ - Private - """ - PRIVATE - - """ - Public - """ - PUBLIC -} - -""" -Ways in which star connections can be ordered. -""" -input StarOrder { - """ - The direction in which to order nodes. - """ - direction: OrderDirection! - - """ - The field in which to order nodes by. - """ - field: StarOrderField! -} - -""" -Properties by which star connections can be ordered. -""" -enum StarOrderField { - """ - Allows ordering a list of stars by when they were created. - """ - STARRED_AT -} - -""" -The connection type for User. -""" -type StargazerConnection { - """ - A list of edges. - """ - edges: [StargazerEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user that's starred a repository. -""" -type StargazerEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: User! - - """ - Identifies when the item was starred. - """ - starredAt: DateTime! -} - -""" -Things that can be starred. -""" -interface Starrable { - id: ID! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! -} - -""" -The connection type for Repository. -""" -type StarredRepositoryConnection { - """ - A list of edges. - """ - edges: [StarredRepositoryEdge] - - """ - Is the list of stars for this user truncated? This is true for users that have many stars. - """ - isOverLimit: Boolean! - - """ - A list of nodes. - """ - nodes: [Repository] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a starred repository. -""" -type StarredRepositoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: Repository! - - """ - Identifies when the item was starred. - """ - starredAt: DateTime! -} - -""" -Represents a commit status. -""" -type Status implements Node { - """ - The commit this status is attached to. - """ - commit: Commit - - """ - Looks up an individual status context by context name. - """ - context( - """ - The context name. - """ - name: String! - ): StatusContext - - """ - The individual status contexts for this commit. - """ - contexts: [StatusContext!]! - id: ID! - - """ - The combined commit status. - """ - state: StatusState! -} - -""" -Represents the rollup for both the check runs and status for a commit. -""" -type StatusCheckRollup implements Node { - """ - The commit the status and check runs are attached to. - """ - commit: Commit - - """ - A list of status contexts and check runs for this commit. - """ - contexts( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): StatusCheckRollupContextConnection! - id: ID! - - """ - The combined status for the commit. - """ - state: StatusState! -} - -""" -Types that can be inside a StatusCheckRollup context. -""" -union StatusCheckRollupContext = CheckRun | StatusContext - -""" -The connection type for StatusCheckRollupContext. -""" -type StatusCheckRollupContextConnection { - """ - A list of edges. - """ - edges: [StatusCheckRollupContextEdge] - - """ - A list of nodes. - """ - nodes: [StatusCheckRollupContext] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type StatusCheckRollupContextEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: StatusCheckRollupContext -} - -""" -Represents an individual commit status context -""" -type StatusContext implements Node { - """ - The avatar of the OAuth application or the user that created the status - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int = 40 - ): URI - - """ - This commit this status context is attached to. - """ - commit: Commit - - """ - The name of this status context. - """ - context: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The actor who created this status context. - """ - creator: Actor - - """ - The description for this status context. - """ - description: String - id: ID! - - """ - The state of this status context. - """ - state: StatusState! - - """ - The URL for this status context. - """ - targetUrl: URI -} - -""" -The possible commit status states. -""" -enum StatusState { - """ - Status is errored. - """ - ERROR - - """ - Status is expected. - """ - EXPECTED - - """ - Status is failing. - """ - FAILURE - - """ - Status is pending. - """ - PENDING - - """ - Status is successful. - """ - SUCCESS -} - -""" -Autogenerated input type of SubmitPullRequestReview -""" -input SubmitPullRequestReviewInput { - """ - The text field to set on the Pull Request Review. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The event to send to the Pull Request Review. - """ - event: PullRequestReviewEvent! - - """ - The Pull Request ID to submit any pending reviews. - """ - pullRequestId: ID @possibleTypes(concreteTypes: ["PullRequest"]) - - """ - The Pull Request Review ID to submit. - """ - pullRequestReviewId: ID @possibleTypes(concreteTypes: ["PullRequestReview"]) -} - -""" -Autogenerated return type of SubmitPullRequestReview -""" -type SubmitPullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The submitted pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -A pointer to a repository at a specific revision embedded inside another repository. -""" -type Submodule { - """ - The branch of the upstream submodule for tracking updates - """ - branch: String - - """ - The git URL of the submodule repository - """ - gitUrl: URI! - - """ - The name of the submodule in .gitmodules - """ - name: String! - - """ - The path in the superproject that this submodule is located in - """ - path: String! - - """ - The commit revision of the subproject repository being tracked by the submodule - """ - subprojectCommitOid: GitObjectID -} - -""" -The connection type for Submodule. -""" -type SubmoduleConnection { - """ - A list of edges. - """ - edges: [SubmoduleEdge] - - """ - A list of nodes. - """ - nodes: [Submodule] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SubmoduleEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Submodule -} - -""" -Entities that can be subscribed to for web and email notifications. -""" -interface Subscribable { - id: ID! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -Represents a 'subscribed' event on a given `Subscribable`. -""" -type SubscribedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Object referenced by event. - """ - subscribable: Subscribable! -} - -""" -The possible states of a subscription. -""" -enum SubscriptionState { - """ - The User is never notified. - """ - IGNORED - - """ - The User is notified of all conversations. - """ - SUBSCRIBED - - """ - The User is only notified when participating or @mentioned. - """ - UNSUBSCRIBED -} - -""" -A suggestion to review a pull request based on a user's commit history and review comments. -""" -type SuggestedReviewer { - """ - Is this suggestion based on past commits? - """ - isAuthor: Boolean! - - """ - Is this suggestion based on past review comments? - """ - isCommenter: Boolean! - - """ - Identifies the user suggested to review the pull request. - """ - reviewer: User! -} - -""" -Represents a Git tag. -""" -type Tag implements GitObject & Node { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - id: ID! - - """ - The Git tag message. - """ - message: String - - """ - The Git tag name. - """ - name: String! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! - - """ - Details about the tag author. - """ - tagger: GitActor - - """ - The Git object the tag points to. - """ - target: GitObject! -} - -""" -A team of users in an organization. -""" -type Team implements MemberStatusable & Node & Subscribable { - """ - A list of teams that are ancestors of this team. - """ - ancestors( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): TeamConnection! - - """ - A URL pointing to the team's avatar. - """ - avatarUrl( - """ - The size in pixels of the resulting square image. - """ - size: Int = 400 - ): URI - - """ - List of child teams belonging to this team - """ - childTeams( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether to list immediate child teams or all descendant child teams. - """ - immediateOnly: Boolean = true - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: TeamOrder - - """ - User logins to filter by - """ - userLogins: [String!] - ): TeamConnection! - - """ - The slug corresponding to the organization and team. - """ - combinedSlug: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The description of the team. - """ - description: String - - """ - Find a team discussion by its number. - """ - discussion( - """ - The sequence number of the discussion to find. - """ - number: Int! - ): TeamDiscussion - - """ - A list of team discussions. - """ - discussions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If provided, filters discussions according to whether or not they are pinned. - """ - isPinned: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: TeamDiscussionOrder - ): TeamDiscussionConnection! - - """ - The HTTP path for team discussions - """ - discussionsResourcePath: URI! - - """ - The HTTP URL for team discussions - """ - discussionsUrl: URI! - - """ - The HTTP path for editing this team - """ - editTeamResourcePath: URI! - - """ - The HTTP URL for editing this team - """ - editTeamUrl: URI! - id: ID! - - """ - A list of pending invitations for users to this team - """ - invitations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationInvitationConnection - - """ - Get the status messages members of this entity have set that are either public or visible only to the organization. - """ - memberStatuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for user statuses returned from the connection. - """ - orderBy: UserStatusOrder = {field: UPDATED_AT, direction: DESC} - ): UserStatusConnection! - - """ - A list of users who are members of this team. - """ - members( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter by membership type - """ - membership: TeamMembershipType = ALL - - """ - Order for the connection. - """ - orderBy: TeamMemberOrder - - """ - The search string to look for. - """ - query: String - - """ - Filter by team member role - """ - role: TeamMemberRole - ): TeamMemberConnection! - - """ - The HTTP path for the team' members - """ - membersResourcePath: URI! - - """ - The HTTP URL for the team' members - """ - membersUrl: URI! - - """ - The name of the team. - """ - name: String! - - """ - The HTTP path creating a new team - """ - newTeamResourcePath: URI! - - """ - The HTTP URL creating a new team - """ - newTeamUrl: URI! - - """ - The organization that owns this team. - """ - organization: Organization! - - """ - The parent team of the team. - """ - parentTeam: Team - - """ - The level of privacy the team has. - """ - privacy: TeamPrivacy! - - """ - A list of repositories this team has access to. - """ - repositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for the connection. - """ - orderBy: TeamRepositoryOrder - - """ - The search string to look for. - """ - query: String - ): TeamRepositoryConnection! - - """ - The HTTP path for this team's repositories - """ - repositoriesResourcePath: URI! - - """ - The HTTP URL for this team's repositories - """ - repositoriesUrl: URI! - - """ - The HTTP path for this team - """ - resourcePath: URI! - - """ - What algorithm is used for review assignment for this team - """ - reviewRequestDelegationAlgorithm: TeamReviewAssignmentAlgorithm @preview(toggledBy: "stone-crop-preview") - - """ - True if review assignment is enabled for this team - """ - reviewRequestDelegationEnabled: Boolean! @preview(toggledBy: "stone-crop-preview") - - """ - How many team members are required for review assignment for this team - """ - reviewRequestDelegationMemberCount: Int @preview(toggledBy: "stone-crop-preview") - - """ - When assigning team members via delegation, whether the entire team should be notified as well. - """ - reviewRequestDelegationNotifyTeam: Boolean! @preview(toggledBy: "stone-crop-preview") - - """ - The slug corresponding to the team. - """ - slug: String! - - """ - The HTTP path for this team's teams - """ - teamsResourcePath: URI! - - """ - The HTTP URL for this team's teams - """ - teamsUrl: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this team - """ - url: URI! - - """ - Team is adminable by the viewer. - """ - viewerCanAdminister: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -Audit log entry for a team.add_member event. -""" -type TeamAddMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a team.add_repository event. -""" -type TeamAddRepositoryAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Metadata for an audit entry with action team.* -""" -interface TeamAuditEntryData { - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI -} - -""" -Audit log entry for a team.change_parent_team event. -""" -type TeamChangeParentTeamAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The new parent team. - """ - parentTeam: Team - - """ - The name of the new parent team - """ - parentTeamName: String - - """ - The name of the former parent team - """ - parentTeamNameWas: String - - """ - The HTTP path for the parent team - """ - parentTeamResourcePath: URI - - """ - The HTTP URL for the parent team - """ - parentTeamUrl: URI - - """ - The former parent team. - """ - parentTeamWas: Team - - """ - The HTTP path for the previous parent team - """ - parentTeamWasResourcePath: URI - - """ - The HTTP URL for the previous parent team - """ - parentTeamWasUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The connection type for Team. -""" -type TeamConnection { - """ - A list of edges. - """ - edges: [TeamEdge] - - """ - A list of nodes. - """ - nodes: [Team] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A team discussion. -""" -type TeamDiscussion implements Comment & Deletable & Node & Reactable & Subscribable & UniformResourceLocatable & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the discussion's team. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the discussion body hash. - """ - bodyVersion: String! - - """ - A list of comments on this discussion. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - When provided, filters the connection such that results begin with the comment with this number. - """ - fromComment: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: TeamDiscussionCommentOrder - ): TeamDiscussionCommentConnection! - - """ - The HTTP path for discussion comments - """ - commentsResourcePath: URI! - - """ - The HTTP URL for discussion comments - """ - commentsUrl: URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Whether or not the discussion is pinned. - """ - isPinned: Boolean! - - """ - Whether or not the discussion is only visible to team members and org admins. - """ - isPrivate: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Identifies the discussion within its team. - """ - number: Int! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The HTTP path for this discussion - """ - resourcePath: URI! - - """ - The team that defines the context of this discussion. - """ - team: Team! - - """ - The title of the discussion - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this discussion - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Whether or not the current viewer can pin this discussion. - """ - viewerCanPin: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -A comment on a team discussion. -""" -type TeamDiscussionComment implements Comment & Deletable & Node & Reactable & UniformResourceLocatable & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the comment's team. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - The current version of the body content. - """ - bodyVersion: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The discussion this comment is about. - """ - discussion: TeamDiscussion! - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Identifies the comment number. - """ - number: Int! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The HTTP path for this comment - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this comment - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for TeamDiscussionComment. -""" -type TeamDiscussionCommentConnection { - """ - A list of edges. - """ - edges: [TeamDiscussionCommentEdge] - - """ - A list of nodes. - """ - nodes: [TeamDiscussionComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type TeamDiscussionCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: TeamDiscussionComment -} - -""" -Ways in which team discussion comment connections can be ordered. -""" -input TeamDiscussionCommentOrder { - """ - The direction in which to order nodes. - """ - direction: OrderDirection! - - """ - The field by which to order nodes. - """ - field: TeamDiscussionCommentOrderField! -} - -""" -Properties by which team discussion comment connections can be ordered. -""" -enum TeamDiscussionCommentOrderField { - """ - Allows sequential ordering of team discussion comments (which is equivalent to chronological ordering). - """ - NUMBER -} - -""" -The connection type for TeamDiscussion. -""" -type TeamDiscussionConnection { - """ - A list of edges. - """ - edges: [TeamDiscussionEdge] - - """ - A list of nodes. - """ - nodes: [TeamDiscussion] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type TeamDiscussionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: TeamDiscussion -} - -""" -Ways in which team discussion connections can be ordered. -""" -input TeamDiscussionOrder { - """ - The direction in which to order nodes. - """ - direction: OrderDirection! - - """ - The field by which to order nodes. - """ - field: TeamDiscussionOrderField! -} - -""" -Properties by which team discussion connections can be ordered. -""" -enum TeamDiscussionOrderField { - """ - Allows chronological ordering of team discussions. - """ - CREATED_AT -} - -""" -An edge in a connection. -""" -type TeamEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Team -} - -""" -The connection type for User. -""" -type TeamMemberConnection { - """ - A list of edges. - """ - edges: [TeamMemberEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user who is a member of a team. -""" -type TeamMemberEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The HTTP path to the organization's member access page. - """ - memberAccessResourcePath: URI! - - """ - The HTTP URL to the organization's member access page. - """ - memberAccessUrl: URI! - node: User! - - """ - The role the member has on the team. - """ - role: TeamMemberRole! -} - -""" -Ordering options for team member connections -""" -input TeamMemberOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order team members by. - """ - field: TeamMemberOrderField! -} - -""" -Properties by which team member connections can be ordered. -""" -enum TeamMemberOrderField { - """ - Order team members by creation time - """ - CREATED_AT - - """ - Order team members by login - """ - LOGIN -} - -""" -The possible team member roles; either 'maintainer' or 'member'. -""" -enum TeamMemberRole { - """ - A team maintainer has permission to add and remove team members. - """ - MAINTAINER - - """ - A team member has no administrative permissions on the team. - """ - MEMBER -} - -""" -Defines which types of team members are included in the returned list. Can be one of IMMEDIATE, CHILD_TEAM or ALL. -""" -enum TeamMembershipType { - """ - Includes immediate and child team members for the team. - """ - ALL - - """ - Includes only child team members for the team. - """ - CHILD_TEAM - - """ - Includes only immediate members of the team. - """ - IMMEDIATE -} - -""" -Ways in which team connections can be ordered. -""" -input TeamOrder { - """ - The direction in which to order nodes. - """ - direction: OrderDirection! - - """ - The field in which to order nodes by. - """ - field: TeamOrderField! -} - -""" -Properties by which team connections can be ordered. -""" -enum TeamOrderField { - """ - Allows ordering a list of teams by name. - """ - NAME -} - -""" -The possible team privacy values. -""" -enum TeamPrivacy { - """ - A secret team can only be seen by its members. - """ - SECRET - - """ - A visible team can be seen and @mentioned by every member of the organization. - """ - VISIBLE -} - -""" -Audit log entry for a team.remove_member event. -""" -type TeamRemoveMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a team.remove_repository event. -""" -type TeamRemoveRepositoryAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The corresponding operation type for the action - """ - operationType: OperationType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The connection type for Repository. -""" -type TeamRepositoryConnection { - """ - A list of edges. - """ - edges: [TeamRepositoryEdge] - - """ - A list of nodes. - """ - nodes: [Repository] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a team repository. -""" -type TeamRepositoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: Repository! - - """ - The permission level the team has on the repository - - **Upcoming Change on 2020-10-01 UTC** - **Description:** Type for `permission` will change from `RepositoryPermission!` to `String`. - **Reason:** This field may return additional values - """ - permission: RepositoryPermission! -} - -""" -Ordering options for team repository connections -""" -input TeamRepositoryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repositories by. - """ - field: TeamRepositoryOrderField! -} - -""" -Properties by which team repository connections can be ordered. -""" -enum TeamRepositoryOrderField { - """ - Order repositories by creation time - """ - CREATED_AT - - """ - Order repositories by name - """ - NAME - - """ - Order repositories by permission - """ - PERMISSION - - """ - Order repositories by push time - """ - PUSHED_AT - - """ - Order repositories by number of stargazers - """ - STARGAZERS - - """ - Order repositories by update time - """ - UPDATED_AT -} - -""" -The possible team review assignment algorithms -""" -enum TeamReviewAssignmentAlgorithm @preview(toggledBy: "stone-crop-preview") { - """ - Balance review load across the entire team - """ - LOAD_BALANCE - - """ - Alternate reviews between each team member - """ - ROUND_ROBIN -} - -""" -The role of a user on a team. -""" -enum TeamRole { - """ - User has admin rights on the team. - """ - ADMIN - - """ - User is a member of the team. - """ - MEMBER -} - -""" -A text match within a search result. -""" -type TextMatch { - """ - The specific text fragment within the property matched on. - """ - fragment: String! - - """ - Highlights within the matched fragment. - """ - highlights: [TextMatchHighlight!]! - - """ - The property matched on. - """ - property: String! -} - -""" -Represents a single highlight in a search result match. -""" -type TextMatchHighlight { - """ - The indice in the fragment where the matched text begins. - """ - beginIndice: Int! - - """ - The indice in the fragment where the matched text ends. - """ - endIndice: Int! - - """ - The text matched. - """ - text: String! -} - -""" -A topic aggregates entities that are related to a subject. -""" -type Topic implements Node & Starrable { - id: ID! - - """ - The topic's name. - """ - name: String! - - """ - A list of related topics, including aliases of this topic, sorted with the most relevant - first. Returns up to 10 Topics. - """ - relatedTopics( - """ - How many topics to return. - """ - first: Int = 3 - ): [Topic!]! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! -} - -""" -Metadata for an audit entry with a topic. -""" -interface TopicAuditEntryData { - """ - The name of the topic added to the repository - """ - topic: Topic - - """ - The name of the topic added to the repository - """ - topicName: String -} - -""" -Reason that the suggested topic is declined. -""" -enum TopicSuggestionDeclineReason { - """ - The suggested topic is not relevant to the repository. - """ - NOT_RELEVANT - - """ - The viewer does not like the suggested topic. - """ - PERSONAL_PREFERENCE - - """ - The suggested topic is too general for the repository. - """ - TOO_GENERAL - - """ - The suggested topic is too specific for the repository (e.g. #ruby-on-rails-version-4-2-1). - """ - TOO_SPECIFIC -} - -""" -Autogenerated input type of TransferIssue -""" -input TransferIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the issue to be transferred - """ - issueId: ID! @possibleTypes(concreteTypes: ["Issue"]) - - """ - The Node ID of the repository the issue should be transferred to - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of TransferIssue -""" -type TransferIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was transferred - """ - issue: Issue -} - -""" -Represents a 'transferred' event on a given issue or pull request. -""" -type TransferredEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The repository this came from - """ - fromRepository: Repository - id: ID! - - """ - Identifies the issue associated with the event. - """ - issue: Issue! -} - -""" -Represents a Git tree. -""" -type Tree implements GitObject & Node { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - - """ - A list of tree entries. - """ - entries: [TreeEntry!] - id: ID! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! -} - -""" -Represents a Git tree entry. -""" -type TreeEntry { - """ - Entry file mode. - """ - mode: Int! - - """ - Entry file name. - """ - name: String! - - """ - Entry file object. - """ - object: GitObject - - """ - Entry file Git object ID. - """ - oid: GitObjectID! - - """ - The Repository the tree entry belongs to - """ - repository: Repository! - - """ - If the TreeEntry is for a directory occupied by a submodule project, this returns the corresponding submodule - """ - submodule: Submodule - - """ - Entry file type. - """ - type: String! -} - -""" -An RFC 3986, RFC 3987, and RFC 6570 (level 4) compliant URI string. -""" -scalar URI - -""" -Autogenerated input type of UnarchiveRepository -""" -input UnarchiveRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the repository to unarchive. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of UnarchiveRepository -""" -type UnarchiveRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The repository that was unarchived. - """ - repository: Repository -} - -""" -Represents an 'unassigned' event on any assignable object. -""" -type UnassignedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the assignable associated with the event. - """ - assignable: Assignable! - - """ - Identifies the user or mannequin that was unassigned. - """ - assignee: Assignee - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the subject (user) who was unassigned. - """ - user: User @deprecated(reason: "Assignees can now be mannequins. Use the `assignee` field instead. Removal on 2020-01-01 UTC.") -} - -""" -Autogenerated input type of UnfollowUser -""" -input UnfollowUserInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the user to unfollow. - """ - userId: ID! @possibleTypes(concreteTypes: ["User"]) -} - -""" -Autogenerated return type of UnfollowUser -""" -type UnfollowUserPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The user that was unfollowed. - """ - user: User -} - -""" -Represents a type that can be retrieved by a URL. -""" -interface UniformResourceLocatable { - """ - The HTML path to this resource. - """ - resourcePath: URI! - - """ - The URL to this resource. - """ - url: URI! -} - -""" -Represents an unknown signature on a Commit or Tag. -""" -type UnknownSignature implements GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -Represents an 'unlabeled' event on a given issue or pull request. -""" -type UnlabeledEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the label associated with the 'unlabeled' event. - """ - label: Label! - - """ - Identifies the `Labelable` associated with the event. - """ - labelable: Labelable! -} - -""" -Autogenerated input type of UnlinkRepositoryFromProject -""" -input UnlinkRepositoryFromProjectInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Project linked to the Repository. - """ - projectId: ID! @possibleTypes(concreteTypes: ["Project"]) - - """ - The ID of the Repository linked to the Project. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of UnlinkRepositoryFromProject -""" -type UnlinkRepositoryFromProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The linked Project. - """ - project: Project - - """ - The linked Repository. - """ - repository: Repository -} - -""" -Autogenerated input type of UnlockLockable -""" -input UnlockLockableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue or pull request to be unlocked. - """ - lockableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Lockable") -} - -""" -Autogenerated return type of UnlockLockable -""" -type UnlockLockablePayload { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was unlocked. - """ - unlockedRecord: Lockable -} - -""" -Represents an 'unlocked' event on a given issue or pull request. -""" -type UnlockedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Object that was unlocked. - """ - lockable: Lockable! -} - -""" -Autogenerated input type of UnmarkIssueAsDuplicate -""" -input UnmarkIssueAsDuplicateInput { - """ - ID of the issue or pull request currently considered canonical/authoritative/original. - """ - canonicalId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "IssueOrPullRequest") - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue or pull request currently marked as a duplicate. - """ - duplicateId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "IssueOrPullRequest") -} - -""" -Autogenerated return type of UnmarkIssueAsDuplicate -""" -type UnmarkIssueAsDuplicatePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue or pull request that was marked as a duplicate. - """ - duplicate: IssueOrPullRequest -} - -""" -Represents an 'unmarked_as_duplicate' event on a given issue or pull request. -""" -type UnmarkedAsDuplicateEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! -} - -""" -Autogenerated input type of UnminimizeComment -""" -input UnminimizeCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! @possibleTypes(concreteTypes: ["CommitComment", "GistComment", "IssueComment", "PullRequestReviewComment"], abstractType: "Minimizable") -} - -""" -Autogenerated return type of UnminimizeComment -""" -type UnminimizeCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The comment that was unminimized. - """ - unminimizedComment: Minimizable -} - -""" -Autogenerated input type of UnpinIssue -""" -input UnpinIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the issue to be unpinned - """ - issueId: ID! @possibleTypes(concreteTypes: ["Issue"]) -} - -""" -Autogenerated return type of UnpinIssue -""" -type UnpinIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was unpinned - """ - issue: Issue -} - -""" -Represents an 'unpinned' event on a given issue or pull request. -""" -type UnpinnedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the issue associated with the event. - """ - issue: Issue! -} - -""" -Autogenerated input type of UnresolveReviewThread -""" -input UnresolveReviewThreadInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the thread to unresolve - """ - threadId: ID! @possibleTypes(concreteTypes: ["PullRequestReviewThread"]) -} - -""" -Autogenerated return type of UnresolveReviewThread -""" -type UnresolveReviewThreadPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The thread to resolve. - """ - thread: PullRequestReviewThread -} - -""" -Represents an 'unsubscribed' event on a given `Subscribable`. -""" -type UnsubscribedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Object referenced by event. - """ - subscribable: Subscribable! -} - -""" -Entities that can be updated. -""" -interface Updatable { - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! -} - -""" -Comments that can be updated. -""" -interface UpdatableComment { - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! -} - -""" -Autogenerated input type of UpdateBranchProtectionRule -""" -input UpdateBranchProtectionRuleInput { - """ - The global relay id of the branch protection rule to be updated. - """ - branchProtectionRuleId: ID! @possibleTypes(concreteTypes: ["BranchProtectionRule"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Will new commits pushed to matching branches dismiss pull request review approvals. - """ - dismissesStaleReviews: Boolean - - """ - Can admins overwrite branch protection. - """ - isAdminEnforced: Boolean - - """ - The glob-like pattern used to determine matching branches. - """ - pattern: String - - """ - A list of User, Team or App IDs allowed to push to matching branches. - """ - pushActorIds: [ID!] - - """ - Number of approving reviews required to update matching branches. - """ - requiredApprovingReviewCount: Int - - """ - List of required status check contexts that must pass for commits to be accepted to matching branches. - """ - requiredStatusCheckContexts: [String!] - - """ - Are approving reviews required to update matching branches. - """ - requiresApprovingReviews: Boolean - - """ - Are reviews from code owners required to update matching branches. - """ - requiresCodeOwnerReviews: Boolean - - """ - Are commits required to be signed. - """ - requiresCommitSignatures: Boolean - - """ - Are status checks required to update matching branches. - """ - requiresStatusChecks: Boolean - - """ - Are branches required to be up to date before merging. - """ - requiresStrictStatusChecks: Boolean - - """ - Is pushing to matching branches restricted. - """ - restrictsPushes: Boolean - - """ - Is dismissal of pull request reviews restricted. - """ - restrictsReviewDismissals: Boolean - - """ - A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. - """ - reviewDismissalActorIds: [ID!] -} - -""" -Autogenerated return type of UpdateBranchProtectionRule -""" -type UpdateBranchProtectionRulePayload { - """ - The newly created BranchProtectionRule. - """ - branchProtectionRule: BranchProtectionRule - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of UpdateCheckRun -""" -input UpdateCheckRunInput @preview(toggledBy: "antiope-preview") { - """ - Possible further actions the integrator can perform, which a user may trigger. - """ - actions: [CheckRunAction!] - - """ - The node of the check. - """ - checkRunId: ID! @possibleTypes(concreteTypes: ["CheckRun"]) - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The time that the check run finished. - """ - completedAt: DateTime - - """ - The final conclusion of the check. - """ - conclusion: CheckConclusionState - - """ - The URL of the integrator's site that has the full details of the check. - """ - detailsUrl: URI - - """ - A reference for the run on the integrator's system. - """ - externalId: String - - """ - The name of the check. - """ - name: String - - """ - Descriptive details about the run. - """ - output: CheckRunOutput - - """ - The node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - The time that the check run began. - """ - startedAt: DateTime - - """ - The current status. - """ - status: RequestableCheckStatusState -} - -""" -Autogenerated return type of UpdateCheckRun -""" -type UpdateCheckRunPayload @preview(toggledBy: "antiope-preview") { - """ - The updated check run. - """ - checkRun: CheckRun - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of UpdateCheckSuitePreferences -""" -input UpdateCheckSuitePreferencesInput @preview(toggledBy: "antiope-preview") { - """ - The check suite preferences to modify. - """ - autoTriggerPreferences: [CheckSuiteAutoTriggerPreference!]! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of UpdateCheckSuitePreferences -""" -type UpdateCheckSuitePreferencesPayload @preview(toggledBy: "antiope-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated repository. - """ - repository: Repository -} - -""" -Autogenerated input type of UpdateEnterpriseActionExecutionCapabilitySetting -""" -input UpdateEnterpriseActionExecutionCapabilitySettingInput { - """ - The value for the action execution capability setting on the enterprise. - """ - capability: ActionExecutionCapabilitySetting! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can create repositories setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) -} - -""" -Autogenerated return type of UpdateEnterpriseActionExecutionCapabilitySetting -""" -type UpdateEnterpriseActionExecutionCapabilitySettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated action execution capability setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the action execution capability setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseAdministratorRole -""" -input UpdateEnterpriseAdministratorRoleInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Enterprise which the admin belongs to. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The login of a administrator whose role is being changed. - """ - login: String! - - """ - The new role for the Enterprise administrator. - """ - role: EnterpriseAdministratorRole! -} - -""" -Autogenerated return type of UpdateEnterpriseAdministratorRole -""" -type UpdateEnterpriseAdministratorRolePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A message confirming the result of changing the administrator's role. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseAllowPrivateRepositoryForkingSetting -""" -input UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the allow private repository forking setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the allow private repository forking setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseAllowPrivateRepositoryForkingSetting -""" -type UpdateEnterpriseAllowPrivateRepositoryForkingSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated allow private repository forking setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the allow private repository forking setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseDefaultRepositoryPermissionSetting -""" -input UpdateEnterpriseDefaultRepositoryPermissionSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the default repository permission setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the default repository permission setting on the enterprise. - """ - settingValue: EnterpriseDefaultRepositoryPermissionSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseDefaultRepositoryPermissionSetting -""" -type UpdateEnterpriseDefaultRepositoryPermissionSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated default repository permission setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the default repository permission setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanChangeRepositoryVisibilitySetting -""" -input UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can change repository visibility setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can change repository visibility setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanChangeRepositoryVisibilitySetting -""" -type UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can change repository visibility setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can change repository visibility setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanCreateRepositoriesSetting -""" -input UpdateEnterpriseMembersCanCreateRepositoriesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can create repositories setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - Allow members to create internal repositories. Defaults to current value. - """ - membersCanCreateInternalRepositories: Boolean - - """ - Allow members to create private repositories. Defaults to current value. - """ - membersCanCreatePrivateRepositories: Boolean - - """ - Allow members to create public repositories. Defaults to current value. - """ - membersCanCreatePublicRepositories: Boolean - - """ - When false, allow member organizations to set their own repository creation member privileges. - """ - membersCanCreateRepositoriesPolicyEnabled: Boolean - - """ - Value for the members can create repositories setting on the enterprise. This - or the granular public/private/internal allowed fields (but not both) must be provided. - """ - settingValue: EnterpriseMembersCanCreateRepositoriesSettingValue -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanCreateRepositoriesSetting -""" -type UpdateEnterpriseMembersCanCreateRepositoriesSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can create repositories setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can create repositories setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanDeleteIssuesSetting -""" -input UpdateEnterpriseMembersCanDeleteIssuesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can delete issues setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can delete issues setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanDeleteIssuesSetting -""" -type UpdateEnterpriseMembersCanDeleteIssuesSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can delete issues setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can delete issues setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanDeleteRepositoriesSetting -""" -input UpdateEnterpriseMembersCanDeleteRepositoriesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can delete repositories setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can delete repositories setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanDeleteRepositoriesSetting -""" -type UpdateEnterpriseMembersCanDeleteRepositoriesSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can delete repositories setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can delete repositories setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanInviteCollaboratorsSetting -""" -input UpdateEnterpriseMembersCanInviteCollaboratorsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can invite collaborators setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can invite collaborators setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanInviteCollaboratorsSetting -""" -type UpdateEnterpriseMembersCanInviteCollaboratorsSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can invite collaborators setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can invite collaborators setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanMakePurchasesSetting -""" -input UpdateEnterpriseMembersCanMakePurchasesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can make purchases setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can make purchases setting on the enterprise. - """ - settingValue: EnterpriseMembersCanMakePurchasesSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanMakePurchasesSetting -""" -type UpdateEnterpriseMembersCanMakePurchasesSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can make purchases setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can make purchases setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanUpdateProtectedBranchesSetting -""" -input UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can update protected branches setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can update protected branches setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanUpdateProtectedBranchesSetting -""" -type UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can update protected branches setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can update protected branches setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanViewDependencyInsightsSetting -""" -input UpdateEnterpriseMembersCanViewDependencyInsightsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can view dependency insights setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the members can view dependency insights setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseMembersCanViewDependencyInsightsSetting -""" -type UpdateEnterpriseMembersCanViewDependencyInsightsSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated members can view dependency insights setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the members can view dependency insights setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseOrganizationProjectsSetting -""" -input UpdateEnterpriseOrganizationProjectsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the organization projects setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the organization projects setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseOrganizationProjectsSetting -""" -type UpdateEnterpriseOrganizationProjectsSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated organization projects setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the organization projects setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseProfile -""" -input UpdateEnterpriseProfileInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The description of the enterprise. - """ - description: String - - """ - The Enterprise ID to update. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The location of the enterprise. - """ - location: String - - """ - The name of the enterprise. - """ - name: String - - """ - The URL of the enterprise's website. - """ - websiteUrl: String -} - -""" -Autogenerated return type of UpdateEnterpriseProfile -""" -type UpdateEnterpriseProfilePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated enterprise. - """ - enterprise: Enterprise -} - -""" -Autogenerated input type of UpdateEnterpriseRepositoryProjectsSetting -""" -input UpdateEnterpriseRepositoryProjectsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the repository projects setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the repository projects setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseRepositoryProjectsSetting -""" -type UpdateEnterpriseRepositoryProjectsSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated repository projects setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the repository projects setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseTeamDiscussionsSetting -""" -input UpdateEnterpriseTeamDiscussionsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the team discussions setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the team discussions setting on the enterprise. - """ - settingValue: EnterpriseEnabledDisabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseTeamDiscussionsSetting -""" -type UpdateEnterpriseTeamDiscussionsSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated team discussions setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the team discussions setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateEnterpriseTwoFactorAuthenticationRequiredSetting -""" -input UpdateEnterpriseTwoFactorAuthenticationRequiredSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the two factor authentication required setting. - """ - enterpriseId: ID! @possibleTypes(concreteTypes: ["Enterprise"]) - - """ - The value for the two factor authentication required setting on the enterprise. - """ - settingValue: EnterpriseEnabledSettingValue! -} - -""" -Autogenerated return type of UpdateEnterpriseTwoFactorAuthenticationRequiredSetting -""" -type UpdateEnterpriseTwoFactorAuthenticationRequiredSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The enterprise with the updated two factor authentication required setting. - """ - enterprise: Enterprise - - """ - A message confirming the result of updating the two factor authentication required setting. - """ - message: String -} - -""" -Autogenerated input type of UpdateIpAllowListEnabledSetting -""" -input UpdateIpAllowListEnabledSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the owner on which to set the IP allow list enabled setting. - """ - ownerId: ID! @possibleTypes(concreteTypes: ["Enterprise", "Organization"], abstractType: "IpAllowListOwner") - - """ - The value for the IP allow list enabled setting. - """ - settingValue: IpAllowListEnabledSettingValue! -} - -""" -Autogenerated return type of UpdateIpAllowListEnabledSetting -""" -type UpdateIpAllowListEnabledSettingPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The IP allow list owner on which the setting was updated. - """ - owner: IpAllowListOwner -} - -""" -Autogenerated input type of UpdateIpAllowListEntry -""" -input UpdateIpAllowListEntryInput { - """ - An IP address or range of addresses in CIDR notation. - """ - allowListValue: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the IP allow list entry to update. - """ - ipAllowListEntryId: ID! @possibleTypes(concreteTypes: ["IpAllowListEntry"]) - - """ - Whether the IP allow list entry is active when an IP allow list is enabled. - """ - isActive: Boolean! - - """ - An optional name for the IP allow list entry. - """ - name: String -} - -""" -Autogenerated return type of UpdateIpAllowListEntry -""" -type UpdateIpAllowListEntryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The IP allow list entry that was updated. - """ - ipAllowListEntry: IpAllowListEntry -} - -""" -Autogenerated input type of UpdateIssueComment -""" -input UpdateIssueCommentInput { - """ - The updated text of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the IssueComment to modify. - """ - id: ID! @possibleTypes(concreteTypes: ["IssueComment"]) -} - -""" -Autogenerated return type of UpdateIssueComment -""" -type UpdateIssueCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated comment. - """ - issueComment: IssueComment -} - -""" -Autogenerated input type of UpdateIssue -""" -input UpdateIssueInput { - """ - An array of Node IDs of users for this issue. - """ - assigneeIds: [ID!] @possibleTypes(concreteTypes: ["User"]) - - """ - The body for the issue description. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Issue to modify. - """ - id: ID! @possibleTypes(concreteTypes: ["Issue"]) - - """ - An array of Node IDs of labels for this issue. - """ - labelIds: [ID!] @possibleTypes(concreteTypes: ["Label"]) - - """ - The Node ID of the milestone for this issue. - """ - milestoneId: ID @possibleTypes(concreteTypes: ["Milestone"]) - - """ - An array of Node IDs for projects associated with this issue. - """ - projectIds: [ID!] - - """ - The desired issue state. - """ - state: IssueState - - """ - The title for the issue. - """ - title: String -} - -""" -Autogenerated return type of UpdateIssue -""" -type UpdateIssuePayload { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue. - """ - issue: Issue -} - -""" -Autogenerated input type of UpdateLabel -""" -input UpdateLabelInput @preview(toggledBy: "bane-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A 6 character hex code, without the leading #, identifying the updated color of the label. - """ - color: String - - """ - A brief description of the label, such as its purpose. - """ - description: String - - """ - The Node ID of the label to be updated. - """ - id: ID! @possibleTypes(concreteTypes: ["Label"]) - - """ - The updated name of the label. - """ - name: String -} - -""" -Autogenerated return type of UpdateLabel -""" -type UpdateLabelPayload @preview(toggledBy: "bane-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated label. - """ - label: Label -} - -""" -Autogenerated input type of UpdateProjectCard -""" -input UpdateProjectCardInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Whether or not the ProjectCard should be archived - """ - isArchived: Boolean - - """ - The note of ProjectCard. - """ - note: String - - """ - The ProjectCard ID to update. - """ - projectCardId: ID! @possibleTypes(concreteTypes: ["ProjectCard"]) -} - -""" -Autogenerated return type of UpdateProjectCard -""" -type UpdateProjectCardPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated ProjectCard. - """ - projectCard: ProjectCard -} - -""" -Autogenerated input type of UpdateProjectColumn -""" -input UpdateProjectColumnInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of project column. - """ - name: String! - - """ - The ProjectColumn ID to update. - """ - projectColumnId: ID! @possibleTypes(concreteTypes: ["ProjectColumn"]) -} - -""" -Autogenerated return type of UpdateProjectColumn -""" -type UpdateProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated project column. - """ - projectColumn: ProjectColumn -} - -""" -Autogenerated input type of UpdateProject -""" -input UpdateProjectInput { - """ - The description of project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of project. - """ - name: String - - """ - The Project ID to update. - """ - projectId: ID! @possibleTypes(concreteTypes: ["Project"]) - - """ - Whether the project is public or not. - """ - public: Boolean - - """ - Whether the project is open or closed. - """ - state: ProjectState -} - -""" -Autogenerated return type of UpdateProject -""" -type UpdateProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated project. - """ - project: Project -} - -""" -Autogenerated input type of UpdatePullRequest -""" -input UpdatePullRequestInput { - """ - An array of Node IDs of users for this pull request. - """ - assigneeIds: [ID!] @possibleTypes(concreteTypes: ["User"]) - - """ - The name of the branch you want your changes pulled into. This should be an existing branch - on the current repository. - """ - baseRefName: String - - """ - The contents of the pull request. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - An array of Node IDs of labels for this pull request. - """ - labelIds: [ID!] @possibleTypes(concreteTypes: ["Label"]) - - """ - Indicates whether maintainers can modify the pull request. - """ - maintainerCanModify: Boolean - - """ - The Node ID of the milestone for this pull request. - """ - milestoneId: ID @possibleTypes(concreteTypes: ["Milestone"]) - - """ - An array of Node IDs for projects associated with this pull request. - """ - projectIds: [ID!] - - """ - The Node ID of the pull request. - """ - pullRequestId: ID! @possibleTypes(concreteTypes: ["PullRequest"]) - - """ - The target state of the pull request. - """ - state: PullRequestUpdateState - - """ - The title of the pull request. - """ - title: String -} - -""" -Autogenerated return type of UpdatePullRequest -""" -type UpdatePullRequestPayload { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated pull request. - """ - pullRequest: PullRequest -} - -""" -Autogenerated input type of UpdatePullRequestReviewComment -""" -input UpdatePullRequestReviewCommentInput { - """ - The text of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the comment to modify. - """ - pullRequestReviewCommentId: ID! @possibleTypes(concreteTypes: ["PullRequestReviewComment"]) -} - -""" -Autogenerated return type of UpdatePullRequestReviewComment -""" -type UpdatePullRequestReviewCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated comment. - """ - pullRequestReviewComment: PullRequestReviewComment -} - -""" -Autogenerated input type of UpdatePullRequestReview -""" -input UpdatePullRequestReviewInput { - """ - The contents of the pull request review body. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pull request review to modify. - """ - pullRequestReviewId: ID! @possibleTypes(concreteTypes: ["PullRequestReview"]) -} - -""" -Autogenerated return type of UpdatePullRequestReview -""" -type UpdatePullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Autogenerated input type of UpdateRef -""" -input UpdateRefInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Permit updates of branch Refs that are not fast-forwards? - """ - force: Boolean = false - - """ - The GitObjectID that the Ref shall be updated to target. - """ - oid: GitObjectID! - - """ - The Node ID of the Ref to be updated. - """ - refId: ID! @possibleTypes(concreteTypes: ["Ref"]) -} - -""" -Autogenerated return type of UpdateRef -""" -type UpdateRefPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated Ref. - """ - ref: Ref -} - -""" -Autogenerated input type of UpdateRefs -""" -input UpdateRefsInput @preview(toggledBy: "update-refs-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A list of ref updates. - """ - refUpdates: [RefUpdate!]! - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) -} - -""" -Autogenerated return type of UpdateRefs -""" -type UpdateRefsPayload @preview(toggledBy: "update-refs-preview") { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of UpdateRepository -""" -input UpdateRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A new description for the repository. Pass an empty string to erase the existing description. - """ - description: String - - """ - Indicates if the repository should have the issues feature enabled. - """ - hasIssuesEnabled: Boolean - - """ - Indicates if the repository should have the project boards feature enabled. - """ - hasProjectsEnabled: Boolean - - """ - Indicates if the repository should have the wiki feature enabled. - """ - hasWikiEnabled: Boolean - - """ - The URL for a web page about this repository. Pass an empty string to erase the existing URL. - """ - homepageUrl: URI - - """ - The new name of the repository. - """ - name: String - - """ - The ID of the repository to update. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - Whether this repository should be marked as a template such that anyone who - can access it can create new repositories with the same files and directory structure. - """ - template: Boolean -} - -""" -Autogenerated return type of UpdateRepository -""" -type UpdateRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated repository. - """ - repository: Repository -} - -""" -Autogenerated input type of UpdateSubscription -""" -input UpdateSubscriptionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new state of the subscription. - """ - state: SubscriptionState! - - """ - The Node ID of the subscribable object to modify. - """ - subscribableId: ID! @possibleTypes(concreteTypes: ["Commit", "Issue", "PullRequest", "Repository", "Team", "TeamDiscussion"], abstractType: "Subscribable") -} - -""" -Autogenerated return type of UpdateSubscription -""" -type UpdateSubscriptionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The input subscribable entity. - """ - subscribable: Subscribable -} - -""" -Autogenerated input type of UpdateTeamDiscussionComment -""" -input UpdateTeamDiscussionCommentInput { - """ - The updated text of the comment. - """ - body: String! - - """ - The current version of the body content. - """ - bodyVersion: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the comment to modify. - """ - id: ID! @possibleTypes(concreteTypes: ["TeamDiscussionComment"]) -} - -""" -Autogenerated return type of UpdateTeamDiscussionComment -""" -type UpdateTeamDiscussionCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated comment. - """ - teamDiscussionComment: TeamDiscussionComment -} - -""" -Autogenerated input type of UpdateTeamDiscussion -""" -input UpdateTeamDiscussionInput { - """ - The updated text of the discussion. - """ - body: String - - """ - The current version of the body content. If provided, this update operation - will be rejected if the given version does not match the latest version on the server. - """ - bodyVersion: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the discussion to modify. - """ - id: ID! @possibleTypes(concreteTypes: ["TeamDiscussion"]) - - """ - If provided, sets the pinned state of the updated discussion. - """ - pinned: Boolean - - """ - The updated title of the discussion. - """ - title: String -} - -""" -Autogenerated return type of UpdateTeamDiscussion -""" -type UpdateTeamDiscussionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated discussion. - """ - teamDiscussion: TeamDiscussion -} - -""" -Autogenerated input type of UpdateTeamReviewAssignment -""" -input UpdateTeamReviewAssignmentInput @preview(toggledBy: "stone-crop-preview") { - """ - The algorithm to use for review assignment - """ - algorithm: TeamReviewAssignmentAlgorithm = ROUND_ROBIN - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Turn on or off review assignment - """ - enabled: Boolean! - - """ - An array of team member IDs to exclude - """ - excludedTeamMemberIds: [ID!] @possibleTypes(concreteTypes: ["User"]) - - """ - The Node ID of the team to update review assginments of - """ - id: ID! @possibleTypes(concreteTypes: ["Team"]) - - """ - Notify the entire team of the PR if it is delegated - """ - notifyTeam: Boolean = true - - """ - The number of team members to assign - """ - teamMemberCount: Int = 1 -} - -""" -Autogenerated return type of UpdateTeamReviewAssignment -""" -type UpdateTeamReviewAssignmentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The team that was modified - """ - team: Team -} - -""" -Autogenerated input type of UpdateTopics -""" -input UpdateTopicsInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the repository. - """ - repositoryId: ID! @possibleTypes(concreteTypes: ["Repository"]) - - """ - An array of topic names. - """ - topicNames: [String!]! -} - -""" -Autogenerated return type of UpdateTopics -""" -type UpdateTopicsPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Names of the provided topics that are not valid. - """ - invalidTopicNames: [String!] - - """ - The updated repository. - """ - repository: Repository -} - -""" -A user is an individual's account on GitHub that owns repositories and can make new content. -""" -type User implements Actor & Node & PackageOwner & ProfileOwner & ProjectOwner & RepositoryOwner & Sponsorable & UniformResourceLocatable { - """ - Determine if this repository owner has any items that can be pinned to their profile. - """ - anyPinnableItems( - """ - Filter to only a particular kind of pinnable item. - """ - type: PinnableItemType - ): Boolean! - - """ - A URL pointing to the user's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - The user's public profile bio. - """ - bio: String - - """ - The user's public profile bio as HTML. - """ - bioHTML: HTML! - - """ - A list of commit comments made by this user. - """ - commitComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The user's public profile company. - """ - company: String - - """ - The user's public profile company as HTML. - """ - companyHTML: HTML! - - """ - The collection of contributions this user has made to different repositories. - """ - contributionsCollection( - """ - Only contributions made at this time or later will be counted. If omitted, defaults to a year ago. - """ - from: DateTime - - """ - The ID of the organization used to filter contributions. - """ - organizationID: ID - - """ - Only contributions made before and up to and including this time will be - counted. If omitted, defaults to the current time. - """ - to: DateTime - ): ContributionsCollection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The user's publicly visible profile email. - """ - email: String! - - """ - A list of users the given user is followed by. - """ - followers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): FollowerConnection! - - """ - A list of users the given user is following. - """ - following( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): FollowingConnection! - - """ - Find gist by repo name. - """ - gist( - """ - The gist name to find. - """ - name: String! - ): Gist - - """ - A list of gist comments made by this user. - """ - gistComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): GistCommentConnection! - - """ - A list of the Gists the user has created. - """ - gists( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for gists returned from the connection - """ - orderBy: GistOrder - - """ - Filters Gists according to privacy. - """ - privacy: GistPrivacy - ): GistConnection! - - """ - The hovercard information for this user in a given context - """ - hovercard( - """ - The ID of the subject to get the hovercard in the context of - """ - primarySubjectId: ID - ): Hovercard! - id: ID! - - """ - Whether or not this user is a participant in the GitHub Security Bug Bounty. - """ - isBountyHunter: Boolean! - - """ - Whether or not this user is a participant in the GitHub Campus Experts Program. - """ - isCampusExpert: Boolean! - - """ - Whether or not this user is a GitHub Developer Program member. - """ - isDeveloperProgramMember: Boolean! - - """ - Whether or not this user is a GitHub employee. - """ - isEmployee: Boolean! - - """ - Whether or not the user has marked themselves as for hire. - """ - isHireable: Boolean! - - """ - Whether or not this user is a site administrator. - """ - isSiteAdmin: Boolean! - - """ - Whether or not this user is the viewing user. - """ - isViewer: Boolean! - - """ - A list of issue comments made by this user. - """ - issueComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): IssueCommentConnection! - - """ - A list of issues associated with this user. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Showcases a selection of repositories and gists that the profile owner has - either curated or that have been selected automatically based on popularity. - """ - itemShowcase: ProfileItemShowcase! - - """ - The user's public profile location. - """ - location: String - - """ - The username used to login. - """ - login: String! - - """ - The user's public profile name. - """ - name: String - - """ - Find an organization by its login that the user belongs to. - """ - organization( - """ - The login of the organization to find. - """ - login: String! - ): Organization - - """ - Verified email addresses that match verified domains for a specified organization the user is a member of. - """ - organizationVerifiedDomainEmails( - """ - The login of the organization to match verified domains from. - """ - login: String! - ): [String!]! - - """ - A list of organizations the user belongs to. - """ - organizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationConnection! - - """ - A list of packages under the owner. - """ - packages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find packages by their names. - """ - names: [String] - - """ - Ordering of the returned packages. - """ - orderBy: PackageOrder = {field: CREATED_AT, direction: DESC} - - """ - Filter registry package by type. - """ - packageType: PackageType - - """ - Find packages in a repository by ID. - """ - repositoryId: ID - ): PackageConnection! - - """ - A list of repositories and gists this profile owner can pin to their profile. - """ - pinnableItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinnable items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - A list of repositories and gists this profile owner has pinned to their profile - """ - pinnedItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinned items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - Returns how many more items this profile owner can pin to their profile. - """ - pinnedItemsRemaining: Int! - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing user's projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing user's projects - """ - projectsUrl: URI! - - """ - A list of public keys associated with this user. - """ - publicKeys( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PublicKeyConnection! - - """ - A list of pull requests associated with this user. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - A list of repositories that the user owns. - """ - repositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they are forks of another repository - """ - isFork: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - A list of repositories that the user recently contributed to. - """ - repositoriesContributedTo( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - If non-null, include only the specified types of contributions. The - GitHub.com UI uses [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY] - """ - contributionTypes: [RepositoryContributionType] - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If true, include user repositories - """ - includeUserRepositories: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Find Repository. - """ - repository( - """ - Name of Repository to find. - """ - name: String! - ): Repository - - """ - The HTTP path for this user - """ - resourcePath: URI! - - """ - Replies this user has saved - """ - savedReplies( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - The field to order saved replies by. - """ - orderBy: SavedReplyOrder = {field: UPDATED_AT, direction: DESC} - ): SavedReplyConnection - - """ - The GitHub Sponsors listing for this user. - """ - sponsorsListing: SponsorsListing - - """ - This object's sponsorships as the maintainer. - """ - sponsorshipsAsMaintainer( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether or not to include private sponsorships in the result set - """ - includePrivate: Boolean = false - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - This object's sponsorships as the sponsor. - """ - sponsorshipsAsSponsor( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - Repositories the user has starred. - """ - starredRepositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - - """ - Filters starred repositories to only return repositories owned by the viewer. - """ - ownedByViewer: Boolean - ): StarredRepositoryConnection! - - """ - The user's description of what they're currently doing. - """ - status: UserStatus - - """ - Repositories the user has contributed to, ordered by contribution rank, plus repositories the user has created - """ - topRepositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder! - - """ - How far back in time to fetch contributed repositories - """ - since: DateTime - ): RepositoryConnection! - - """ - The user's Twitter username. - """ - twitterUsername: String - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this user - """ - url: URI! - - """ - Can the viewer pin repositories and gists to the profile? - """ - viewerCanChangePinnedItems: Boolean! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! - - """ - Whether or not the viewer is able to follow the user. - """ - viewerCanFollow: Boolean! - - """ - Whether or not this user is followed by the viewer. - """ - viewerIsFollowing: Boolean! - - """ - A list of repositories the given user is watching. - """ - watching( - """ - Affiliation options for repositories returned from the connection. If none - specified, the results will include repositories for which the current - viewer is an owner or collaborator, or member. - """ - affiliations: [RepositoryAffiliation] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - A URL pointing to the user's public website/blog. - """ - websiteUrl: URI -} - -""" -The possible durations that a user can be blocked for. -""" -enum UserBlockDuration { - """ - The user was blocked for 1 day - """ - ONE_DAY - - """ - The user was blocked for 30 days - """ - ONE_MONTH - - """ - The user was blocked for 7 days - """ - ONE_WEEK - - """ - The user was blocked permanently - """ - PERMANENT - - """ - The user was blocked for 3 days - """ - THREE_DAYS -} - -""" -Represents a 'user_blocked' event on a given user. -""" -type UserBlockedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Number of days that the user was blocked for. - """ - blockDuration: UserBlockDuration! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The user who was blocked. - """ - subject: User -} - -""" -The connection type for User. -""" -type UserConnection { - """ - A list of edges. - """ - edges: [UserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edit on user content -""" -type UserContentEdit implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the date and time when the object was deleted. - """ - deletedAt: DateTime - - """ - The actor who deleted this content - """ - deletedBy: Actor - - """ - A summary of the changes for this edit - """ - diff: String - - """ - When this content was edited - """ - editedAt: DateTime! - - """ - The actor who edited this content - """ - editor: Actor - id: ID! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -A list of edits to content. -""" -type UserContentEditConnection { - """ - A list of edges. - """ - edges: [UserContentEditEdge] - - """ - A list of nodes. - """ - nodes: [UserContentEdit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type UserContentEditEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: UserContentEdit -} - -""" -Represents a user. -""" -type UserEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User -} - -""" -The user's description of what they're currently doing. -""" -type UserStatus implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - An emoji summarizing the user's status. - """ - emoji: String - - """ - The status emoji as HTML. - """ - emojiHTML: HTML - - """ - If set, the status will not be shown after this date. - """ - expiresAt: DateTime - - """ - ID of the object. - """ - id: ID! - - """ - Whether this status indicates the user is not fully available on GitHub. - """ - indicatesLimitedAvailability: Boolean! - - """ - A brief message describing what the user is doing. - """ - message: String - - """ - The organization whose members can see this status. If null, this status is publicly visible. - """ - organization: Organization - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The user who has this status. - """ - user: User! -} - -""" -The connection type for UserStatus. -""" -type UserStatusConnection { - """ - A list of edges. - """ - edges: [UserStatusEdge] - - """ - A list of nodes. - """ - nodes: [UserStatus] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type UserStatusEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: UserStatus -} - -""" -Ordering options for user status connections. -""" -input UserStatusOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order user statuses by. - """ - field: UserStatusOrderField! -} - -""" -Properties by which user status connections can be ordered. -""" -enum UserStatusOrderField { - """ - Order user statuses by when they were updated. - """ - UPDATED_AT -} - -""" -A hovercard context with a message describing how the viewer is related. -""" -type ViewerHovercardContext implements HovercardContext { - """ - A string describing this context - """ - message: String! - - """ - An octicon to accompany this context - """ - octicon: String! - - """ - Identifies the user who is related to this context. - """ - viewer: User! -} - -""" -A valid x509 certificate string -""" -scalar X509Certificate diff --git a/Sources/StarWarsAPI/API.swift b/Sources/StarWarsAPI/API.swift deleted file mode 100644 index 9b355aa766..0000000000 --- a/Sources/StarWarsAPI/API.swift +++ /dev/null @@ -1,8407 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -/// The episodes in the Star Wars trilogy -public enum Episode: RawRepresentable, Equatable, Hashable, CaseIterable, Apollo.JSONDecodable, Apollo.JSONEncodable { - public typealias RawValue = String - /// Star Wars Episode IV: A New Hope, released in 1977. - case newhope - /// Star Wars Episode V: The Empire Strikes Back, released in 1980. - case empire - /// Star Wars Episode VI: Return of the Jedi, released in 1983. - case jedi - /// Auto generated constant for unknown enum values - case __unknown(RawValue) - - public init?(rawValue: RawValue) { - switch rawValue { - case "NEWHOPE": self = .newhope - case "EMPIRE": self = .empire - case "JEDI": self = .jedi - default: self = .__unknown(rawValue) - } - } - - public var rawValue: RawValue { - switch self { - case .newhope: return "NEWHOPE" - case .empire: return "EMPIRE" - case .jedi: return "JEDI" - case .__unknown(let value): return value - } - } - - public static func == (lhs: Episode, rhs: Episode) -> Bool { - switch (lhs, rhs) { - case (.newhope, .newhope): return true - case (.empire, .empire): return true - case (.jedi, .jedi): return true - case (.__unknown(let lhsValue), .__unknown(let rhsValue)): return lhsValue == rhsValue - default: return false - } - } - - public static var allCases: [Episode] { - return [ - .newhope, - .empire, - .jedi, - ] - } -} - -/// The input object sent when someone is creating a new review -public struct ReviewInput: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - stars: 0-5 stars - /// - commentary: Comment about the movie, optional - /// - favoriteColor: Favorite color, optional - public init(stars: Int, commentary: Swift.Optional = nil, favoriteColor: Swift.Optional = nil) { - graphQLMap = ["stars": stars, "commentary": commentary, "favorite_color": favoriteColor] - } - - /// 0-5 stars - public var stars: Int { - get { - return graphQLMap["stars"] as! Int - } - set { - graphQLMap.updateValue(newValue, forKey: "stars") - } - } - - /// Comment about the movie, optional - public var commentary: Swift.Optional { - get { - return graphQLMap["commentary"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "commentary") - } - } - - /// Favorite color, optional - public var favoriteColor: Swift.Optional { - get { - return graphQLMap["favorite_color"] as? Swift.Optional ?? Swift.Optional.none - } - set { - graphQLMap.updateValue(newValue, forKey: "favorite_color") - } - } -} - -/// The input object sent when passing in a color -public struct ColorInput: GraphQLMapConvertible { - public var graphQLMap: GraphQLMap - - /// - Parameters: - /// - red - /// - green - /// - blue - public init(red: Int, green: Int, blue: Int) { - graphQLMap = ["red": red, "green": green, "blue": blue] - } - - public var red: Int { - get { - return graphQLMap["red"] as! Int - } - set { - graphQLMap.updateValue(newValue, forKey: "red") - } - } - - public var green: Int { - get { - return graphQLMap["green"] as! Int - } - set { - graphQLMap.updateValue(newValue, forKey: "green") - } - } - - public var blue: Int { - get { - return graphQLMap["blue"] as! Int - } - set { - graphQLMap.updateValue(newValue, forKey: "blue") - } - } -} - -public final class CreateReviewForEpisodeMutation: GraphQLMutation { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) { - createReview(episode: $episode, review: $review) { - __typename - stars - commentary - } - } - """ - - public let operationName: String = "CreateReviewForEpisode" - - public let operationIdentifier: String? = "9bbf5b4074d0635fb19d17c621b7b04ebfb1920d468a94266819e149841e7d5d" - - public var episode: Episode - public var review: ReviewInput - - public init(episode: Episode, review: ReviewInput) { - self.episode = episode - self.review = review - } - - public var variables: GraphQLMap? { - return ["episode": episode, "review": review] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Mutation"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("createReview", arguments: ["episode": GraphQLVariable("episode"), "review": GraphQLVariable("review")], type: .object(CreateReview.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(createReview: CreateReview? = nil) { - self.init(unsafeResultMap: ["__typename": "Mutation", "createReview": createReview.flatMap { (value: CreateReview) -> ResultMap in value.resultMap }]) - } - - public var createReview: CreateReview? { - get { - return (resultMap["createReview"] as? ResultMap).flatMap { CreateReview(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "createReview") - } - } - - public struct CreateReview: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Review"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("stars", type: .nonNull(.scalar(Int.self))), - GraphQLField("commentary", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(stars: Int, commentary: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Review", "stars": stars, "commentary": commentary]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The number of stars this review gave, 1-5 - public var stars: Int { - get { - return resultMap["stars"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "stars") - } - } - - /// Comment about the movie - public var commentary: String? { - get { - return resultMap["commentary"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "commentary") - } - } - } - } -} - -public final class CreateAwesomeReviewMutation: GraphQLMutation { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - mutation CreateAwesomeReview { - createReview(episode: JEDI, review: {stars: 10, commentary: "This is awesome!"}) { - __typename - stars - commentary - } - } - """ - - public let operationName: String = "CreateAwesomeReview" - - public let operationIdentifier: String? = "4a1250de93ebcb5cad5870acf15001112bf27bb963e8709555b5ff67a1405374" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Mutation"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("createReview", arguments: ["episode": "JEDI", "review": ["stars": 10, "commentary": "This is awesome!"]], type: .object(CreateReview.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(createReview: CreateReview? = nil) { - self.init(unsafeResultMap: ["__typename": "Mutation", "createReview": createReview.flatMap { (value: CreateReview) -> ResultMap in value.resultMap }]) - } - - public var createReview: CreateReview? { - get { - return (resultMap["createReview"] as? ResultMap).flatMap { CreateReview(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "createReview") - } - } - - public struct CreateReview: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Review"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("stars", type: .nonNull(.scalar(Int.self))), - GraphQLField("commentary", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(stars: Int, commentary: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Review", "stars": stars, "commentary": commentary]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The number of stars this review gave, 1-5 - public var stars: Int { - get { - return resultMap["stars"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "stars") - } - } - - /// Comment about the movie - public var commentary: String? { - get { - return resultMap["commentary"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "commentary") - } - } - } - } -} - -public final class CreateReviewWithNullFieldMutation: GraphQLMutation { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - mutation CreateReviewWithNullField { - createReview(episode: JEDI, review: {stars: 10, commentary: null}) { - __typename - stars - commentary - } - } - """ - - public let operationName: String = "CreateReviewWithNullField" - - public let operationIdentifier: String? = "a9600d176cd7e4671b8689f1d01fe79ea896932bfafb8a925af673f0e4111828" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Mutation"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("createReview", arguments: ["episode": "JEDI", "review": ["stars": 10, "commentary": nil]], type: .object(CreateReview.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(createReview: CreateReview? = nil) { - self.init(unsafeResultMap: ["__typename": "Mutation", "createReview": createReview.flatMap { (value: CreateReview) -> ResultMap in value.resultMap }]) - } - - public var createReview: CreateReview? { - get { - return (resultMap["createReview"] as? ResultMap).flatMap { CreateReview(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "createReview") - } - } - - public struct CreateReview: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Review"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("stars", type: .nonNull(.scalar(Int.self))), - GraphQLField("commentary", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(stars: Int, commentary: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Review", "stars": stars, "commentary": commentary]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The number of stars this review gave, 1-5 - public var stars: Int { - get { - return resultMap["stars"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "stars") - } - } - - /// Comment about the movie - public var commentary: String? { - get { - return resultMap["commentary"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "commentary") - } - } - } - } -} - -public final class HeroAndFriendsNamesQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - __typename - name - friends { - __typename - name - } - } - } - """ - - public let operationName: String = "HeroAndFriendsNames" - - public let operationIdentifier: String? = "fe3f21394eb861aa515c4d582e645469045793c9cbbeca4b5d4ce4d7dd617556" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } -} - -public final class HeroAndFriendsNamesWithIDsQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAndFriendsNamesWithIDs($episode: Episode) { - hero(episode: $episode) { - __typename - id - name - friends { - __typename - id - name - } - } - } - """ - - public let operationName: String = "HeroAndFriendsNamesWithIDs" - - public let operationIdentifier: String? = "8e4ca76c63660898cfd5a3845e3709027750b5f0151c7f9be65759b869c5486d" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "id": id, "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(id: GraphQLID, name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "id": id, "name": name]) - } - - public static func makeDroid(id: GraphQLID, name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } -} - -public final class HeroAndFriendsIDsQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAndFriendsIDs($episode: Episode) { - hero(episode: $episode) { - __typename - id - name - friends { - __typename - id - } - } - } - """ - - public let operationName: String = "HeroAndFriendsIDs" - - public let operationIdentifier: String? = "117d0f6831d8f4abe5b61ed1dbb8071b0825e19649916c0fe0906a6f578bb088" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "id": id, "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(id: GraphQLID, name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "id": id]) - } - - public static func makeDroid(id: GraphQLID) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "id": id]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - } - } - } -} - -public final class HeroAndFriendsNamesWithIdForParentOnlyQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAndFriendsNamesWithIDForParentOnly($episode: Episode) { - hero(episode: $episode) { - __typename - id - name - friends { - __typename - name - } - } - } - """ - - public let operationName: String = "HeroAndFriendsNamesWithIDForParentOnly" - - public let operationIdentifier: String? = "f091468a629f3b757c03a1b7710c6ede8b5c8f10df7ba3238f2bbcd71c56f90f" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "id": id, "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(id: GraphQLID, name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } -} - -public final class HeroAndFriendsNamesWithFragmentQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAndFriendsNamesWithFragment($episode: Episode) { - hero(episode: $episode) { - __typename - name - ...FriendsNames - } - } - """ - - public let operationName: String = "HeroAndFriendsNamesWithFragment" - - public let operationIdentifier: String? = "1d3ad903dad146ff9d7aa09813fc01becd017489bfc1af8ffd178498730a5a26" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + FriendsNames.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(name: String, friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var friendsNames: FriendsNames { - get { - return FriendsNames(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } -} - -public final class HeroAndFriendsNamesWithFragmentTwiceQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAndFriendsNamesWithFragmentTwice($episode: Episode) { - hero(episode: $episode) { - __typename - friends { - __typename - ...CharacterName - } - ... on Droid { - __typename - friends { - __typename - ...CharacterName - } - } - } - } - """ - - public let operationName: String = "HeroAndFriendsNamesWithFragmentTwice" - - public let operationIdentifier: String? = "b5f4eca712a136f0d5d9f96203ef7d03cd119d8388f093f4b78ae124acb904cb" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + CharacterName.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(friends: [AsDroid.Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "friends": friends.flatMap { (value: [AsDroid.Friend?]) -> [ResultMap?] in value.map { (value: AsDroid.Friend?) -> ResultMap? in value.flatMap { (value: AsDroid.Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(friends: [Friend?]? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// This droid's friends, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } - } - } -} - -public final class HeroAppearsInQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAppearsIn { - hero { - __typename - appearsIn - } - } - """ - - public let operationName: String = "HeroAppearsIn" - - public let operationIdentifier: String? = "22d772c0fc813281705e8f0a55fc70e71eeff6e98f3f9ef96cf67fb896914522" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "appearsIn": appearsIn]) - } - - public static func makeDroid(appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - } - } -} - -public final class HeroAppearsInWithFragmentQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroAppearsInWithFragment($episode: Episode) { - hero(episode: $episode) { - __typename - ...CharacterAppearsIn - } - } - """ - - public let operationName: String = "HeroAppearsInWithFragment" - - public let operationIdentifier: String? = "1756158bd7736d58db45a48d74a724fa1b6fdac735376df8afac8318ba5431fb" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + CharacterAppearsIn.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "appearsIn": appearsIn]) - } - - public static func makeDroid(appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterAppearsIn: CharacterAppearsIn { - get { - return CharacterAppearsIn(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } -} - -public final class HeroNameConditionalExclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameConditionalExclusion($skipName: Boolean!) { - hero { - __typename - name @skip(if: $skipName) - } - } - """ - - public let operationName: String = "HeroNameConditionalExclusion" - - public let operationIdentifier: String? = "3dd42259adf2d0598e89e0279bee2c128a7913f02b1da6aa43f3b5def6a8a1f8" - - public var skipName: Bool - - public init(skipName: Bool) { - self.skipName = skipName - } - - public var variables: GraphQLMap? { - return ["skipName": skipName] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "skipName", inverted: true, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public final class HeroNameConditionalInclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameConditionalInclusion($includeName: Boolean!) { - hero { - __typename - name @include(if: $includeName) - } - } - """ - - public let operationName: String = "HeroNameConditionalInclusion" - - public let operationIdentifier: String? = "338081aea3acc83d04af0741ecf0da1ec2ee8e6468a88383476b681015905ef8" - - public var includeName: Bool - - public init(includeName: Bool) { - self.includeName = includeName - } - - public var variables: GraphQLMap? { - return ["includeName": includeName] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeName", inverted: false, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public final class HeroNameConditionalBothQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameConditionalBoth($skipName: Boolean!, $includeName: Boolean!) { - hero { - __typename - name @skip(if: $skipName) @include(if: $includeName) - } - } - """ - - public let operationName: String = "HeroNameConditionalBoth" - - public let operationIdentifier: String? = "66f4dc124b6374b1912b22a2a208e34a4b1997349402a372b95bcfafc7884064" - - public var skipName: Bool - public var includeName: Bool - - public init(skipName: Bool, includeName: Bool) { - self.skipName = skipName - self.includeName = includeName - } - - public var variables: GraphQLMap? { - return ["skipName": skipName, "includeName": includeName] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeName", inverted: false, selections: [ - GraphQLBooleanCondition(variableName: "skipName", inverted: true, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public final class HeroNameConditionalBothSeparateQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameConditionalBothSeparate($skipName: Boolean!, $includeName: Boolean!) { - hero { - __typename - name @skip(if: $skipName) - name @include(if: $includeName) - } - } - """ - - public let operationName: String = "HeroNameConditionalBothSeparate" - - public let operationIdentifier: String? = "d0f9e9205cdc09320035662f528a177654d3275b0bf94cf0e259a65fde33e7e5" - - public var skipName: Bool - public var includeName: Bool - - public init(skipName: Bool, includeName: Bool) { - self.skipName = skipName - self.includeName = includeName - } - - public var variables: GraphQLMap? { - return ["skipName": skipName, "includeName": includeName] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "skipName", inverted: true, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - GraphQLBooleanCondition(variableName: "includeName", inverted: false, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public final class HeroDetailsInlineConditionalInclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroDetailsInlineConditionalInclusion($includeDetails: Boolean!) { - hero { - __typename - ... @include(if: $includeDetails) { - __typename - name - appearsIn - } - } - } - """ - - public let operationName: String = "HeroDetailsInlineConditionalInclusion" - - public let operationIdentifier: String? = "3091d9d3f1d2374e2f835ce05d332e50b3fe61502d73213b9aa511f0f94f091c" - - public var includeDetails: Bool - - public init(includeDetails: Bool) { - self.includeDetails = includeDetails - } - - public var variables: GraphQLMap? { - return ["includeDetails": includeDetails] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil, appearsIn: [Episode?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "appearsIn": appearsIn]) - } - - public static func makeDroid(name: String? = nil, appearsIn: [Episode?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?]? { - get { - return resultMap["appearsIn"] as? [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - } - } -} - -public final class HeroDetailsFragmentConditionalInclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroDetailsFragmentConditionalInclusion($includeDetails: Boolean!) { - hero { - __typename - ...HeroDetails @include(if: $includeDetails) - } - } - """ - - public let operationName: String = "HeroDetailsFragmentConditionalInclusion" - - public let operationIdentifier: String? = "b0fa7927ff93b4a579c3460fb04d093072d34c8018e41197c7e080aeeec5e19b" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + HeroDetails.fragmentDefinition) - return document - } - - public var includeDetails: Bool - - public init(includeDetails: Bool) { - self.includeDetails = includeDetails - } - - public var variables: GraphQLMap? { - return ["includeDetails": includeDetails] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil, height: Double? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public static func makeDroid(name: String? = nil, primaryFunction: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var heroDetails: HeroDetails { - get { - return HeroDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - GraphQLBooleanCondition(variableName: "includeDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", type: .scalar(Double.self)), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String? = nil, height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var heroDetails: HeroDetails { - get { - return HeroDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - GraphQLBooleanCondition(variableName: "includeDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String? = nil, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var heroDetails: HeroDetails { - get { - return HeroDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } - } -} - -public final class HeroNameTypeSpecificConditionalInclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameTypeSpecificConditionalInclusion($episode: Episode, $includeName: Boolean!) { - hero(episode: $episode) { - __typename - name @include(if: $includeName) - ... on Droid { - __typename - name - } - } - } - """ - - public let operationName: String = "HeroNameTypeSpecificConditionalInclusion" - - public let operationIdentifier: String? = "76aecc75265295818d3990000b17e32d5524ca85a4bc159ae8a3f8ec7ce91cc3" - - public var episode: Episode? - public var includeName: Bool - - public init(episode: Episode? = nil, includeName: Bool) { - self.episode = episode - self.includeName = includeName - } - - public var variables: GraphQLMap? { - return ["episode": episode, "includeName": includeName] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeName", inverted: false, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String? { - get { - return resultMap["name"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeName", inverted: false, selections: [ - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } -} - -public final class HeroFriendsDetailsConditionalInclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroFriendsDetailsConditionalInclusion($includeFriendsDetails: Boolean!) { - hero { - __typename - friends @include(if: $includeFriendsDetails) { - __typename - name - ... on Droid { - __typename - primaryFunction - } - } - } - } - """ - - public let operationName: String = "HeroFriendsDetailsConditionalInclusion" - - public let operationIdentifier: String? = "8cada231691ff2f5a0a07c54b7332114588f11b947795da345c5b054211fbcfd" - - public var includeFriendsDetails: Bool - - public init(includeFriendsDetails: Bool) { - self.includeFriendsDetails = includeFriendsDetails - } - - public var variables: GraphQLMap? { - return ["includeFriendsDetails": includeFriendsDetails] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeFriendsDetails", inverted: false, selections: [ - GraphQLField("friends", type: .list(.object(Friend.selections))), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - } - } - } - } -} - -public final class HeroFriendsDetailsUnconditionalAndConditionalInclusionQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroFriendsDetailsUnconditionalAndConditionalInclusion($includeFriendsDetails: Boolean!) { - hero { - __typename - friends { - __typename - name - } - friends @include(if: $includeFriendsDetails) { - __typename - name - ... on Droid { - __typename - primaryFunction - } - } - } - } - """ - - public let operationName: String = "HeroFriendsDetailsUnconditionalAndConditionalInclusion" - - public let operationIdentifier: String? = "65381a20574db4b458a0821328252deb0da1a107f9ab77c99fb2467e66a5f12d" - - public var includeFriendsDetails: Bool - - public init(includeFriendsDetails: Bool) { - self.includeFriendsDetails = includeFriendsDetails - } - - public var variables: GraphQLMap? { - return ["includeFriendsDetails": includeFriendsDetails] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - GraphQLBooleanCondition(variableName: "includeFriendsDetails", inverted: false, selections: [ - GraphQLField("friends", type: .list(.object(Friend.selections))), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeFriendsDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLBooleanCondition(variableName: "includeFriendsDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ]), - GraphQLBooleanCondition(variableName: "includeFriendsDetails", inverted: false, selections: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ]), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - } - } - } - } -} - -public final class HeroDetailsQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroDetails($episode: Episode) { - hero(episode: $episode) { - __typename - name - ... on Human { - __typename - height - } - ... on Droid { - __typename - primaryFunction - } - } - } - """ - - public let operationName: String = "HeroDetails" - - public let operationIdentifier: String? = "207d29944f5822bff08a07db4a55274ea14035bacfe20699da41a47454f1181e" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, height: Double? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - } - } - } -} - -public final class HeroDetailsWithFragmentQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroDetailsWithFragment($episode: Episode) { - hero(episode: $episode) { - __typename - ...HeroDetails - } - } - """ - - public let operationName: String = "HeroDetailsWithFragment" - - public let operationIdentifier: String? = "b55bd9d56d1b5972345412b6adb88ceb64d6086c8051d2588d8ab701f0ee7c2f" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + HeroDetails.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, height: Double? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var heroDetails: HeroDetails { - get { - return HeroDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var heroDetails: HeroDetails { - get { - return HeroDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var heroDetails: HeroDetails { - get { - return HeroDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } - } -} - -public final class DroidDetailsWithFragmentQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query DroidDetailsWithFragment($episode: Episode) { - hero(episode: $episode) { - __typename - ...DroidDetails - } - } - """ - - public let operationName: String = "DroidDetailsWithFragment" - - public let operationIdentifier: String? = "7277e97563e911ac8f5c91d401028d218aae41f38df014d7fa0b037bb2a2e739" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + DroidDetails.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman() -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human"]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var droidDetails: DroidDetails? { - get { - if !DroidDetails.possibleTypes.contains(resultMap["__typename"]! as! String) { return nil } - return DroidDetails(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap += newValue.resultMap - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var droidDetails: DroidDetails { - get { - return DroidDetails(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } - } -} - -public final class HeroFriendsOfFriendsNamesQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroFriendsOfFriendsNames($episode: Episode) { - hero(episode: $episode) { - __typename - friends { - __typename - id - friends { - __typename - name - } - } - } - } - """ - - public let operationName: String = "HeroFriendsOfFriendsNames" - - public let operationIdentifier: String? = "37cd5626048e7243716ffda9e56503939dd189772124a1c21b0e0b87e69aae01" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(friends: [Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, friends: [Friend?]? = nil) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "id": id, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(id: GraphQLID, friends: [Friend?]? = nil) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "id": id, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } - } -} - -public final class HeroNameQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroName($episode: Episode) { - hero(episode: $episode) { - __typename - name - } - } - """ - - public let operationName: String = "HeroName" - - public let operationIdentifier: String? = "f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public final class HeroNameWithIdQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameWithID($episode: Episode) { - hero(episode: $episode) { - __typename - id - name - } - } - """ - - public let operationName: String = "HeroNameWithID" - - public let operationIdentifier: String? = "83c03f612c46fca72f6cb902df267c57bffc9209bc44dd87d2524fb2b34f6f18" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "id": id, "name": name]) - } - - public static func makeDroid(id: GraphQLID, name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public final class HeroNameWithFragmentQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameWithFragment($episode: Episode) { - hero(episode: $episode) { - __typename - ...CharacterName - } - } - """ - - public let operationName: String = "HeroNameWithFragment" - - public let operationIdentifier: String? = "b952f0054915a32ec524ac0dde0244bcda246649debe149f9e32e303e21c8266" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + CharacterName.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } -} - -public final class HeroNameWithFragmentAndIdQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameWithFragmentAndID($episode: Episode) { - hero(episode: $episode) { - __typename - id - ...CharacterName - } - } - """ - - public let operationName: String = "HeroNameWithFragmentAndID" - - public let operationIdentifier: String? = "a87a0694c09d1ed245e9a80f245d96a5f57b20a4aa936ee9ab09b2a43620db02" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + CharacterName.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "id": id, "name": name]) - } - - public static func makeDroid(id: GraphQLID, name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the character - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } -} - -public final class HeroNameAndAppearsInQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameAndAppearsIn($episode: Episode) { - hero(episode: $episode) { - __typename - name - appearsIn - } - } - """ - - public let operationName: String = "HeroNameAndAppearsIn" - - public let operationIdentifier: String? = "f714414a2002404f9943490c8cc9c1a7b8ecac3ca229fa5a326186b43c1385ce" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "appearsIn": appearsIn]) - } - - public static func makeDroid(name: String, appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - } - } -} - -public final class HeroNameAndAppearsInWithFragmentQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroNameAndAppearsInWithFragment($episode: Episode) { - hero(episode: $episode) { - __typename - ...CharacterNameAndAppearsIn - } - } - """ - - public let operationName: String = "HeroNameAndAppearsInWithFragment" - - public let operationIdentifier: String? = "0664fed3eb4f9fbdb44e8691d9e8fd11f2b3c097ba11327592054f602bd3ba1a" - - public var queryDocument: String { - var document: String = operationDefinition - document.append("\n" + CharacterNameAndAppearsIn.fragmentDefinition) - return document - } - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "appearsIn": appearsIn]) - } - - public static func makeDroid(name: String, appearsIn: [Episode?]) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterNameAndAppearsIn: CharacterNameAndAppearsIn { - get { - return CharacterNameAndAppearsIn(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } - } -} - -public final class HeroParentTypeDependentFieldQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroParentTypeDependentField($episode: Episode) { - hero(episode: $episode) { - __typename - name - ... on Human { - __typename - friends { - __typename - name - ... on Human { - __typename - height(unit: FOOT) - } - } - } - ... on Droid { - __typename - friends { - __typename - name - ... on Human { - __typename - height(unit: METER) - } - } - } - } - } - """ - - public let operationName: String = "HeroParentTypeDependentField" - - public let operationIdentifier: String? = "39eb41b5a9477c36fa529c23d6f0de6ebcc0312daf5bdcfe208d5baec752dc5b" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, friends: [AsHuman.Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name, "friends": friends.flatMap { (value: [AsHuman.Friend?]) -> [ResultMap?] in value.map { (value: AsHuman.Friend?) -> ResultMap? in value.flatMap { (value: AsHuman.Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(name: String, friends: [AsDroid.Friend?]? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name, "friends": friends.flatMap { (value: [AsDroid.Friend?]) -> [ResultMap?] in value.map { (value: AsDroid.Friend?) -> ResultMap? in value.flatMap { (value: AsDroid.Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, friends: [Friend?]? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This human's friends, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public static func makeHuman(name: String, height: Double? = nil) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", arguments: ["unit": "FOOT"], type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, friends: [Friend?]? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's friends, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public static func makeHuman(name: String, height: Double? = nil) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", arguments: ["unit": "METER"], type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } - } - } - } - } - } -} - -public final class HeroTypeDependentAliasedFieldQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query HeroTypeDependentAliasedField($episode: Episode) { - hero(episode: $episode) { - __typename - ... on Human { - __typename - property: homePlanet - } - ... on Droid { - __typename - property: primaryFunction - } - } - } - """ - - public let operationName: String = "HeroTypeDependentAliasedField" - - public let operationIdentifier: String? = "eac5a52f9020fc2e9b5dc5facfd6a6295683b8d57ea62ee84254069fcd5e504c" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .object(Hero.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(property: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "property": property]) - } - - public static func makeDroid(property: String? = nil) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "property": property]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("homePlanet", alias: "property", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(property: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "property": property]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The home planet of the human, or null if unknown - public var property: String? { - get { - return resultMap["property"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "property") - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", alias: "property", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(property: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "property": property]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// This droid's primary function - public var property: String? { - get { - return resultMap["property"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "property") - } - } - } - } - } -} - -public final class SameHeroTwiceQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query SameHeroTwice { - hero { - __typename - name - } - r2: hero { - __typename - appearsIn - } - } - """ - - public let operationName: String = "SameHeroTwice" - - public let operationIdentifier: String? = "2a8ad85a703add7d64622aaf6be76b58a1134caf28e4ff6b34dd00ba89541364" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", type: .object(Hero.selections)), - GraphQLField("hero", alias: "r2", type: .object(R2.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(hero: Hero? = nil, r2: R2? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "hero": hero.flatMap { (value: Hero) -> ResultMap in value.resultMap }, "r2": r2.flatMap { (value: R2) -> ResultMap in value.resultMap }]) - } - - public var hero: Hero? { - get { - return (resultMap["hero"] as? ResultMap).flatMap { Hero(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "hero") - } - } - - public var r2: R2? { - get { - return (resultMap["r2"] as? ResultMap).flatMap { R2(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "r2") - } - } - - public struct Hero: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Hero { - return Hero(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - - public struct R2: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(appearsIn: [Episode?]) -> R2 { - return R2(unsafeResultMap: ["__typename": "Human", "appearsIn": appearsIn]) - } - - public static func makeDroid(appearsIn: [Episode?]) -> R2 { - return R2(unsafeResultMap: ["__typename": "Droid", "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - } - } -} - -public final class SearchQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query Search($term: String) { - search(text: $term) { - __typename - ... on Human { - __typename - id - name - } - ... on Droid { - __typename - id - name - } - ... on Starship { - __typename - id - name - } - } - } - """ - - public let operationName: String = "Search" - - public let operationIdentifier: String? = "477b77c476899915498a56ae7bb835667b1e875cb94f6daa7f75e05018be2c3a" - - public var term: String? - - public init(term: String? = nil) { - self.term = term - } - - public var variables: GraphQLMap? { - return ["term": term] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("search", arguments: ["text": GraphQLVariable("term")], type: .list(.object(Search.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(search: [Search?]? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "search": search.flatMap { (value: [Search?]) -> [ResultMap?] in value.map { (value: Search?) -> ResultMap? in value.flatMap { (value: Search) -> ResultMap in value.resultMap } } }]) - } - - public var search: [Search?]? { - get { - return (resultMap["search"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Search?] in value.map { (value: ResultMap?) -> Search? in value.flatMap { (value: ResultMap) -> Search in Search(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Search?]) -> [ResultMap?] in value.map { (value: Search?) -> ResultMap? in value.flatMap { (value: Search) -> ResultMap in value.resultMap } } }, forKey: "search") - } - } - - public struct Search: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid", "Starship"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections, "Starship": AsStarship.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(id: GraphQLID, name: String) -> Search { - return Search(unsafeResultMap: ["__typename": "Human", "id": id, "name": name]) - } - - public static func makeDroid(id: GraphQLID, name: String) -> Search { - return Search(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name]) - } - - public static func makeStarship(id: GraphQLID, name: String) -> Search { - return Search(unsafeResultMap: ["__typename": "Starship", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID, name: String) { - self.init(unsafeResultMap: ["__typename": "Human", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the human - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID, name: String) { - self.init(unsafeResultMap: ["__typename": "Droid", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the droid - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - - public var asStarship: AsStarship? { - get { - if !AsStarship.possibleTypes.contains(__typename) { return nil } - return AsStarship(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsStarship: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Starship"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID, name: String) { - self.init(unsafeResultMap: ["__typename": "Starship", "id": id, "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The ID of the starship - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - /// The name of the starship - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } - } -} - -public final class StarshipQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query Starship { - starship(id: 3000) { - __typename - name - coordinates - } - } - """ - - public let operationName: String = "Starship" - - public let operationIdentifier: String? = "a3734516185da9919e3e66d74fe92b60d65292a1943dc54913f7332637dfdd2a" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("starship", arguments: ["id": 3000], type: .object(Starship.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(starship: Starship? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "starship": starship.flatMap { (value: Starship) -> ResultMap in value.resultMap }]) - } - - public var starship: Starship? { - get { - return (resultMap["starship"] as? ResultMap).flatMap { Starship(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "starship") - } - } - - public struct Starship: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Starship"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("coordinates", type: .list(.nonNull(.list(.nonNull(.scalar(Double.self)))))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, coordinates: [[Double]]? = nil) { - self.init(unsafeResultMap: ["__typename": "Starship", "name": name, "coordinates": coordinates]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the starship - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var coordinates: [[Double]]? { - get { - return resultMap["coordinates"] as? [[Double]] - } - set { - resultMap.updateValue(newValue, forKey: "coordinates") - } - } - } - } -} - -public final class StarshipCoordinatesQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query StarshipCoordinates($coordinates: [[Float!]!]) { - starshipCoordinates(coordinates: $coordinates) { - __typename - name - coordinates - length - } - } - """ - - public let operationName: String = "StarshipCoordinates" - - public let operationIdentifier: String? = "8dd77d4bc7494c184606da092a665a7c2ca3c2a3f14d3b23fa5e469e207b3406" - - public var coordinates: [[Double]]? - - public init(coordinates: [[Double]]?) { - self.coordinates = coordinates - } - - public var variables: GraphQLMap? { - return ["coordinates": coordinates] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("starshipCoordinates", arguments: ["coordinates": GraphQLVariable("coordinates")], type: .object(StarshipCoordinate.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(starshipCoordinates: StarshipCoordinate? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "starshipCoordinates": starshipCoordinates.flatMap { (value: StarshipCoordinate) -> ResultMap in value.resultMap }]) - } - - public var starshipCoordinates: StarshipCoordinate? { - get { - return (resultMap["starshipCoordinates"] as? ResultMap).flatMap { StarshipCoordinate(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "starshipCoordinates") - } - } - - public struct StarshipCoordinate: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Starship"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("coordinates", type: .list(.nonNull(.list(.nonNull(.scalar(Double.self)))))), - GraphQLField("length", type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, coordinates: [[Double]]? = nil, length: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Starship", "name": name, "coordinates": coordinates, "length": length]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the starship - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var coordinates: [[Double]]? { - get { - return resultMap["coordinates"] as? [[Double]] - } - set { - resultMap.updateValue(newValue, forKey: "coordinates") - } - } - - /// Length of the starship, along the longest axis - public var length: Double? { - get { - return resultMap["length"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "length") - } - } - } - } -} - -public final class ReviewAddedSubscription: GraphQLSubscription { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - subscription ReviewAdded($episode: Episode) { - reviewAdded(episode: $episode) { - __typename - episode - stars - commentary - } - } - """ - - public let operationName: String = "ReviewAdded" - - public let operationIdentifier: String? = "38644c5e7cf4fd506b91d2e7010cabf84e63dfcd33cf1deb443b4b32b55e2cbe" - - public var episode: Episode? - - public init(episode: Episode? = nil) { - self.episode = episode - } - - public var variables: GraphQLMap? { - return ["episode": episode] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Subscription"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("reviewAdded", arguments: ["episode": GraphQLVariable("episode")], type: .object(ReviewAdded.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(reviewAdded: ReviewAdded? = nil) { - self.init(unsafeResultMap: ["__typename": "Subscription", "reviewAdded": reviewAdded.flatMap { (value: ReviewAdded) -> ResultMap in value.resultMap }]) - } - - public var reviewAdded: ReviewAdded? { - get { - return (resultMap["reviewAdded"] as? ResultMap).flatMap { ReviewAdded(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "reviewAdded") - } - } - - public struct ReviewAdded: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Review"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("episode", type: .scalar(Episode.self)), - GraphQLField("stars", type: .nonNull(.scalar(Int.self))), - GraphQLField("commentary", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(episode: Episode? = nil, stars: Int, commentary: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Review", "episode": episode, "stars": stars, "commentary": commentary]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The movie - public var episode: Episode? { - get { - return resultMap["episode"] as? Episode - } - set { - resultMap.updateValue(newValue, forKey: "episode") - } - } - - /// The number of stars this review gave, 1-5 - public var stars: Int { - get { - return resultMap["stars"]! as! Int - } - set { - resultMap.updateValue(newValue, forKey: "stars") - } - } - - /// Comment about the movie - public var commentary: String? { - get { - return resultMap["commentary"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "commentary") - } - } - } - } -} - -public final class HumanQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query Human($id: ID!) { - human(id: $id) { - __typename - name - mass - } - } - """ - - public let operationName: String = "Human" - - public let operationIdentifier: String? = "b37eb69b82fd52358321e49453769750983be1c286744dbf415735d7bcf12f1e" - - public var id: GraphQLID - - public init(id: GraphQLID) { - self.id = id - } - - public var variables: GraphQLMap? { - return ["id": id] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("human", arguments: ["id": GraphQLVariable("id")], type: .object(Human.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(human: Human? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "human": human.flatMap { (value: Human) -> ResultMap in value.resultMap }]) - } - - public var human: Human? { - get { - return (resultMap["human"] as? ResultMap).flatMap { Human(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "human") - } - } - - public struct Human: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("mass", type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, mass: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "mass": mass]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Mass in kilograms, or null if unknown - public var mass: Double? { - get { - return resultMap["mass"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "mass") - } - } - } - } -} - -public final class TwoHeroesQuery: GraphQLQuery { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - query TwoHeroes { - r2: hero { - __typename - name - } - luke: hero(episode: EMPIRE) { - __typename - name - } - } - """ - - public let operationName: String = "TwoHeroes" - - public let operationIdentifier: String? = "b868fa9c48f19b8151c08c09f46831e3b9cd09f5c617d328647de785244b52bb" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Query"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("hero", alias: "r2", type: .object(R2.selections)), - GraphQLField("hero", alias: "luke", arguments: ["episode": "EMPIRE"], type: .object(Luke.selections)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(r2: R2? = nil, luke: Luke? = nil) { - self.init(unsafeResultMap: ["__typename": "Query", "r2": r2.flatMap { (value: R2) -> ResultMap in value.resultMap }, "luke": luke.flatMap { (value: Luke) -> ResultMap in value.resultMap }]) - } - - public var r2: R2? { - get { - return (resultMap["r2"] as? ResultMap).flatMap { R2(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "r2") - } - } - - public var luke: Luke? { - get { - return (resultMap["luke"] as? ResultMap).flatMap { Luke(unsafeResultMap: $0) } - } - set { - resultMap.updateValue(newValue?.resultMap, forKey: "luke") - } - } - - public struct R2: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> R2 { - return R2(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> R2 { - return R2(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - - public struct Luke: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Luke { - return Luke(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Luke { - return Luke(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public struct DroidNameAndPrimaryFunction: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment DroidNameAndPrimaryFunction on Droid { - __typename - ...CharacterName - ...DroidPrimaryFunction - } - """ - - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public var droidPrimaryFunction: DroidPrimaryFunction { - get { - return DroidPrimaryFunction(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } -} - -public struct CharacterNameAndDroidPrimaryFunction: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterNameAndDroidPrimaryFunction on Character { - __typename - ...CharacterName - ...DroidPrimaryFunction - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> CharacterNameAndDroidPrimaryFunction { - return CharacterNameAndDroidPrimaryFunction(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> CharacterNameAndDroidPrimaryFunction { - return CharacterNameAndDroidPrimaryFunction(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public var droidPrimaryFunction: DroidPrimaryFunction? { - get { - if !DroidPrimaryFunction.possibleTypes.contains(resultMap["__typename"]! as! String) { return nil } - return DroidPrimaryFunction(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap += newValue.resultMap - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public var droidPrimaryFunction: DroidPrimaryFunction { - get { - return DroidPrimaryFunction(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - } -} - -public struct CharacterNameAndDroidAppearsIn: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterNameAndDroidAppearsIn on Character { - __typename - name - ... on Droid { - __typename - appearsIn - } - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> CharacterNameAndDroidAppearsIn { - return CharacterNameAndDroidAppearsIn(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String, appearsIn: [Episode?]) -> CharacterNameAndDroidAppearsIn { - return CharacterNameAndDroidAppearsIn(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, appearsIn: [Episode?]) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this droid appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - } -} - -public struct DroidName: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment DroidName on Droid { - __typename - name - } - """ - - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } -} - -public struct DroidPrimaryFunction: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment DroidPrimaryFunction on Droid { - __typename - primaryFunction - } - """ - - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } -} - -public struct HumanHeightWithVariable: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment HumanHeightWithVariable on Human { - __typename - height(unit: $heightUnit) - } - """ - - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", arguments: ["unit": GraphQLVariable("heightUnit")], type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } -} - -public struct CharacterNameAndAppearsInWithNestedFragments: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterNameAndAppearsInWithNestedFragments on Character { - __typename - ...CharacterNameWithNestedAppearsInFragment - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, appearsIn: [Episode?]) -> CharacterNameAndAppearsInWithNestedFragments { - return CharacterNameAndAppearsInWithNestedFragments(unsafeResultMap: ["__typename": "Human", "name": name, "appearsIn": appearsIn]) - } - - public static func makeDroid(name: String, appearsIn: [Episode?]) -> CharacterNameAndAppearsInWithNestedFragments { - return CharacterNameAndAppearsInWithNestedFragments(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterNameWithNestedAppearsInFragment: CharacterNameWithNestedAppearsInFragment { - get { - return CharacterNameWithNestedAppearsInFragment(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public var characterAppearsIn: CharacterAppearsIn { - get { - return CharacterAppearsIn(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } -} - -public struct CharacterNameWithNestedAppearsInFragment: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterNameWithNestedAppearsInFragment on Character { - __typename - name - ...CharacterAppearsIn - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, appearsIn: [Episode?]) -> CharacterNameWithNestedAppearsInFragment { - return CharacterNameWithNestedAppearsInFragment(unsafeResultMap: ["__typename": "Human", "name": name, "appearsIn": appearsIn]) - } - - public static func makeDroid(name: String, appearsIn: [Episode?]) -> CharacterNameWithNestedAppearsInFragment { - return CharacterNameWithNestedAppearsInFragment(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterAppearsIn: CharacterAppearsIn { - get { - return CharacterAppearsIn(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } -} - -public struct CharacterNameWithInlineFragment: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterNameWithInlineFragment on Character { - __typename - ... on Human { - __typename - friends { - __typename - appearsIn - } - } - ... on Droid { - __typename - ...CharacterName - ...FriendsNames - } - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(friends: [AsHuman.Friend?]? = nil) -> CharacterNameWithInlineFragment { - return CharacterNameWithInlineFragment(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [AsHuman.Friend?]) -> [ResultMap?] in value.map { (value: AsHuman.Friend?) -> ResultMap? in value.flatMap { (value: AsHuman.Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(name: String, friends: [AsDroid.Friend?]? = nil) -> CharacterNameWithInlineFragment { - return CharacterNameWithInlineFragment(unsafeResultMap: ["__typename": "Droid", "name": name, "friends": friends.flatMap { (value: [AsDroid.Friend?]) -> [ResultMap?] in value.map { (value: AsDroid.Friend?) -> ResultMap? in value.flatMap { (value: AsDroid.Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(friends: [Friend?]? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// This human's friends, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(appearsIn: [Episode?]) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "appearsIn": appearsIn]) - } - - public static func makeDroid(appearsIn: [Episode?]) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, friends: [Friend?]? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's friends, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public var fragments: Fragments { - get { - return Fragments(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public struct Fragments { - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public var characterName: CharacterName { - get { - return CharacterName(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - - public var friendsNames: FriendsNames { - get { - return FriendsNames(unsafeResultMap: resultMap) - } - set { - resultMap += newValue.resultMap - } - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } - } -} - -public struct FriendsNames: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment FriendsNames on Character { - __typename - friends { - __typename - name - } - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("friends", type: .list(.object(Friend.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(friends: [Friend?]? = nil) -> FriendsNames { - return FriendsNames(unsafeResultMap: ["__typename": "Human", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public static func makeDroid(friends: [Friend?]? = nil) -> FriendsNames { - return FriendsNames(unsafeResultMap: ["__typename": "Droid", "friends": friends.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The friends of the character, or an empty list if they have none - public var friends: [Friend?]? { - get { - return (resultMap["friends"] as? [ResultMap?]).flatMap { (value: [ResultMap?]) -> [Friend?] in value.map { (value: ResultMap?) -> Friend? in value.flatMap { (value: ResultMap) -> Friend in Friend(unsafeResultMap: value) } } } - } - set { - resultMap.updateValue(newValue.flatMap { (value: [Friend?]) -> [ResultMap?] in value.map { (value: Friend?) -> ResultMap? in value.flatMap { (value: Friend) -> ResultMap in value.resultMap } } }, forKey: "friends") - } - } - - public struct Friend: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> Friend { - return Friend(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - } -} - -public struct CharacterAppearsIn: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterAppearsIn on Character { - __typename - appearsIn - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(appearsIn: [Episode?]) -> CharacterAppearsIn { - return CharacterAppearsIn(unsafeResultMap: ["__typename": "Human", "appearsIn": appearsIn]) - } - - public static func makeDroid(appearsIn: [Episode?]) -> CharacterAppearsIn { - return CharacterAppearsIn(unsafeResultMap: ["__typename": "Droid", "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } -} - -public struct HeroDetails: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment HeroDetails on Character { - __typename - name - ... on Human { - __typename - height - } - ... on Droid { - __typename - primaryFunction - } - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLTypeCase( - variants: ["Human": AsHuman.selections, "Droid": AsDroid.selections], - default: [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - ) - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, height: Double? = nil) -> HeroDetails { - return HeroDetails(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public static func makeDroid(name: String, primaryFunction: String? = nil) -> HeroDetails { - return HeroDetails(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - public var asHuman: AsHuman? { - get { - if !AsHuman.possibleTypes.contains(__typename) { return nil } - return AsHuman(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsHuman: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Human"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("height", type: .scalar(Double.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, height: Double? = nil) { - self.init(unsafeResultMap: ["__typename": "Human", "name": name, "height": height]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What this human calls themselves - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// Height in the preferred unit, default is meters - public var height: Double? { - get { - return resultMap["height"] as? Double - } - set { - resultMap.updateValue(newValue, forKey: "height") - } - } - } - - public var asDroid: AsDroid? { - get { - if !AsDroid.possibleTypes.contains(__typename) { return nil } - return AsDroid(unsafeResultMap: resultMap) - } - set { - guard let newValue = newValue else { return } - resultMap = newValue.resultMap - } - } - - public struct AsDroid: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } - } -} - -public struct DroidDetails: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment DroidDetails on Droid { - __typename - name - primaryFunction - } - """ - - public static let possibleTypes: [String] = ["Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("primaryFunction", type: .scalar(String.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(name: String, primaryFunction: String? = nil) { - self.init(unsafeResultMap: ["__typename": "Droid", "name": name, "primaryFunction": primaryFunction]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// What others call this droid - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// This droid's primary function - public var primaryFunction: String? { - get { - return resultMap["primaryFunction"] as? String - } - set { - resultMap.updateValue(newValue, forKey: "primaryFunction") - } - } -} - -public struct CharacterName: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterName on Character { - __typename - name - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String) -> CharacterName { - return CharacterName(unsafeResultMap: ["__typename": "Human", "name": name]) - } - - public static func makeDroid(name: String) -> CharacterName { - return CharacterName(unsafeResultMap: ["__typename": "Droid", "name": name]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } -} - -public struct CharacterNameAndAppearsIn: GraphQLFragment { - /// The raw GraphQL definition of this fragment. - public static let fragmentDefinition: String = - """ - fragment CharacterNameAndAppearsIn on Character { - __typename - name - appearsIn - } - """ - - public static let possibleTypes: [String] = ["Human", "Droid"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("name", type: .nonNull(.scalar(String.self))), - GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public static func makeHuman(name: String, appearsIn: [Episode?]) -> CharacterNameAndAppearsIn { - return CharacterNameAndAppearsIn(unsafeResultMap: ["__typename": "Human", "name": name, "appearsIn": appearsIn]) - } - - public static func makeDroid(name: String, appearsIn: [Episode?]) -> CharacterNameAndAppearsIn { - return CharacterNameAndAppearsIn(unsafeResultMap: ["__typename": "Droid", "name": name, "appearsIn": appearsIn]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - /// The name of the character - public var name: String { - get { - return resultMap["name"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "name") - } - } - - /// The movies this character appears in - public var appearsIn: [Episode?] { - get { - return resultMap["appearsIn"]! as! [Episode?] - } - set { - resultMap.updateValue(newValue, forKey: "appearsIn") - } - } -} diff --git a/Sources/StarWarsAPI/Info.plist b/Sources/StarWarsAPI/Info.plist deleted file mode 100644 index 09738dfd75..0000000000 --- a/Sources/StarWarsAPI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/StarWarsAPI/StarWarsAPI.h b/Sources/StarWarsAPI/StarWarsAPI.h deleted file mode 100644 index 742b59d853..0000000000 --- a/Sources/StarWarsAPI/StarWarsAPI.h +++ /dev/null @@ -1,9 +0,0 @@ -#import - -//! Project version number for StarWarsAPI. -FOUNDATION_EXPORT double StarWarsAPIVersionNumber; - -//! Project version string for StarWarsAPI. -FOUNDATION_EXPORT const unsigned char StarWarsAPIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Sources/StarWarsAPI/graphql/API.json b/Sources/StarWarsAPI/graphql/API.json deleted file mode 100644 index 9d2e099e0a..0000000000 --- a/Sources/StarWarsAPI/graphql/API.json +++ /dev/null @@ -1,7590 +0,0 @@ -{ - "operations": [ - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CreateReviewForEpisode.graphql", - "operationName": "CreateReviewForEpisode", - "operationType": "mutation", - "rootType": "Mutation", - "variables": [ - { - "name": "episode", - "type": "Episode!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - { - "name": "review", - "type": "ReviewInput!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ReviewInput" - } - } - } - } - ], - "source": "mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) {\n createReview(episode: $episode, review: $review) {\n __typename\n stars\n commentary\n }\n}", - "fields": [ - { - "responseName": "createReview", - "fieldName": "createReview", - "type": "Review", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Review" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - }, - { - "name": "review", - "value": { - "kind": "Variable", - "variableName": "review" - }, - "type": "ReviewInput!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ReviewInput" - } - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "stars", - "fieldName": "stars", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "isConditional": false, - "description": "The number of stars this review gave, 1-5", - "isDeprecated": false - }, - { - "responseName": "commentary", - "fieldName": "commentary", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "Comment about the movie", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) {\n createReview(episode: $episode, review: $review) {\n __typename\n stars\n commentary\n }\n}", - "operationId": "9bbf5b4074d0635fb19d17c621b7b04ebfb1920d468a94266819e149841e7d5d" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CreateReviewForEpisode.graphql", - "operationName": "CreateAwesomeReview", - "operationType": "mutation", - "rootType": "Mutation", - "variables": [], - "source": "mutation CreateAwesomeReview {\n createReview(episode: JEDI, review: {stars: 10, commentary: \"This is awesome!\"}) {\n __typename\n stars\n commentary\n }\n}", - "fields": [ - { - "responseName": "createReview", - "fieldName": "createReview", - "type": "Review", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Review" - } - }, - "args": [ - { - "name": "episode", - "value": "JEDI", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - }, - { - "name": "review", - "value": { - "stars": 10, - "commentary": "This is awesome!" - }, - "type": "ReviewInput!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ReviewInput" - } - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "stars", - "fieldName": "stars", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "isConditional": false, - "description": "The number of stars this review gave, 1-5", - "isDeprecated": false - }, - { - "responseName": "commentary", - "fieldName": "commentary", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "Comment about the movie", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "mutation CreateAwesomeReview {\n createReview(episode: JEDI, review: {stars: 10, commentary: \"This is awesome!\"}) {\n __typename\n stars\n commentary\n }\n}", - "operationId": "4a1250de93ebcb5cad5870acf15001112bf27bb963e8709555b5ff67a1405374" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "operationName": "HeroAndFriendsNames", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAndFriendsNames($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n friends {\n __typename\n name\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroAndFriendsNames($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n friends {\n __typename\n name\n }\n }\n}", - "operationId": "fe3f21394eb861aa515c4d582e645469045793c9cbbeca4b5d4ce4d7dd617556" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "operationName": "HeroAndFriendsNamesWithIDs", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAndFriendsNamesWithIDs($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n id\n name\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroAndFriendsNamesWithIDs($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n id\n name\n }\n }\n}", - "operationId": "8e4ca76c63660898cfd5a3845e3709027750b5f0151c7f9be65759b869c5486d" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "operationName": "HeroAndFriendsIDs", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAndFriendsIDs($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n id\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroAndFriendsIDs($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n id\n }\n }\n}", - "operationId": "117d0f6831d8f4abe5b61ed1dbb8071b0825e19649916c0fe0906a6f578bb088" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "operationName": "HeroAndFriendsNamesWithIDForParentOnly", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAndFriendsNamesWithIDForParentOnly($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n name\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroAndFriendsNamesWithIDForParentOnly($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n name\n }\n }\n}", - "operationId": "f091468a629f3b757c03a1b7710c6ede8b5c8f10df7ba3238f2bbcd71c56f90f" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "operationName": "HeroAndFriendsNamesWithFragment", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAndFriendsNamesWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ...FriendsNames\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [ - "FriendsNames" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "FriendsNames" - ], - "sourceWithFragments": "query HeroAndFriendsNamesWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ...FriendsNames\n }\n}\nfragment FriendsNames on Character {\n __typename\n friends {\n __typename\n name\n }\n}", - "operationId": "1d3ad903dad146ff9d7aa09813fc01becd017489bfc1af8ffd178498730a5a26" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "operationName": "HeroAndFriendsNamesWithFragmentTwice", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAndFriendsNamesWithFragmentTwice($episode: Episode) {\n hero(episode: $episode) {\n __typename\n friends {\n __typename\n ...CharacterName\n }\n ... on Droid {\n friends {\n __typename\n ...CharacterName\n }\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "This droid's friends, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName", - "CharacterName" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "CharacterName" - ], - "sourceWithFragments": "query HeroAndFriendsNamesWithFragmentTwice($episode: Episode) {\n hero(episode: $episode) {\n __typename\n friends {\n __typename\n ...CharacterName\n }\n ... on Droid {\n friends {\n __typename\n ...CharacterName\n }\n }\n }\n}\nfragment CharacterName on Character {\n __typename\n name\n}", - "operationId": "e02ef22e116ad1ca35f0298ed3badb60eeb986203f0088575a5f137768c322fc" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAppearsIn.graphql", - "operationName": "HeroAppearsIn", - "operationType": "query", - "rootType": "Query", - "variables": [], - "source": "query HeroAppearsIn {\n hero {\n __typename\n appearsIn\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroAppearsIn {\n hero {\n __typename\n appearsIn\n }\n}", - "operationId": "22d772c0fc813281705e8f0a55fc70e71eeff6e98f3f9ef96cf67fb896914522" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAppearsIn.graphql", - "operationName": "HeroAppearsInWithFragment", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroAppearsInWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterAppearsIn\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterAppearsIn" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "CharacterAppearsIn" - ], - "sourceWithFragments": "query HeroAppearsInWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterAppearsIn\n }\n}\nfragment CharacterAppearsIn on Character {\n __typename\n appearsIn\n}", - "operationId": "1756158bd7736d58db45a48d74a724fa1b6fdac735376df8afac8318ba5431fb" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroNameConditionalExclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "skipName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroNameConditionalExclusion($skipName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName)\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "skipName", - "inverted": true - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameConditionalExclusion($skipName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName)\n }\n}", - "operationId": "3dd42259adf2d0598e89e0279bee2c128a7913f02b1da6aa43f3b5def6a8a1f8" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroNameConditionalInclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "includeName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroNameConditionalInclusion($includeName: Boolean!) {\n hero {\n __typename\n name @include(if: $includeName)\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeName", - "inverted": false - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameConditionalInclusion($includeName: Boolean!) {\n hero {\n __typename\n name @include(if: $includeName)\n }\n}", - "operationId": "338081aea3acc83d04af0741ecf0da1ec2ee8e6468a88383476b681015905ef8" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroNameConditionalBoth", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "skipName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - }, - { - "name": "includeName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroNameConditionalBoth($skipName: Boolean!, $includeName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName) @include(if: $includeName)\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeName", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "skipName", - "inverted": true - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameConditionalBoth($skipName: Boolean!, $includeName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName) @include(if: $includeName)\n }\n}", - "operationId": "66f4dc124b6374b1912b22a2a208e34a4b1997349402a372b95bcfafc7884064" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroNameConditionalBothSeparate", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "skipName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - }, - { - "name": "includeName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroNameConditionalBothSeparate($skipName: Boolean!, $includeName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName)\n name @include(if: $includeName)\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "skipName", - "inverted": true - }, - { - "kind": "BooleanCondition", - "variableName": "includeName", - "inverted": false - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameConditionalBothSeparate($skipName: Boolean!, $includeName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName)\n name @include(if: $includeName)\n }\n}", - "operationId": "d0f9e9205cdc09320035662f528a177654d3275b0bf94cf0e259a65fde33e7e5" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroDetailsInlineConditionalInclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "includeDetails", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroDetailsInlineConditionalInclusion($includeDetails: Boolean!) {\n hero {\n __typename\n ... @include(if: $includeDetails) {\n name\n appearsIn\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroDetailsInlineConditionalInclusion($includeDetails: Boolean!) {\n hero {\n __typename\n ... @include(if: $includeDetails) {\n name\n appearsIn\n }\n }\n}", - "operationId": "fcd9d7acb4e7c97e3ae5ad3cbf4e83556626149de589f0c2fce2f8ede31b0d90" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroDetailsFragmentConditionalInclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "includeDetails", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroDetailsFragmentConditionalInclusion($includeDetails: Boolean!) {\n hero {\n __typename\n ...HeroDetails @include(if: $includeDetails)\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "HeroDetails" - ], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "HeroDetails" - ] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeDetails", - "inverted": false - } - ], - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "HeroDetails" - ] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "HeroDetails" - ], - "sourceWithFragments": "query HeroDetailsFragmentConditionalInclusion($includeDetails: Boolean!) {\n hero {\n __typename\n ...HeroDetails @include(if: $includeDetails)\n }\n}\nfragment HeroDetails on Character {\n __typename\n name\n ... on Human {\n height\n }\n ... on Droid {\n primaryFunction\n }\n}", - "operationId": "b31aec7d977249e185922e4cc90318fd2c7197631470904bf937b0626de54b4f" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroNameTypeSpecificConditionalInclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - }, - { - "name": "includeName", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroNameTypeSpecificConditionalInclusion($episode: Episode, $includeName: Boolean!) {\n hero(episode: $episode) {\n __typename\n name @include(if: $includeName)\n ... on Droid {\n name\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeName", - "inverted": false - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeName", - "inverted": false - } - ], - "description": "What others call this droid", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameTypeSpecificConditionalInclusion($episode: Episode, $includeName: Boolean!) {\n hero(episode: $episode) {\n __typename\n name @include(if: $includeName)\n ... on Droid {\n name\n }\n }\n}", - "operationId": "4d465fbc6e3731d011025048502f16278307d73300ea9329a709d7e2b6815e40" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroFriendsDetailsConditionalInclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "includeFriendsDetails", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroFriendsDetailsConditionalInclusion($includeFriendsDetails: Boolean!) {\n hero {\n __typename\n friends @include(if: $includeFriendsDetails) {\n __typename\n name\n ... on Droid {\n primaryFunction\n }\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroFriendsDetailsConditionalInclusion($includeFriendsDetails: Boolean!) {\n hero {\n __typename\n friends @include(if: $includeFriendsDetails) {\n __typename\n name\n ... on Droid {\n primaryFunction\n }\n }\n }\n}", - "operationId": "9bdfeee789c1d22123402a9c3e3edefeb66799b3436289751be8f47905e3babd" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroConditional.graphql", - "operationName": "HeroFriendsDetailsUnconditionalAndConditionalInclusion", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "includeFriendsDetails", - "type": "Boolean!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Boolean" - } - } - } - } - ], - "source": "query HeroFriendsDetailsUnconditionalAndConditionalInclusion($includeFriendsDetails: Boolean!) {\n hero {\n __typename\n friends {\n __typename\n name\n }\n friends @include(if: $includeFriendsDetails) {\n __typename\n name\n ... on Droid {\n primaryFunction\n }\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - }, - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": true, - "conditions": [ - { - "kind": "BooleanCondition", - "variableName": "includeFriendsDetails", - "inverted": false - } - ], - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroFriendsDetailsUnconditionalAndConditionalInclusion($includeFriendsDetails: Boolean!) {\n hero {\n __typename\n friends {\n __typename\n name\n }\n friends @include(if: $includeFriendsDetails) {\n __typename\n name\n ... on Droid {\n primaryFunction\n }\n }\n }\n}", - "operationId": "501fcb710e5ffeeab2c65b7935fbded394ffea92e7b5dd904d05d5deab6f39c6" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroDetails.graphql", - "operationName": "HeroDetails", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroDetails($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ... on Human {\n height\n }\n ... on Droid {\n primaryFunction\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "isConditional": false, - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroDetails($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ... on Human {\n height\n }\n ... on Droid {\n primaryFunction\n }\n }\n}", - "operationId": "2b67111fd3a1c6b2ac7d1ef7764e5cefa41d3f4218e1d60cb67c22feafbd43ec" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroDetails.graphql", - "operationName": "HeroDetailsWithFragment", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroDetailsWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...HeroDetails\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "HeroDetails" - ], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "isConditional": false, - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "HeroDetails" - ] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "HeroDetails" - ] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "HeroDetails" - ], - "sourceWithFragments": "query HeroDetailsWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...HeroDetails\n }\n}\nfragment HeroDetails on Character {\n __typename\n name\n ... on Human {\n height\n }\n ... on Droid {\n primaryFunction\n }\n}", - "operationId": "d20fa2f460058b8eec3d227f2f6088a708cf35dfa2b5ebf1414e34f9674ecfce" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroDetails.graphql", - "operationName": "DroidDetailsWithFragment", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query DroidDetailsWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...DroidDetails\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "DroidDetails" - ], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "DroidDetails" - ] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "DroidDetails" - ], - "sourceWithFragments": "query DroidDetailsWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...DroidDetails\n }\n}\nfragment DroidDetails on Droid {\n __typename\n name\n primaryFunction\n}", - "operationId": "7277e97563e911ac8f5c91d401028d218aae41f38df014d7fa0b037bb2a2e739" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroFriendsOfFriends.graphql", - "operationName": "HeroFriendsOfFriendsNames", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroFriendsOfFriendsNames($episode: Episode) {\n hero(episode: $episode) {\n __typename\n friends {\n __typename\n id\n friends {\n __typename\n name\n }\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroFriendsOfFriendsNames($episode: Episode) {\n hero(episode: $episode) {\n __typename\n friends {\n __typename\n id\n friends {\n __typename\n name\n }\n }\n }\n}", - "operationId": "37cd5626048e7243716ffda9e56503939dd189772124a1c21b0e0b87e69aae01" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroName.graphql", - "operationName": "HeroName", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroName($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroName($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n }\n}", - "operationId": "f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroName.graphql", - "operationName": "HeroNameWithID", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroNameWithID($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameWithID($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n }\n}", - "operationId": "83c03f612c46fca72f6cb902df267c57bffc9209bc44dd87d2524fb2b34f6f18" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroName.graphql", - "operationName": "HeroNameWithFragment", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroNameWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterName\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "CharacterName" - ], - "sourceWithFragments": "query HeroNameWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterName\n }\n}\nfragment CharacterName on Character {\n __typename\n name\n}", - "operationId": "b952f0054915a32ec524ac0dde0244bcda246649debe149f9e32e303e21c8266" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroName.graphql", - "operationName": "HeroNameWithFragmentAndID", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroNameWithFragmentAndID($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n ...CharacterName\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the character", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "CharacterName" - ], - "sourceWithFragments": "query HeroNameWithFragmentAndID($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n ...CharacterName\n }\n}\nfragment CharacterName on Character {\n __typename\n name\n}", - "operationId": "a87a0694c09d1ed245e9a80f245d96a5f57b20a4aa936ee9ab09b2a43620db02" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroNameAndAppearsIn.graphql", - "operationName": "HeroNameAndAppearsIn", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroNameAndAppearsIn($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n appearsIn\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroNameAndAppearsIn($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n appearsIn\n }\n}", - "operationId": "f714414a2002404f9943490c8cc9c1a7b8ecac3ca229fa5a326186b43c1385ce" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroNameAndAppearsIn.graphql", - "operationName": "HeroNameAndAppearsInWithFragment", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroNameAndAppearsInWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterNameAndAppearsIn\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterNameAndAppearsIn" - ], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [ - "CharacterNameAndAppearsIn" - ], - "sourceWithFragments": "query HeroNameAndAppearsInWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterNameAndAppearsIn\n }\n}\nfragment CharacterNameAndAppearsIn on Character {\n __typename\n name\n appearsIn\n}", - "operationId": "0664fed3eb4f9fbdb44e8691d9e8fd11f2b3c097ba11327592054f602bd3ba1a" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroParentTypeDependentField.graphql", - "operationName": "HeroParentTypeDependentField", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroParentTypeDependentField($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ... on Human {\n friends {\n __typename\n name\n ... on Human {\n height(unit: FOOT)\n }\n }\n }\n ... on Droid {\n friends {\n __typename\n name\n ... on Human {\n height(unit: METER)\n }\n }\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "This human's friends, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "args": [ - { - "name": "unit", - "value": "FOOT", - "type": "LengthUnit", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "LengthUnit" - } - } - } - ], - "isConditional": false, - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "This droid's friends, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "args": [ - { - "name": "unit", - "value": "METER", - "type": "LengthUnit", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "LengthUnit" - } - } - } - ], - "isConditional": false, - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroParentTypeDependentField($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ... on Human {\n friends {\n __typename\n name\n ... on Human {\n height(unit: FOOT)\n }\n }\n }\n ... on Droid {\n friends {\n __typename\n name\n ... on Human {\n height(unit: METER)\n }\n }\n }\n }\n}", - "operationId": "561e22ac4da5209f254779b70e01557fb2fc57916b9914088429ec809e166cad" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroTypeDependentAliasedField.graphql", - "operationName": "HeroTypeDependentAliasedField", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "query HeroTypeDependentAliasedField($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ... on Human {\n property: homePlanet\n }\n ... on Droid {\n property: primaryFunction\n }\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "property", - "fieldName": "homePlanet", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "The home planet of the human, or null if unknown", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "property", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query HeroTypeDependentAliasedField($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ... on Human {\n property: homePlanet\n }\n ... on Droid {\n property: primaryFunction\n }\n }\n}", - "operationId": "b5838c22bac1c5626023dac4412ca9b86bebfe16608991fb632a37c44e12811e" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/SameHeroTwice.graphql", - "operationName": "SameHeroTwice", - "operationType": "query", - "rootType": "Query", - "variables": [], - "source": "query SameHeroTwice {\n hero {\n __typename\n name\n }\n r2: hero {\n __typename\n appearsIn\n }\n}", - "fields": [ - { - "responseName": "hero", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "responseName": "r2", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query SameHeroTwice {\n hero {\n __typename\n name\n }\n r2: hero {\n __typename\n appearsIn\n }\n}", - "operationId": "2a8ad85a703add7d64622aaf6be76b58a1134caf28e4ff6b34dd00ba89541364" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/Search.graphql", - "operationName": "Search", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "term", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - } - ], - "source": "query Search($term: String) {\n search(text: $term) {\n __typename\n ... on Human {\n id\n name\n }\n ... on Droid {\n id\n name\n }\n ... on Starship {\n id\n name\n }\n }\n}", - "fields": [ - { - "responseName": "search", - "fieldName": "search", - "type": "[SearchResult]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "SearchResult" - } - } - }, - "args": [ - { - "name": "text", - "value": { - "kind": "Variable", - "variableName": "term" - }, - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the human", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the droid", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Starship", - "possibleTypes": [ - "Starship" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "id", - "fieldName": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - }, - "isConditional": false, - "description": "The ID of the starship", - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the starship", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query Search($term: String) {\n search(text: $term) {\n __typename\n ... on Human {\n id\n name\n }\n ... on Droid {\n id\n name\n }\n ... on Starship {\n id\n name\n }\n }\n}", - "operationId": "73536da2eec4d83e6e1003e674cb2299d9da2798f7bd310e57339a6bcd713b77" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/Starship.graphql", - "operationName": "Starship", - "operationType": "query", - "rootType": "Query", - "variables": [], - "source": "query Starship {\n starship(id: 3000) {\n __typename\n name\n coordinates\n }\n}", - "fields": [ - { - "responseName": "starship", - "fieldName": "starship", - "type": "Starship", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Starship" - } - }, - "args": [ - { - "name": "id", - "value": 3000, - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the starship", - "isDeprecated": false - }, - { - "responseName": "coordinates", - "fieldName": "coordinates", - "type": "[[Float!]!]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - } - } - } - } - }, - "isConditional": false, - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query Starship {\n starship(id: 3000) {\n __typename\n name\n coordinates\n }\n}", - "operationId": "a3734516185da9919e3e66d74fe92b60d65292a1943dc54913f7332637dfdd2a" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/Starship.graphql", - "operationName": "StarshipCoordinates", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "coordinates", - "type": "[[Float!]!]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - } - } - } - } - } - } - ], - "source": "query StarshipCoordinates($coordinates: [[Float!]!]) {\n starshipCoordinates(coordinates: $coordinates) {\n __typename\n name\n coordinates\n length\n }\n}", - "fields": [ - { - "responseName": "starshipCoordinates", - "fieldName": "starshipCoordinates", - "type": "Starship", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Starship" - } - }, - "args": [ - { - "name": "coordinates", - "value": { - "kind": "Variable", - "variableName": "coordinates" - }, - "type": "[[Float!]!]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - } - } - } - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the starship", - "isDeprecated": false - }, - { - "responseName": "coordinates", - "fieldName": "coordinates", - "type": "[[Float!]!]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - } - } - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "length", - "fieldName": "length", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "isConditional": false, - "description": "Length of the starship, along the longest axis", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query StarshipCoordinates($coordinates: [[Float!]!]) {\n starshipCoordinates(coordinates: $coordinates) {\n __typename\n name\n coordinates\n length\n }\n}", - "operationId": "8dd77d4bc7494c184606da092a665a7c2ca3c2a3f14d3b23fa5e469e207b3406" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/SubscribeReview.graphql", - "operationName": "ReviewAdded", - "operationType": "subscription", - "rootType": "Subscription", - "variables": [ - { - "name": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "source": "subscription ReviewAdded($episode: Episode) {\n reviewAdded(episode: $episode) {\n __typename\n episode\n stars\n commentary\n }\n}", - "fields": [ - { - "responseName": "reviewAdded", - "fieldName": "reviewAdded", - "type": "Review", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Review" - } - }, - "args": [ - { - "name": "episode", - "value": { - "kind": "Variable", - "variableName": "episode" - }, - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "episode", - "fieldName": "episode", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - }, - "isConditional": false, - "description": "The movie", - "isDeprecated": false - }, - { - "responseName": "stars", - "fieldName": "stars", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "isConditional": false, - "description": "The number of stars this review gave, 1-5", - "isDeprecated": false - }, - { - "responseName": "commentary", - "fieldName": "commentary", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "Comment about the movie", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "subscription ReviewAdded($episode: Episode) {\n reviewAdded(episode: $episode) {\n __typename\n episode\n stars\n commentary\n }\n}", - "operationId": "38644c5e7cf4fd506b91d2e7010cabf84e63dfcd33cf1deb443b4b32b55e2cbe" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/TestFolder/TestFolder2/Human.graphql", - "operationName": "Human", - "operationType": "query", - "rootType": "Query", - "variables": [ - { - "name": "id", - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - } - } - ], - "source": "query Human($id: ID!) {\n human(id: $id) {\n __typename\n name\n mass\n }\n}", - "fields": [ - { - "responseName": "human", - "fieldName": "human", - "type": "Human", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Human" - } - }, - "args": [ - { - "name": "id", - "value": { - "kind": "Variable", - "variableName": "id" - }, - "type": "ID!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ID" - } - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "mass", - "fieldName": "mass", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "isConditional": false, - "description": "Mass in kilograms, or null if unknown", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query Human($id: ID!) {\n human(id: $id) {\n __typename\n name\n mass\n }\n}", - "operationId": "b37eb69b82fd52358321e49453769750983be1c286744dbf415735d7bcf12f1e" - }, - { - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/TwoHeroes.graphql", - "operationName": "TwoHeroes", - "operationType": "query", - "rootType": "Query", - "variables": [], - "source": "query TwoHeroes {\n r2: hero {\n __typename\n name\n }\n luke: hero(episode: EMPIRE) {\n __typename\n name\n }\n}", - "fields": [ - { - "responseName": "r2", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "responseName": "luke", - "fieldName": "hero", - "type": "Character", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "args": [ - { - "name": "episode", - "value": "EMPIRE", - "type": "Episode", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - ], - "isConditional": false, - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [], - "fragmentsReferenced": [], - "sourceWithFragments": "query TwoHeroes {\n r2: hero {\n __typename\n name\n }\n luke: hero(episode: EMPIRE) {\n __typename\n name\n }\n}", - "operationId": "b868fa9c48f19b8151c08c09f46831e3b9cd09f5c617d328647de785244b52bb" - } - ], - "fragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fragmentName": "DroidNameAndPrimaryFunction", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment DroidNameAndPrimaryFunction on Droid {\n __typename\n ...CharacterName\n ...DroidPrimaryFunction\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Droid" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName", - "DroidPrimaryFunction" - ], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterNameAndDroidPrimaryFunction", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment CharacterNameAndDroidPrimaryFunction on Character {\n __typename\n ...CharacterName\n ...DroidPrimaryFunction\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName", - "DroidPrimaryFunction" - ], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterName", - "DroidPrimaryFunction" - ] - } - ] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterNameAndDroidAppearsIn", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment CharacterNameAndDroidAppearsIn on Character {\n __typename\n name\n ... on Droid {\n appearsIn\n }\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this droid appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fragmentName": "DroidName", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment DroidName on Droid {\n __typename\n name\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Droid" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fragmentName": "DroidPrimaryFunction", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment DroidPrimaryFunction on Droid {\n __typename\n primaryFunction\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Droid" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fragmentName": "HumanHeightWithVariable", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment HumanHeightWithVariable on Human {\n __typename\n height(unit: $heightUnit)\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Human" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "args": [ - { - "name": "unit", - "value": { - "kind": "Variable", - "variableName": "heightUnit" - }, - "type": "LengthUnit", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "LengthUnit" - } - } - } - ], - "isConditional": false, - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterNameAndAppearsInWithNestedFragments", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment CharacterNameAndAppearsInWithNestedFragments on Character {\n __typename\n ...CharacterNameWithNestedAppearsInFragment\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterNameWithNestedAppearsInFragment" - ], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterNameWithNestedAppearsInFragment", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment CharacterNameWithNestedAppearsInFragment on Character {\n __typename\n name\n ...CharacterAppearsIn\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [ - "CharacterAppearsIn" - ], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterNameWithInlineFragment", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql", - "source": "fragment CharacterNameWithInlineFragment on Character {\n __typename\n ... on Human {\n friends {\n __typename\n appearsIn\n }\n }\n ... on Droid {\n ...CharacterName\n ...FriendsNames\n }\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "This human's friends, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "This droid's friends, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [ - "CharacterName", - "FriendsNames" - ] - } - ] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "FriendsNames", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql", - "source": "fragment FriendsNames on Character {\n __typename\n friends {\n __typename\n name\n }\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "friends", - "fieldName": "friends", - "type": "[Character]", - "typeNode": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - } - }, - "isConditional": false, - "description": "The friends of the character, or an empty list if they have none", - "isDeprecated": false, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterAppearsIn", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroAppearsIn.graphql", - "source": "fragment CharacterAppearsIn on Character {\n __typename\n appearsIn\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "HeroDetails", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroDetails.graphql", - "source": "fragment HeroDetails on Character {\n __typename\n name\n ... on Human {\n height\n }\n ... on Droid {\n primaryFunction\n }\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [ - { - "typeCondition": "Human", - "possibleTypes": [ - "Human" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What this human calls themselves", - "isDeprecated": false - }, - { - "responseName": "height", - "fieldName": "height", - "type": "Float", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Float" - } - }, - "isConditional": false, - "description": "Height in the preferred unit, default is meters", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [] - } - ] - }, - { - "typeCondition": "Droid", - "possibleTypes": [ - "Droid" - ], - "fragmentName": "DroidDetails", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroDetails.graphql", - "source": "fragment DroidDetails on Droid {\n __typename\n name\n primaryFunction\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Droid" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "What others call this droid", - "isDeprecated": false - }, - { - "responseName": "primaryFunction", - "fieldName": "primaryFunction", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "isConditional": false, - "description": "This droid's primary function", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterName", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroName.graphql", - "source": "fragment CharacterName on Character {\n __typename\n name\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - }, - { - "typeCondition": "Character", - "possibleTypes": [ - "Human", - "Droid" - ], - "fragmentName": "CharacterNameAndAppearsIn", - "filePath": "file:///Users/ellen/Desktop/Work/Apollo/apollo-ios/Sources/StarWarsAPI/graphql/HeroNameAndAppearsIn.graphql", - "source": "fragment CharacterNameAndAppearsIn on Character {\n __typename\n name\n appearsIn\n}", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Character" - } - }, - "fields": [ - { - "responseName": "__typename", - "fieldName": "__typename", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "isDeprecated": false - }, - { - "responseName": "name", - "fieldName": "name", - "type": "String!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - } - }, - "isConditional": false, - "description": "The name of the character", - "isDeprecated": false - }, - { - "responseName": "appearsIn", - "fieldName": "appearsIn", - "type": "[Episode]!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "ListType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Episode" - } - } - } - }, - "isConditional": false, - "description": "The movies this character appears in", - "isDeprecated": false - } - ], - "fragmentSpreads": [], - "inlineFragments": [] - } - ], - "typesUsed": [ - { - "kind": "EnumType", - "name": "Episode", - "description": "The episodes in the Star Wars trilogy", - "values": [ - { - "name": "NEWHOPE", - "description": "Star Wars Episode IV: A New Hope, released in 1977.", - "isDeprecated": false - }, - { - "name": "EMPIRE", - "description": "Star Wars Episode V: The Empire Strikes Back, released in 1980.", - "isDeprecated": false - }, - { - "name": "JEDI", - "description": "Star Wars Episode VI: Return of the Jedi, released in 1983.", - "isDeprecated": false - } - ] - }, - { - "kind": "InputObjectType", - "name": "ReviewInput", - "description": "The input object sent when someone is creating a new review", - "fields": [ - { - "name": "stars", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "description": "0-5 stars" - }, - { - "name": "commentary", - "type": "String", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "String" - } - }, - "description": "Comment about the movie, optional" - }, - { - "name": "favorite_color", - "type": "ColorInput", - "typeNode": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "ColorInput" - } - }, - "description": "Favorite color, optional" - } - ] - }, - { - "kind": "InputObjectType", - "name": "ColorInput", - "description": "The input object sent when passing in a color", - "fields": [ - { - "name": "red", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "description": "" - }, - { - "name": "green", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "description": "" - }, - { - "name": "blue", - "type": "Int!", - "typeNode": { - "kind": "NonNullType", - "type": { - "kind": "NamedType", - "name": { - "kind": "Name", - "value": "Int" - } - } - }, - "description": "" - } - ] - } - ], - "unionTypes": [ - { - "name": "SearchResult", - "types": [ - "Human", - "Droid", - "Starship" - ] - } - ], - "interfaceTypes": [ - { - "name": "Character", - "types": [ - "Human", - "Droid" - ] - } - ] -} \ No newline at end of file diff --git a/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql b/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql deleted file mode 100644 index 78c55a1c31..0000000000 --- a/Sources/StarWarsAPI/graphql/CharacterAndSubTypesFragments.graphql +++ /dev/null @@ -1,50 +0,0 @@ -fragment DroidNameAndPrimaryFunction on Droid { - ...CharacterName - ...DroidPrimaryFunction -} - -fragment CharacterNameAndDroidPrimaryFunction on Character { - ...CharacterName - ...DroidPrimaryFunction -} - -fragment CharacterNameAndDroidAppearsIn on Character { - name - ... on Droid { - appearsIn - } -} - -fragment DroidName on Droid { - name -} - -fragment DroidPrimaryFunction on Droid { - primaryFunction -} - -fragment HumanHeightWithVariable on Human { - height(unit: $heightUnit) -} - -fragment CharacterNameAndAppearsInWithNestedFragments on Character { - ...CharacterNameWithNestedAppearsInFragment -} - -fragment CharacterNameWithNestedAppearsInFragment on Character { - name - ...CharacterAppearsIn -} - -fragment CharacterNameWithInlineFragment on Character { - ... on Human { - friends { - appearsIn - } - } - - ... on Droid { - ...CharacterName - ...FriendsNames - } -} diff --git a/Sources/StarWarsAPI/graphql/CreateReviewForEpisode.graphql b/Sources/StarWarsAPI/graphql/CreateReviewForEpisode.graphql deleted file mode 100644 index 516205dfbd..0000000000 --- a/Sources/StarWarsAPI/graphql/CreateReviewForEpisode.graphql +++ /dev/null @@ -1,20 +0,0 @@ -mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) { - createReview(episode: $episode, review: $review) { - stars - commentary - } -} - -mutation CreateAwesomeReview { - createReview(episode: JEDI, review: { stars: 10, commentary: "This is awesome!" }) { - stars - commentary - } -} - -mutation CreateReviewWithNullField { - createReview(episode: JEDI, review: { stars: 10, commentary: null }) { - stars - commentary - } -} diff --git a/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql b/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql deleted file mode 100644 index 1b4424db1a..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroAndFriendsNames.graphql +++ /dev/null @@ -1,65 +0,0 @@ -query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - name - friends { - name - } - } -} - -query HeroAndFriendsNamesWithIDs($episode: Episode) { - hero(episode: $episode) { - id - name - friends { - id - name - } - } -} - -query HeroAndFriendsIDs($episode: Episode) { - hero(episode: $episode) { - id - name - friends { - id - } - } -} - -query HeroAndFriendsNamesWithIDForParentOnly($episode: Episode) { - hero(episode: $episode) { - id - name - friends { - name - } - } -} - -query HeroAndFriendsNamesWithFragment($episode: Episode) { - hero(episode: $episode) { - name - ...FriendsNames - } -} - -query HeroAndFriendsNamesWithFragmentTwice($episode: Episode) { - hero(episode: $episode) { - friends { - ...CharacterName - } - ... on Droid { - friends { - ...CharacterName - } - } - } -} - -fragment FriendsNames on Character { - friends { - name - } -} diff --git a/Sources/StarWarsAPI/graphql/HeroAppearsIn.graphql b/Sources/StarWarsAPI/graphql/HeroAppearsIn.graphql deleted file mode 100644 index d00ee1f17a..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroAppearsIn.graphql +++ /dev/null @@ -1,15 +0,0 @@ -query HeroAppearsIn { - hero { - appearsIn - } -} - -query HeroAppearsInWithFragment($episode: Episode) { - hero(episode: $episode) { - ...CharacterAppearsIn - } -} - -fragment CharacterAppearsIn on Character { - appearsIn -} diff --git a/Sources/StarWarsAPI/graphql/HeroConditional.graphql b/Sources/StarWarsAPI/graphql/HeroConditional.graphql deleted file mode 100644 index 95773964b9..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroConditional.graphql +++ /dev/null @@ -1,73 +0,0 @@ -query HeroNameConditionalExclusion($skipName: Boolean!) { - hero { - name @skip(if: $skipName) - } -} - -query HeroNameConditionalInclusion($includeName: Boolean!) { - hero { - name @include(if: $includeName) - } -} - -query HeroNameConditionalBoth($skipName: Boolean!, $includeName: Boolean!) { - hero { - name @skip(if: $skipName) @include(if: $includeName) - } -} - -query HeroNameConditionalBothSeparate($skipName: Boolean!, $includeName: Boolean!) { - hero { - name @skip(if: $skipName) - name @include(if: $includeName) - } -} - -query HeroDetailsInlineConditionalInclusion($includeDetails: Boolean!) { - hero { - ... @include(if: $includeDetails) { - name - appearsIn - } - } -} - -query HeroDetailsFragmentConditionalInclusion($includeDetails: Boolean!) { - hero { - ...HeroDetails @include(if: $includeDetails) - } -} - -query HeroNameTypeSpecificConditionalInclusion($episode: Episode, $includeName: Boolean!) { - hero(episode: $episode) { - name @include(if: $includeName) - ... on Droid { - name - } - } -} - -query HeroFriendsDetailsConditionalInclusion($includeFriendsDetails: Boolean!) { - hero { - friends @include(if: $includeFriendsDetails) { - name - ... on Droid { - primaryFunction - } - } - } -} - -query HeroFriendsDetailsUnconditionalAndConditionalInclusion($includeFriendsDetails: Boolean!) { - hero { - friends { - name - } - friends @include(if: $includeFriendsDetails) { - name - ... on Droid { - primaryFunction - } - } - } -} diff --git a/Sources/StarWarsAPI/graphql/HeroDetails.graphql b/Sources/StarWarsAPI/graphql/HeroDetails.graphql deleted file mode 100644 index 2e19bd11eb..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroDetails.graphql +++ /dev/null @@ -1,38 +0,0 @@ -query HeroDetails($episode: Episode) { - hero(episode: $episode) { - name - ... on Human { - height - } - ... on Droid { - primaryFunction - } - } -} - -query HeroDetailsWithFragment($episode: Episode) { - hero(episode: $episode) { - ...HeroDetails - } -} - -query DroidDetailsWithFragment($episode: Episode) { - hero(episode: $episode) { - ...DroidDetails - } -} - -fragment HeroDetails on Character { - name - ... on Human { - height - } - ... on Droid { - primaryFunction - } -} - -fragment DroidDetails on Droid { - name - primaryFunction -} diff --git a/Sources/StarWarsAPI/graphql/HeroFriendsOfFriends.graphql b/Sources/StarWarsAPI/graphql/HeroFriendsOfFriends.graphql deleted file mode 100644 index 7959e66743..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroFriendsOfFriends.graphql +++ /dev/null @@ -1,10 +0,0 @@ -query HeroFriendsOfFriendsNames($episode: Episode) { - hero(episode: $episode) { - friends { - id - friends { - name - } - } - } -} diff --git a/Sources/StarWarsAPI/graphql/HeroName.graphql b/Sources/StarWarsAPI/graphql/HeroName.graphql deleted file mode 100644 index 5f583be0bf..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroName.graphql +++ /dev/null @@ -1,29 +0,0 @@ -query HeroName($episode: Episode) { - hero(episode: $episode) { - name - } -} - -query HeroNameWithID($episode: Episode) { - hero(episode: $episode) { - id - name - } -} - -query HeroNameWithFragment($episode: Episode) { - hero(episode: $episode) { - ...CharacterName - } -} - -query HeroNameWithFragmentAndID($episode: Episode) { - hero(episode: $episode) { - id - ...CharacterName - } -} - -fragment CharacterName on Character { - name -} diff --git a/Sources/StarWarsAPI/graphql/HeroNameAndAppearsIn.graphql b/Sources/StarWarsAPI/graphql/HeroNameAndAppearsIn.graphql deleted file mode 100644 index dd8a0af573..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroNameAndAppearsIn.graphql +++ /dev/null @@ -1,17 +0,0 @@ -query HeroNameAndAppearsIn($episode: Episode) { - hero(episode: $episode) { - name - appearsIn - } -} - -query HeroNameAndAppearsInWithFragment($episode: Episode) { - hero(episode: $episode) { - ...CharacterNameAndAppearsIn - } -} - -fragment CharacterNameAndAppearsIn on Character { - name - appearsIn -} diff --git a/Sources/StarWarsAPI/graphql/HeroParentTypeDependentField.graphql b/Sources/StarWarsAPI/graphql/HeroParentTypeDependentField.graphql deleted file mode 100644 index b3f31bebcd..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroParentTypeDependentField.graphql +++ /dev/null @@ -1,21 +0,0 @@ -query HeroParentTypeDependentField($episode: Episode) { - hero(episode: $episode) { - name - ... on Human { - friends { - name - ... on Human { - height(unit: FOOT) - } - } - } - ... on Droid { - friends { - name - ... on Human { - height(unit: METER) - } - } - } - } -} diff --git a/Sources/StarWarsAPI/graphql/HeroTypeDependentAliasedField.graphql b/Sources/StarWarsAPI/graphql/HeroTypeDependentAliasedField.graphql deleted file mode 100644 index 1ab5a0656d..0000000000 --- a/Sources/StarWarsAPI/graphql/HeroTypeDependentAliasedField.graphql +++ /dev/null @@ -1,10 +0,0 @@ -query HeroTypeDependentAliasedField($episode: Episode) { - hero(episode: $episode) { - ... on Human { - property: homePlanet - } - ... on Droid { - property: primaryFunction - } - } -} diff --git a/Sources/StarWarsAPI/graphql/SameHeroTwice.graphql b/Sources/StarWarsAPI/graphql/SameHeroTwice.graphql deleted file mode 100644 index 2480a0e42c..0000000000 --- a/Sources/StarWarsAPI/graphql/SameHeroTwice.graphql +++ /dev/null @@ -1,8 +0,0 @@ -query SameHeroTwice { - hero { - name - } - r2: hero { - appearsIn - } -} diff --git a/Sources/StarWarsAPI/graphql/Search.graphql b/Sources/StarWarsAPI/graphql/Search.graphql deleted file mode 100644 index d81e3230d0..0000000000 --- a/Sources/StarWarsAPI/graphql/Search.graphql +++ /dev/null @@ -1,16 +0,0 @@ -query Search($term: String) { - search(text: $term) { - ... on Human { - id - name - } - ... on Droid { - id - name - } - ... on Starship { - id - name - } - } -} diff --git a/Sources/StarWarsAPI/graphql/Starship.graphql b/Sources/StarWarsAPI/graphql/Starship.graphql deleted file mode 100644 index 1bfef3a16b..0000000000 --- a/Sources/StarWarsAPI/graphql/Starship.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query Starship { - starship(id: 3000) { - name - coordinates - } -} - -query StarshipCoordinates($coordinates: [[Float!]!]) { - starshipCoordinates(coordinates: $coordinates) { - name - coordinates - length - } -} diff --git a/Sources/StarWarsAPI/graphql/SubscribeReview.graphql b/Sources/StarWarsAPI/graphql/SubscribeReview.graphql deleted file mode 100644 index 4c1235261b..0000000000 --- a/Sources/StarWarsAPI/graphql/SubscribeReview.graphql +++ /dev/null @@ -1,8 +0,0 @@ -subscription ReviewAdded($episode: Episode) { - reviewAdded(episode: $episode) { - episode - stars - commentary - } -} - diff --git a/Sources/StarWarsAPI/graphql/TestFolder/TestFolder2/Human.graphql b/Sources/StarWarsAPI/graphql/TestFolder/TestFolder2/Human.graphql deleted file mode 100644 index f1fdda9f3f..0000000000 --- a/Sources/StarWarsAPI/graphql/TestFolder/TestFolder2/Human.graphql +++ /dev/null @@ -1,6 +0,0 @@ -query Human($id: ID!) { - human(id: $id) { - name - mass - } -} diff --git a/Sources/StarWarsAPI/graphql/TwoHeroes.graphql b/Sources/StarWarsAPI/graphql/TwoHeroes.graphql deleted file mode 100644 index 74df4933bf..0000000000 --- a/Sources/StarWarsAPI/graphql/TwoHeroes.graphql +++ /dev/null @@ -1,8 +0,0 @@ -query TwoHeroes { - r2: hero { - name - } - luke: hero(episode: EMPIRE) { - name - } -} diff --git a/Sources/StarWarsAPI/graphql/operationIDs.json b/Sources/StarWarsAPI/graphql/operationIDs.json deleted file mode 100644 index 29d4000bce..0000000000 --- a/Sources/StarWarsAPI/graphql/operationIDs.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "9bbf5b4074d0635fb19d17c621b7b04ebfb1920d468a94266819e149841e7d5d": { - "name": "CreateReviewForEpisode", - "source": "mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) {\n createReview(episode: $episode, review: $review) {\n __typename\n stars\n commentary\n }\n}" - }, - "4a1250de93ebcb5cad5870acf15001112bf27bb963e8709555b5ff67a1405374": { - "name": "CreateAwesomeReview", - "source": "mutation CreateAwesomeReview {\n createReview(episode: JEDI, review: {stars: 10, commentary: \"This is awesome!\"}) {\n __typename\n stars\n commentary\n }\n}" - }, - "a9600d176cd7e4671b8689f1d01fe79ea896932bfafb8a925af673f0e4111828": { - "name": "CreateReviewWithNullField", - "source": "mutation CreateReviewWithNullField {\n createReview(episode: JEDI, review: {stars: 10, commentary: null}) {\n __typename\n stars\n commentary\n }\n}" - }, - "fe3f21394eb861aa515c4d582e645469045793c9cbbeca4b5d4ce4d7dd617556": { - "name": "HeroAndFriendsNames", - "source": "query HeroAndFriendsNames($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n friends {\n __typename\n name\n }\n }\n}" - }, - "8e4ca76c63660898cfd5a3845e3709027750b5f0151c7f9be65759b869c5486d": { - "name": "HeroAndFriendsNamesWithIDs", - "source": "query HeroAndFriendsNamesWithIDs($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n id\n name\n }\n }\n}" - }, - "117d0f6831d8f4abe5b61ed1dbb8071b0825e19649916c0fe0906a6f578bb088": { - "name": "HeroAndFriendsIDs", - "source": "query HeroAndFriendsIDs($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n id\n }\n }\n}" - }, - "f091468a629f3b757c03a1b7710c6ede8b5c8f10df7ba3238f2bbcd71c56f90f": { - "name": "HeroAndFriendsNamesWithIDForParentOnly", - "source": "query HeroAndFriendsNamesWithIDForParentOnly($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n friends {\n __typename\n name\n }\n }\n}" - }, - "1d3ad903dad146ff9d7aa09813fc01becd017489bfc1af8ffd178498730a5a26": { - "name": "HeroAndFriendsNamesWithFragment", - "source": "query HeroAndFriendsNamesWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ...FriendsNames\n }\n}\nfragment FriendsNames on Character {\n __typename\n friends {\n __typename\n name\n }\n}" - }, - "b5f4eca712a136f0d5d9f96203ef7d03cd119d8388f093f4b78ae124acb904cb": { - "name": "HeroAndFriendsNamesWithFragmentTwice", - "source": "query HeroAndFriendsNamesWithFragmentTwice($episode: Episode) {\n hero(episode: $episode) {\n __typename\n friends {\n __typename\n ...CharacterName\n }\n ... on Droid {\n __typename\n friends {\n __typename\n ...CharacterName\n }\n }\n }\n}\nfragment CharacterName on Character {\n __typename\n name\n}" - }, - "22d772c0fc813281705e8f0a55fc70e71eeff6e98f3f9ef96cf67fb896914522": { - "name": "HeroAppearsIn", - "source": "query HeroAppearsIn {\n hero {\n __typename\n appearsIn\n }\n}" - }, - "1756158bd7736d58db45a48d74a724fa1b6fdac735376df8afac8318ba5431fb": { - "name": "HeroAppearsInWithFragment", - "source": "query HeroAppearsInWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterAppearsIn\n }\n}\nfragment CharacterAppearsIn on Character {\n __typename\n appearsIn\n}" - }, - "3dd42259adf2d0598e89e0279bee2c128a7913f02b1da6aa43f3b5def6a8a1f8": { - "name": "HeroNameConditionalExclusion", - "source": "query HeroNameConditionalExclusion($skipName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName)\n }\n}" - }, - "338081aea3acc83d04af0741ecf0da1ec2ee8e6468a88383476b681015905ef8": { - "name": "HeroNameConditionalInclusion", - "source": "query HeroNameConditionalInclusion($includeName: Boolean!) {\n hero {\n __typename\n name @include(if: $includeName)\n }\n}" - }, - "66f4dc124b6374b1912b22a2a208e34a4b1997349402a372b95bcfafc7884064": { - "name": "HeroNameConditionalBoth", - "source": "query HeroNameConditionalBoth($skipName: Boolean!, $includeName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName) @include(if: $includeName)\n }\n}" - }, - "d0f9e9205cdc09320035662f528a177654d3275b0bf94cf0e259a65fde33e7e5": { - "name": "HeroNameConditionalBothSeparate", - "source": "query HeroNameConditionalBothSeparate($skipName: Boolean!, $includeName: Boolean!) {\n hero {\n __typename\n name @skip(if: $skipName)\n name @include(if: $includeName)\n }\n}" - }, - "3091d9d3f1d2374e2f835ce05d332e50b3fe61502d73213b9aa511f0f94f091c": { - "name": "HeroDetailsInlineConditionalInclusion", - "source": "query HeroDetailsInlineConditionalInclusion($includeDetails: Boolean!) {\n hero {\n __typename\n ... @include(if: $includeDetails) {\n __typename\n name\n appearsIn\n }\n }\n}" - }, - "b0fa7927ff93b4a579c3460fb04d093072d34c8018e41197c7e080aeeec5e19b": { - "name": "HeroDetailsFragmentConditionalInclusion", - "source": "query HeroDetailsFragmentConditionalInclusion($includeDetails: Boolean!) {\n hero {\n __typename\n ...HeroDetails @include(if: $includeDetails)\n }\n}\nfragment HeroDetails on Character {\n __typename\n name\n ... on Human {\n __typename\n height\n }\n ... on Droid {\n __typename\n primaryFunction\n }\n}" - }, - "76aecc75265295818d3990000b17e32d5524ca85a4bc159ae8a3f8ec7ce91cc3": { - "name": "HeroNameTypeSpecificConditionalInclusion", - "source": "query HeroNameTypeSpecificConditionalInclusion($episode: Episode, $includeName: Boolean!) {\n hero(episode: $episode) {\n __typename\n name @include(if: $includeName)\n ... on Droid {\n __typename\n name\n }\n }\n}" - }, - "8cada231691ff2f5a0a07c54b7332114588f11b947795da345c5b054211fbcfd": { - "name": "HeroFriendsDetailsConditionalInclusion", - "source": "query HeroFriendsDetailsConditionalInclusion($includeFriendsDetails: Boolean!) {\n hero {\n __typename\n friends @include(if: $includeFriendsDetails) {\n __typename\n name\n ... on Droid {\n __typename\n primaryFunction\n }\n }\n }\n}" - }, - "65381a20574db4b458a0821328252deb0da1a107f9ab77c99fb2467e66a5f12d": { - "name": "HeroFriendsDetailsUnconditionalAndConditionalInclusion", - "source": "query HeroFriendsDetailsUnconditionalAndConditionalInclusion($includeFriendsDetails: Boolean!) {\n hero {\n __typename\n friends {\n __typename\n name\n }\n friends @include(if: $includeFriendsDetails) {\n __typename\n name\n ... on Droid {\n __typename\n primaryFunction\n }\n }\n }\n}" - }, - "207d29944f5822bff08a07db4a55274ea14035bacfe20699da41a47454f1181e": { - "name": "HeroDetails", - "source": "query HeroDetails($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ... on Human {\n __typename\n height\n }\n ... on Droid {\n __typename\n primaryFunction\n }\n }\n}" - }, - "b55bd9d56d1b5972345412b6adb88ceb64d6086c8051d2588d8ab701f0ee7c2f": { - "name": "HeroDetailsWithFragment", - "source": "query HeroDetailsWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...HeroDetails\n }\n}\nfragment HeroDetails on Character {\n __typename\n name\n ... on Human {\n __typename\n height\n }\n ... on Droid {\n __typename\n primaryFunction\n }\n}" - }, - "7277e97563e911ac8f5c91d401028d218aae41f38df014d7fa0b037bb2a2e739": { - "name": "DroidDetailsWithFragment", - "source": "query DroidDetailsWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...DroidDetails\n }\n}\nfragment DroidDetails on Droid {\n __typename\n name\n primaryFunction\n}" - }, - "37cd5626048e7243716ffda9e56503939dd189772124a1c21b0e0b87e69aae01": { - "name": "HeroFriendsOfFriendsNames", - "source": "query HeroFriendsOfFriendsNames($episode: Episode) {\n hero(episode: $episode) {\n __typename\n friends {\n __typename\n id\n friends {\n __typename\n name\n }\n }\n }\n}" - }, - "f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671": { - "name": "HeroName", - "source": "query HeroName($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n }\n}" - }, - "83c03f612c46fca72f6cb902df267c57bffc9209bc44dd87d2524fb2b34f6f18": { - "name": "HeroNameWithID", - "source": "query HeroNameWithID($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n name\n }\n}" - }, - "b952f0054915a32ec524ac0dde0244bcda246649debe149f9e32e303e21c8266": { - "name": "HeroNameWithFragment", - "source": "query HeroNameWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterName\n }\n}\nfragment CharacterName on Character {\n __typename\n name\n}" - }, - "a87a0694c09d1ed245e9a80f245d96a5f57b20a4aa936ee9ab09b2a43620db02": { - "name": "HeroNameWithFragmentAndID", - "source": "query HeroNameWithFragmentAndID($episode: Episode) {\n hero(episode: $episode) {\n __typename\n id\n ...CharacterName\n }\n}\nfragment CharacterName on Character {\n __typename\n name\n}" - }, - "f714414a2002404f9943490c8cc9c1a7b8ecac3ca229fa5a326186b43c1385ce": { - "name": "HeroNameAndAppearsIn", - "source": "query HeroNameAndAppearsIn($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n appearsIn\n }\n}" - }, - "0664fed3eb4f9fbdb44e8691d9e8fd11f2b3c097ba11327592054f602bd3ba1a": { - "name": "HeroNameAndAppearsInWithFragment", - "source": "query HeroNameAndAppearsInWithFragment($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ...CharacterNameAndAppearsIn\n }\n}\nfragment CharacterNameAndAppearsIn on Character {\n __typename\n name\n appearsIn\n}" - }, - "39eb41b5a9477c36fa529c23d6f0de6ebcc0312daf5bdcfe208d5baec752dc5b": { - "name": "HeroParentTypeDependentField", - "source": "query HeroParentTypeDependentField($episode: Episode) {\n hero(episode: $episode) {\n __typename\n name\n ... on Human {\n __typename\n friends {\n __typename\n name\n ... on Human {\n __typename\n height(unit: FOOT)\n }\n }\n }\n ... on Droid {\n __typename\n friends {\n __typename\n name\n ... on Human {\n __typename\n height(unit: METER)\n }\n }\n }\n }\n}" - }, - "eac5a52f9020fc2e9b5dc5facfd6a6295683b8d57ea62ee84254069fcd5e504c": { - "name": "HeroTypeDependentAliasedField", - "source": "query HeroTypeDependentAliasedField($episode: Episode) {\n hero(episode: $episode) {\n __typename\n ... on Human {\n __typename\n property: homePlanet\n }\n ... on Droid {\n __typename\n property: primaryFunction\n }\n }\n}" - }, - "2a8ad85a703add7d64622aaf6be76b58a1134caf28e4ff6b34dd00ba89541364": { - "name": "SameHeroTwice", - "source": "query SameHeroTwice {\n hero {\n __typename\n name\n }\n r2: hero {\n __typename\n appearsIn\n }\n}" - }, - "477b77c476899915498a56ae7bb835667b1e875cb94f6daa7f75e05018be2c3a": { - "name": "Search", - "source": "query Search($term: String) {\n search(text: $term) {\n __typename\n ... on Human {\n __typename\n id\n name\n }\n ... on Droid {\n __typename\n id\n name\n }\n ... on Starship {\n __typename\n id\n name\n }\n }\n}" - }, - "a3734516185da9919e3e66d74fe92b60d65292a1943dc54913f7332637dfdd2a": { - "name": "Starship", - "source": "query Starship {\n starship(id: 3000) {\n __typename\n name\n coordinates\n }\n}" - }, - "8dd77d4bc7494c184606da092a665a7c2ca3c2a3f14d3b23fa5e469e207b3406": { - "name": "StarshipCoordinates", - "source": "query StarshipCoordinates($coordinates: [[Float!]!]) {\n starshipCoordinates(coordinates: $coordinates) {\n __typename\n name\n coordinates\n length\n }\n}" - }, - "38644c5e7cf4fd506b91d2e7010cabf84e63dfcd33cf1deb443b4b32b55e2cbe": { - "name": "ReviewAdded", - "source": "subscription ReviewAdded($episode: Episode) {\n reviewAdded(episode: $episode) {\n __typename\n episode\n stars\n commentary\n }\n}" - }, - "b37eb69b82fd52358321e49453769750983be1c286744dbf415735d7bcf12f1e": { - "name": "Human", - "source": "query Human($id: ID!) {\n human(id: $id) {\n __typename\n name\n mass\n }\n}" - }, - "b868fa9c48f19b8151c08c09f46831e3b9cd09f5c617d328647de785244b52bb": { - "name": "TwoHeroes", - "source": "query TwoHeroes {\n r2: hero {\n __typename\n name\n }\n luke: hero(episode: EMPIRE) {\n __typename\n name\n }\n}" - } -} \ No newline at end of file diff --git a/Sources/StarWarsAPI/graphql/schema.graphqls b/Sources/StarWarsAPI/graphql/schema.graphqls deleted file mode 100644 index 2e55c4a84d..0000000000 --- a/Sources/StarWarsAPI/graphql/schema.graphqls +++ /dev/null @@ -1,194 +0,0 @@ - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -# The query type, represents all of the entry points into our object graph -type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human - starship(id: ID!): Starship -} - -# The mutation type, represents all updates we can make to our data -type Mutation { - createReview(episode: Episode, review: ReviewInput!): Review -} - -# The subscription type, represents all subscriptions we can make to our data -type Subscription { - reviewAdded(episode: Episode): Review -} - -# The episodes in the Star Wars trilogy -enum Episode { - # Star Wars Episode IV: A New Hope, released in 1977. - NEWHOPE - - # Star Wars Episode V: The Empire Strikes Back, released in 1980. - EMPIRE - - # Star Wars Episode VI: Return of the Jedi, released in 1983. - JEDI -} - -# A character from the Star Wars universe -interface Character { - # The ID of the character - id: ID! - - # The name of the character - name: String! - - # The friends of the character, or an empty list if they have none - friends: [Character] - - # The friends of the character exposed as a connection with edges - friendsConnection(first: Int, after: ID): FriendsConnection! - - # The movies this character appears in - appearsIn: [Episode]! -} - -# Units of height -enum LengthUnit { - # The standard unit around the world - METER - - # Primarily used in the United States - FOOT -} - -# A humanoid creature from the Star Wars universe -type Human implements Character { - # The ID of the human - id: ID! - - # What this human calls themselves - name: String! - - # The home planet of the human, or null if unknown - homePlanet: String - - # Height in the preferred unit, default is meters - height(unit: LengthUnit = METER): Float - - # Mass in kilograms, or null if unknown - mass: Float - - # This human's friends, or an empty list if they have none - friends: [Character] - - # The friends of the human exposed as a connection with edges - friendsConnection(first: Int, after: ID): FriendsConnection! - - # The movies this human appears in - appearsIn: [Episode]! - - # A list of starships this person has piloted, or an empty list if none - starships: [Starship] -} - -# An autonomous mechanical character in the Star Wars universe -type Droid implements Character { - # The ID of the droid - id: ID! - - # What others call this droid - name: String! - - # This droid's friends, or an empty list if they have none - friends: [Character] - - # The friends of the droid exposed as a connection with edges - friendsConnection(first: Int, after: ID): FriendsConnection! - - # The movies this droid appears in - appearsIn: [Episode]! - - # This droid's primary function - primaryFunction: String -} - -# A connection object for a character's friends -type FriendsConnection { - # The total number of friends - totalCount: Int - - # The edges for each of the character's friends. - edges: [FriendsEdge] - - # A list of the friends, as a convenience when edges are not needed. - friends: [Character] - - # Information for paginating this connection - pageInfo: PageInfo! -} - -# An edge object for a character's friends -type FriendsEdge { - # A cursor used for pagination - cursor: ID! - - # The character represented by this friendship edge - node: Character -} - -# Information for paginating this connection -type PageInfo { - startCursor: ID - endCursor: ID - hasNextPage: Boolean! -} - -# Represents a review for a movie -type Review { - # The movie - episode: Episode - - # The number of stars this review gave, 1-5 - stars: Int! - - # Comment about the movie - commentary: String -} - -# The input object sent when someone is creating a new review -input ReviewInput { - # 0-5 stars - stars: Int! - - # Comment about the movie, optional - commentary: String - - # Favorite color, optional - favorite_color: ColorInput -} - -# The input object sent when passing in a color -input ColorInput { - red: Int! - green: Int! - blue: Int! -} - -type Starship { - # The ID of the starship - id: ID! - - # The name of the starship - name: String! - - # Length of the starship, along the longest axis - length(unit: LengthUnit = METER): Float - - coordinates: [[Float!]!] -} - -union SearchResult = Human | Droid | Starship diff --git a/Sources/StarWarsAPI/graphql/schema.json b/Sources/StarWarsAPI/graphql/schema.json deleted file mode 100644 index b9a35aa09d..0000000000 --- a/Sources/StarWarsAPI/graphql/schema.json +++ /dev/null @@ -1,2226 +0,0 @@ -{ - "data": { - "__schema": { - "queryType": { - "name": "Query" - }, - "mutationType": { - "name": "Mutation" - }, - "subscriptionType": { - "name": "Subscription" - }, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": "The query type, represents all of the entry points into our object graph", - "fields": [ - { - "name": "hero", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "reviews", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Review", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "search", - "description": "", - "args": [ - { - "name": "text", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "UNION", - "name": "SearchResult", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "character", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "human", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Human", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starship", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starshipCoordinates", - "description": "", - "args": [ - { - "name": "coordinates", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "Episode", - "description": "The episodes in the Star Wars trilogy", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "NEWHOPE", - "description": "Star Wars Episode IV: A New Hope, released in 1977.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "EMPIRE", - "description": "Star Wars Episode V: The Empire Strikes Back, released in 1980.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "JEDI", - "description": "Star Wars Episode VI: Return of the Jedi, released in 1983.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "INTERFACE", - "name": "Character", - "description": "A character from the Star Wars universe", - "fields": [ - { - "name": "id", - "description": "The ID of the character", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the character", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "The friends of the character, or an empty list if they have none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friendsConnection", - "description": "The friends of the character exposed as a connection with edges", - "args": [ - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsConnection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "appearsIn", - "description": "The movies this character appears in", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Human", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - } - ] - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FriendsConnection", - "description": "A connection object for a character's friends", - "fields": [ - { - "name": "totalCount", - "description": "The total number of friends", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "The edges for each of the character's friends.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsEdge", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "A list of the friends, as a convenience when edges are not needed.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "Information for paginating this connection", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "PageInfo", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FriendsEdge", - "description": "An edge object for a character's friends", - "fields": [ - { - "name": "cursor", - "description": "A cursor used for pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "The character represented by this friendship edge", - "args": [], - "type": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PageInfo", - "description": "Information for paginating this connection", - "fields": [ - { - "name": "startCursor", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endCursor", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hasNextPage", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Review", - "description": "Represents a review for a movie", - "fields": [ - { - "name": "episode", - "description": "The movie", - "args": [], - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "stars", - "description": "The number of stars this review gave, 1-5", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "commentary", - "description": "Comment about the movie", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "UNION", - "name": "SearchResult", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Human", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - ] - }, - { - "kind": "OBJECT", - "name": "Human", - "description": "A humanoid creature from the Star Wars universe", - "fields": [ - { - "name": "id", - "description": "The ID of the human", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "What this human calls themselves", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "homePlanet", - "description": "The home planet of the human, or null if unknown", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height", - "description": "Height in the preferred unit, default is meters", - "args": [ - { - "name": "unit", - "description": "", - "type": { - "kind": "ENUM", - "name": "LengthUnit", - "ofType": null - }, - "defaultValue": "METER" - } - ], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass", - "description": "Mass in kilograms, or null if unknown", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "This human's friends, or an empty list if they have none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friendsConnection", - "description": "The friends of the human exposed as a connection with edges", - "args": [ - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsConnection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "appearsIn", - "description": "The movies this human appears in", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starships", - "description": "A list of starships this person has piloted, or an empty list if none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "LengthUnit", - "description": "Units of height", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "METER", - "description": "The standard unit around the world", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FOOT", - "description": "Primarily used in the United States", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Starship", - "description": "", - "fields": [ - { - "name": "id", - "description": "The ID of the starship", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the starship", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length", - "description": "Length of the starship, along the longest axis", - "args": [ - { - "name": "unit", - "description": "", - "type": { - "kind": "ENUM", - "name": "LengthUnit", - "ofType": null - }, - "defaultValue": "METER" - } - ], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "coordinates", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Droid", - "description": "An autonomous mechanical character in the Star Wars universe", - "fields": [ - { - "name": "id", - "description": "The ID of the droid", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "What others call this droid", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "This droid's friends, or an empty list if they have none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friendsConnection", - "description": "The friends of the droid exposed as a connection with edges", - "args": [ - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsConnection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "appearsIn", - "description": "The movies this droid appears in", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "primaryFunction", - "description": "This droid's primary function", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": "The mutation type, represents all updates we can make to our data", - "fields": [ - { - "name": "createReview", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "review", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "ReviewInput", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Review", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "ReviewInput", - "description": "The input object sent when someone is creating a new review", - "fields": null, - "inputFields": [ - { - "name": "stars", - "description": "0-5 stars", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "commentary", - "description": "Comment about the movie, optional", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "favorite_color", - "description": "Favorite color, optional", - "type": { - "kind": "INPUT_OBJECT", - "name": "ColorInput", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "ColorInput", - "description": "The input object sent when passing in a color", - "fields": null, - "inputFields": [ - { - "name": "red", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "green", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "blue", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Subscription", - "description": "The subscription type, represents all subscriptions we can make to our data", - "fields": [ - { - "name": "reviewAdded", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Review", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Directive", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "fields": [ - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__TypeKind", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Field", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interfaces", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "possibleTypes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__EnumValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inputFields", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ofType", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locations", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__DirectiveLocation", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "onOperation", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onFragment", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onField", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Location adjacent to an input object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - } - ], - "directives": [ - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "FIELD_DEFINITION", - "ENUM_VALUE" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ] - } - ] - } - } -} diff --git a/Sources/SubscriptionAPI/API.swift b/Sources/SubscriptionAPI/API.swift deleted file mode 100644 index f1d28c984d..0000000000 --- a/Sources/SubscriptionAPI/API.swift +++ /dev/null @@ -1,51 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -public final class IncrementingSubscription: GraphQLSubscription { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - subscription Incrementing { - numberIncremented - } - """ - - public let operationName: String = "Incrementing" - - public let operationIdentifier: String? = "fe12b5f0dfc7fefa513cc8aecef043b45daf2d776fd000d3a7703f9798ecf233" - - public init() { - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Subscription"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("numberIncremented", type: .scalar(Int.self)), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(numberIncremented: Int? = nil) { - self.init(unsafeResultMap: ["__typename": "Subscription", "numberIncremented": numberIncremented]) - } - - public var numberIncremented: Int? { - get { - return resultMap["numberIncremented"] as? Int - } - set { - resultMap.updateValue(newValue, forKey: "numberIncremented") - } - } - } -} diff --git a/Sources/SubscriptionAPI/Info.plist b/Sources/SubscriptionAPI/Info.plist deleted file mode 100644 index 09738dfd75..0000000000 --- a/Sources/SubscriptionAPI/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Sources/SubscriptionAPI/SubscriptionAPI.h b/Sources/SubscriptionAPI/SubscriptionAPI.h deleted file mode 100644 index beb356750a..0000000000 --- a/Sources/SubscriptionAPI/SubscriptionAPI.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -//! Project version number for SubscriptionAPI. -FOUNDATION_EXPORT double SubscriptionAPIVersionNumber; - -//! Project version string for SubscriptionAPI. -FOUNDATION_EXPORT const unsigned char SubscriptionAPIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Sources/SubscriptionAPI/graphql/operation_ids.json b/Sources/SubscriptionAPI/graphql/operation_ids.json deleted file mode 100644 index 9ab21dcf46..0000000000 --- a/Sources/SubscriptionAPI/graphql/operation_ids.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "fe12b5f0dfc7fefa513cc8aecef043b45daf2d776fd000d3a7703f9798ecf233": { - "name": "Incrementing", - "source": "subscription Incrementing {\n numberIncremented\n}" - } -} diff --git a/Sources/SubscriptionAPI/graphql/schema.graphqls b/Sources/SubscriptionAPI/graphql/schema.graphqls deleted file mode 100644 index b8a42c27ac..0000000000 --- a/Sources/SubscriptionAPI/graphql/schema.graphqls +++ /dev/null @@ -1,7 +0,0 @@ -type Query { - currentNumber: Int -} - -type Subscription { - numberIncremented: Int -} diff --git a/Sources/SubscriptionAPI/graphql/subscription.graphql b/Sources/SubscriptionAPI/graphql/subscription.graphql deleted file mode 100644 index 55b482bc83..0000000000 --- a/Sources/SubscriptionAPI/graphql/subscription.graphql +++ /dev/null @@ -1,4 +0,0 @@ -subscription Incrementing { - numberIncremented -} - diff --git a/Sources/UploadAPI/API.swift b/Sources/UploadAPI/API.swift deleted file mode 100644 index 2a056f80c1..0000000000 --- a/Sources/UploadAPI/API.swift +++ /dev/null @@ -1,391 +0,0 @@ -// @generated -// This file was automatically generated and should not be edited. - -import Apollo -import Foundation - -public final class UploadMultipleFilesToTheSameParameterMutation: GraphQLMutation { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - mutation UploadMultipleFilesToTheSameParameter($files: [Upload!]!) { - multipleUpload(files: $files) { - __typename - id - path - filename - mimetype - } - } - """ - - public let operationName: String = "UploadMultipleFilesToTheSameParameter" - - public let operationIdentifier: String? = "88858c283bb72f18c0049dc85b140e72a4046f469fa16a8bf4bcf01c11d8a2b7" - - public var files: [String] - - public init(files: [String]) { - self.files = files - } - - public var variables: GraphQLMap? { - return ["files": files] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Mutation"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("multipleUpload", arguments: ["files": GraphQLVariable("files")], type: .nonNull(.list(.nonNull(.object(MultipleUpload.selections))))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(multipleUpload: [MultipleUpload]) { - self.init(unsafeResultMap: ["__typename": "Mutation", "multipleUpload": multipleUpload.map { (value: MultipleUpload) -> ResultMap in value.resultMap }]) - } - - public var multipleUpload: [MultipleUpload] { - get { - return (resultMap["multipleUpload"] as! [ResultMap]).map { (value: ResultMap) -> MultipleUpload in MultipleUpload(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: MultipleUpload) -> ResultMap in value.resultMap }, forKey: "multipleUpload") - } - } - - public struct MultipleUpload: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["File"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("path", type: .nonNull(.scalar(String.self))), - GraphQLField("filename", type: .nonNull(.scalar(String.self))), - GraphQLField("mimetype", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID, path: String, filename: String, mimetype: String) { - self.init(unsafeResultMap: ["__typename": "File", "id": id, "path": path, "filename": filename, "mimetype": mimetype]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - public var path: String { - get { - return resultMap["path"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "path") - } - } - - public var filename: String { - get { - return resultMap["filename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filename") - } - } - - public var mimetype: String { - get { - return resultMap["mimetype"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "mimetype") - } - } - } - } -} - -public final class UploadMultipleFilesToDifferentParametersMutation: GraphQLMutation { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - mutation UploadMultipleFilesToDifferentParameters($singleFile: Upload!, $multipleFiles: [Upload!]!) { - multipleParameterUpload(singleFile: $singleFile, multipleFiles: $multipleFiles) { - __typename - id - path - filename - mimetype - } - } - """ - - public let operationName: String = "UploadMultipleFilesToDifferentParameters" - - public let operationIdentifier: String? = "1ec89997a185c50bacc5f62ad41f27f3070f4a950d72e4a1510a4c64160812d5" - - public var singleFile: String - public var multipleFiles: [String] - - public init(singleFile: String, multipleFiles: [String]) { - self.singleFile = singleFile - self.multipleFiles = multipleFiles - } - - public var variables: GraphQLMap? { - return ["singleFile": singleFile, "multipleFiles": multipleFiles] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Mutation"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("multipleParameterUpload", arguments: ["singleFile": GraphQLVariable("singleFile"), "multipleFiles": GraphQLVariable("multipleFiles")], type: .nonNull(.list(.nonNull(.object(MultipleParameterUpload.selections))))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(multipleParameterUpload: [MultipleParameterUpload]) { - self.init(unsafeResultMap: ["__typename": "Mutation", "multipleParameterUpload": multipleParameterUpload.map { (value: MultipleParameterUpload) -> ResultMap in value.resultMap }]) - } - - public var multipleParameterUpload: [MultipleParameterUpload] { - get { - return (resultMap["multipleParameterUpload"] as! [ResultMap]).map { (value: ResultMap) -> MultipleParameterUpload in MultipleParameterUpload(unsafeResultMap: value) } - } - set { - resultMap.updateValue(newValue.map { (value: MultipleParameterUpload) -> ResultMap in value.resultMap }, forKey: "multipleParameterUpload") - } - } - - public struct MultipleParameterUpload: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["File"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("path", type: .nonNull(.scalar(String.self))), - GraphQLField("filename", type: .nonNull(.scalar(String.self))), - GraphQLField("mimetype", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID, path: String, filename: String, mimetype: String) { - self.init(unsafeResultMap: ["__typename": "File", "id": id, "path": path, "filename": filename, "mimetype": mimetype]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - public var path: String { - get { - return resultMap["path"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "path") - } - } - - public var filename: String { - get { - return resultMap["filename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filename") - } - } - - public var mimetype: String { - get { - return resultMap["mimetype"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "mimetype") - } - } - } - } -} - -public final class UploadOneFileMutation: GraphQLMutation { - /// The raw GraphQL definition of this operation. - public let operationDefinition: String = - """ - mutation UploadOneFile($file: Upload!) { - singleUpload(file: $file) { - __typename - id - path - filename - mimetype - } - } - """ - - public let operationName: String = "UploadOneFile" - - public let operationIdentifier: String? = "c5d5919f77d9ba16a9689b6b0ad4b781cb05dc1dc4812623bf80f7c044c09533" - - public var file: String - - public init(file: String) { - self.file = file - } - - public var variables: GraphQLMap? { - return ["file": file] - } - - public struct Data: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["Mutation"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("singleUpload", arguments: ["file": GraphQLVariable("file")], type: .nonNull(.object(SingleUpload.selections))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(singleUpload: SingleUpload) { - self.init(unsafeResultMap: ["__typename": "Mutation", "singleUpload": singleUpload.resultMap]) - } - - public var singleUpload: SingleUpload { - get { - return SingleUpload(unsafeResultMap: resultMap["singleUpload"]! as! ResultMap) - } - set { - resultMap.updateValue(newValue.resultMap, forKey: "singleUpload") - } - } - - public struct SingleUpload: GraphQLSelectionSet { - public static let possibleTypes: [String] = ["File"] - - public static var selections: [GraphQLSelection] { - return [ - GraphQLField("__typename", type: .nonNull(.scalar(String.self))), - GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))), - GraphQLField("path", type: .nonNull(.scalar(String.self))), - GraphQLField("filename", type: .nonNull(.scalar(String.self))), - GraphQLField("mimetype", type: .nonNull(.scalar(String.self))), - ] - } - - public private(set) var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } - - public init(id: GraphQLID, path: String, filename: String, mimetype: String) { - self.init(unsafeResultMap: ["__typename": "File", "id": id, "path": path, "filename": filename, "mimetype": mimetype]) - } - - public var __typename: String { - get { - return resultMap["__typename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "__typename") - } - } - - public var id: GraphQLID { - get { - return resultMap["id"]! as! GraphQLID - } - set { - resultMap.updateValue(newValue, forKey: "id") - } - } - - public var path: String { - get { - return resultMap["path"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "path") - } - } - - public var filename: String { - get { - return resultMap["filename"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "filename") - } - } - - public var mimetype: String { - get { - return resultMap["mimetype"]! as! String - } - set { - resultMap.updateValue(newValue, forKey: "mimetype") - } - } - } - } -} diff --git a/Sources/UploadAPI/Info.plist b/Sources/UploadAPI/Info.plist deleted file mode 100644 index 9bcb244429..0000000000 --- a/Sources/UploadAPI/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Sources/UploadAPI/UploadAPI.h b/Sources/UploadAPI/UploadAPI.h deleted file mode 100644 index 5afa45881e..0000000000 --- a/Sources/UploadAPI/UploadAPI.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// UploadAPI.h -// UploadAPI -// -// Created by Ellen Shapiro on 8/10/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -#import - -//! Project version number for UploadAPI. -FOUNDATION_EXPORT double UploadAPIVersionNumber; - -//! Project version string for UploadAPI. -FOUNDATION_EXPORT const unsigned char UploadAPIVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Sources/UploadAPI/graphql/UploadMultipleFiles.graphql b/Sources/UploadAPI/graphql/UploadMultipleFiles.graphql deleted file mode 100644 index ec9199d4ee..0000000000 --- a/Sources/UploadAPI/graphql/UploadMultipleFiles.graphql +++ /dev/null @@ -1,17 +0,0 @@ -mutation UploadMultipleFilesToTheSameParameter($files:[Upload!]!) { - multipleUpload(files:$files) { - id - path - filename - mimetype - } -} - -mutation UploadMultipleFilesToDifferentParameters($singleFile: Upload!, $multipleFiles:[Upload!]!) { - multipleParameterUpload(singleFile:$singleFile, multipleFiles:$multipleFiles) { - id - path - filename - mimetype - } -} diff --git a/Sources/UploadAPI/graphql/UploadOneFile.graphql b/Sources/UploadAPI/graphql/UploadOneFile.graphql deleted file mode 100644 index 598c39e173..0000000000 --- a/Sources/UploadAPI/graphql/UploadOneFile.graphql +++ /dev/null @@ -1,8 +0,0 @@ -mutation UploadOneFile($file: Upload!) { - singleUpload(file: $file) { - id - path - filename - mimetype - } -} diff --git a/Sources/UploadAPI/graphql/operationIDs.json b/Sources/UploadAPI/graphql/operationIDs.json deleted file mode 100644 index 8b0ad1a8ff..0000000000 --- a/Sources/UploadAPI/graphql/operationIDs.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "88858c283bb72f18c0049dc85b140e72a4046f469fa16a8bf4bcf01c11d8a2b7": { - "name": "UploadMultipleFilesToTheSameParameter", - "source": "mutation UploadMultipleFilesToTheSameParameter($files: [Upload!]!) {\n multipleUpload(files: $files) {\n __typename\n id\n path\n filename\n mimetype\n }\n}" - }, - "1ec89997a185c50bacc5f62ad41f27f3070f4a950d72e4a1510a4c64160812d5": { - "name": "UploadMultipleFilesToDifferentParameters", - "source": "mutation UploadMultipleFilesToDifferentParameters($singleFile: Upload!, $multipleFiles: [Upload!]!) {\n multipleParameterUpload(singleFile: $singleFile, multipleFiles: $multipleFiles) {\n __typename\n id\n path\n filename\n mimetype\n }\n}" - }, - "c5d5919f77d9ba16a9689b6b0ad4b781cb05dc1dc4812623bf80f7c044c09533": { - "name": "UploadOneFile", - "source": "mutation UploadOneFile($file: Upload!) {\n singleUpload(file: $file) {\n __typename\n id\n path\n filename\n mimetype\n }\n}" - } -} \ No newline at end of file diff --git a/Sources/UploadAPI/graphql/schema.json b/Sources/UploadAPI/graphql/schema.json deleted file mode 100644 index 207aeefe97..0000000000 --- a/Sources/UploadAPI/graphql/schema.json +++ /dev/null @@ -1,1394 +0,0 @@ -{ - "__schema": { - "description": null, - "queryType": { - "name": "Query" - }, - "mutationType": { - "name": "Mutation" - }, - "subscriptionType": null, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": "", - "fields": [ - { - "name": "uploads", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "File", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "File", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "path", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filename", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimetype", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": "", - "fields": [ - { - "name": "singleUpload", - "description": "", - "args": [ - { - "name": "file", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Upload", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "File", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "multipleUpload", - "description": "", - "args": [ - { - "name": "files", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Upload", - "ofType": null - } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "File", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "multipleParameterUpload", - "description": "", - "args": [ - { - "name": "singleFile", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Upload", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "multipleFiles", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Upload", - "ofType": null - } - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "File", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Upload", - "description": "The `Upload` scalar type represents a file upload.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "CacheControlScope", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "PUBLIC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PRIVATE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Directive", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByUrl`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "fields": [ - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__TypeKind", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "specifiedByUrl", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Field", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interfaces", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "possibleTypes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__EnumValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inputFields", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ofType", - "description": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isRepeatable", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locations", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__DirectiveLocation", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "VARIABLE_DEFINITION", - "description": "Location adjacent to a variable definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Location adjacent to an input object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - } - ], - "directives": [ - { - "name": "cacheControl", - "description": "", - "isRepeatable": false, - "locations": [ - "FIELD_DEFINITION", - "OBJECT", - "INTERFACE" - ], - "args": [ - { - "name": "maxAge", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "scope", - "description": null, - "type": { - "kind": "ENUM", - "name": "CacheControlScope", - "ofType": null - }, - "defaultValue": null - } - ] - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "isRepeatable": false, - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "isRepeatable": false, - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "isRepeatable": false, - "locations": [ - "FIELD_DEFINITION", - "ENUM_VALUE" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ] - }, - { - "name": "specifiedBy", - "description": "Exposes a URL that specifies the behaviour of this scalar.", - "isRepeatable": false, - "locations": [ - "SCALAR" - ], - "args": [ - { - "name": "url", - "description": "The URL that specifies the behaviour of this scalar.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "client", - "description": "Direct the client to resolve this field locally, either from the cache or local resolvers.", - "isRepeatable": false, - "locations": [ - "FIELD", - "FRAGMENT_DEFINITION", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "always", - "description": "When true, the client will never use the cache for this value. See\nhttps://www.apollographql.com/docs/react/essentials/local-state/#forcing-resolvers-with-clientalways-true", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - } - ] - }, - { - "name": "export", - "description": "Export this locally resolved field as a variable to be used in the remainder of this query. See\nhttps://www.apollographql.com/docs/react/essentials/local-state/#using-client-fields-as-variables", - "isRepeatable": false, - "locations": [ - "FIELD" - ], - "args": [ - { - "name": "as", - "description": "The variable name to export this field as.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "connection", - "description": "Specify a custom store key for this result. See\nhttps://www.apollographql.com/docs/react/advanced/caching/#the-connection-directive", - "isRepeatable": false, - "locations": [ - "FIELD" - ], - "args": [ - { - "name": "key", - "description": "Specify the store key.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filter", - "description": "An array of query argument names to include in the generated custom store key.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - } - ] - } - ] - } -} \ No newline at end of file diff --git a/SwiftScripts/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/SwiftScripts/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a625..0000000000 --- a/SwiftScripts/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/SwiftScripts/.swiftpm/xcode/xcshareddata/xcschemes/DocumentationGenerator.xcscheme b/SwiftScripts/.swiftpm/xcode/xcshareddata/xcschemes/DocumentationGenerator.xcscheme deleted file mode 100644 index b45b066290..0000000000 --- a/SwiftScripts/.swiftpm/xcode/xcshareddata/xcschemes/DocumentationGenerator.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SwiftScripts/ApolloCLI/.keep b/SwiftScripts/ApolloCLI/.keep deleted file mode 100644 index e4f700ab1b..0000000000 --- a/SwiftScripts/ApolloCLI/.keep +++ /dev/null @@ -1 +0,0 @@ -This file is here to preserve folder structure in git. diff --git a/SwiftScripts/Package.resolved b/SwiftScripts/Package.resolved deleted file mode 100644 index 7f39734a48..0000000000 --- a/SwiftScripts/Package.resolved +++ /dev/null @@ -1,88 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "MarkdownGenerator", - "repositoryURL": "https://github.com/eneko/MarkdownGenerator.git", - "state": { - "branch": null, - "revision": "1fc31be6b66245187c3f87f35d86b6aeac6dfe7f", - "version": "0.5.0" - } - }, - { - "package": "ProcessRunner", - "repositoryURL": "https://github.com/eneko/ProcessRunner.git", - "state": { - "branch": null, - "revision": "bedc55797b206bff50f652ffad8269223320fee5", - "version": "1.1.0" - } - }, - { - "package": "Rainbow", - "repositoryURL": "https://github.com/onevcat/Rainbow", - "state": { - "branch": null, - "revision": "626c3d4b6b55354b4af3aa309f998fae9b31a3d9", - "version": "3.2.0" - } - }, - { - "package": "SourceDocs", - "repositoryURL": "https://github.com/eneko/SourceDocs.git", - "state": { - "branch": null, - "revision": "fb0e489e3a26c789aad3adbe43e2169f50f485e8", - "version": "2.0.1" - } - }, - { - "package": "SourceKitten", - "repositoryURL": "https://github.com/jpsim/SourceKitten.git", - "state": { - "branch": null, - "revision": "817dfa6f2e09b0476f3a6c9dbc035991f02f0241", - "version": "0.32.0" - } - }, - { - "package": "SQLite.swift", - "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git", - "state": { - "branch": null, - "revision": "4d543d811ee644fa4cc4bfa0be996b4dd6ba0f54", - "version": "0.13.3" - } - }, - { - "package": "swift-argument-parser", - "repositoryURL": "https://github.com/apple/swift-argument-parser.git", - "state": { - "branch": null, - "revision": "e394bf350e38cb100b6bc4172834770ede1b7232", - "version": "1.0.3" - } - }, - { - "package": "SWXMLHash", - "repositoryURL": "https://github.com/drmohundro/SWXMLHash.git", - "state": { - "branch": null, - "revision": "6469881a3f30417c5bb02404ea4b69207f297592", - "version": "6.0.0" - } - }, - { - "package": "Yams", - "repositoryURL": "https://github.com/jpsim/Yams.git", - "state": { - "branch": null, - "revision": "9ff1cc9327586db4e0c8f46f064b6a82ec1566fa", - "version": "4.0.6" - } - } - ] - }, - "version": 1 -} diff --git a/SwiftScripts/Package.swift b/SwiftScripts/Package.swift deleted file mode 100644 index 6762e45fde..0000000000 --- a/SwiftScripts/Package.swift +++ /dev/null @@ -1,36 +0,0 @@ -// swift-tools-version:5.3 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "Codegen", - platforms: [ - .macOS(.v10_15) - ], - dependencies: [ - .package(name: "Apollo", path: ".."), - .package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.0.2")), - .package(url: "https://github.com/eneko/SourceDocs.git", .upToNextMinor(from: "2.0.0")) - ], - targets: [ - .target(name: "Codegen", - dependencies: [ - .product(name: "ApolloCodegenLib", package: "Apollo"), - .product(name: "ArgumentParser", package: "swift-argument-parser"), - ]), - .target(name: "SchemaDownload", - dependencies: [ - .product(name: "ApolloCodegenLib", package: "Apollo"), - ]), - .target(name: "DocumentationGenerator", - dependencies: [ - .product(name: "ApolloCodegenLib", package: "Apollo"), - .product(name: "SourceDocsLib", package: "SourceDocs"), - ]), - .testTarget(name: "CodegenTests", - dependencies: [ - "Codegen" - ]), - ] -) diff --git a/SwiftScripts/README.md b/SwiftScripts/README.md deleted file mode 100644 index ac6e4f9771..0000000000 --- a/SwiftScripts/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Codegen - -A description of this package. diff --git a/SwiftScripts/Sources/Codegen/Target.swift b/SwiftScripts/Sources/Codegen/Target.swift deleted file mode 100644 index e6dcbbe990..0000000000 --- a/SwiftScripts/Sources/Codegen/Target.swift +++ /dev/null @@ -1,76 +0,0 @@ -import Foundation -import ApolloCodegenLib -import ArgumentParser - -enum Target { - case starWars - case gitHub - case upload - - init?(name: String) { - switch name { - case "StarWars": - self = .starWars - case "GitHub": - self = .gitHub - case "Upload": - self = .upload - default: - return nil - } - } - - func targetRootURL(fromSourceRoot sourceRootURL: Foundation.URL) -> Foundation.URL { - switch self { - case .gitHub: - return sourceRootURL - .apollo.childFolderURL(folderName: "Sources") - .apollo.childFolderURL(folderName: "GitHubAPI") - case .starWars: - return sourceRootURL - .apollo.childFolderURL(folderName: "Sources") - .apollo.childFolderURL(folderName: "StarWarsAPI") - case .upload: - return sourceRootURL - .apollo.childFolderURL(folderName: "Sources") - .apollo.childFolderURL(folderName: "UploadAPI") - } - } - - func options(fromSourceRoot sourceRootURL: Foundation.URL) -> ApolloCodegenOptions { - let targetRootURL = self.targetRootURL(fromSourceRoot: sourceRootURL) - switch self { - case .upload: - let outputFileURL = try! targetRootURL.apollo.childFileURL(fileName: "API.swift") - - let graphQLFolderURL = targetRootURL.apollo.childFolderURL(folderName: "graphql") - let operationIDsURL = try! graphQLFolderURL.apollo.childFileURL(fileName: "operationIDs.json") - let schema = try! graphQLFolderURL.apollo.childFileURL(fileName: "schema.json") - return ApolloCodegenOptions(operationIDsURL: operationIDsURL, - outputFormat: .singleFile(atFileURL: outputFileURL), - urlToSchemaFile: schema) - case .starWars: - let outputFileURL = try! targetRootURL.apollo.childFileURL(fileName: "API.swift") - - let graphQLFolderURL = targetRootURL.apollo.childFolderURL(folderName: "graphql") - let operationIDsURL = try! graphQLFolderURL.apollo.childFileURL(fileName: "operationIDs.json") - let schema = try! graphQLFolderURL.apollo.childFileURL(fileName: "schema.json") - - return ApolloCodegenOptions(operationIDsURL: operationIDsURL, - outputFormat: .singleFile(atFileURL: outputFileURL), - urlToSchemaFile: schema) - case .gitHub: - let outputFileURL = try! targetRootURL.apollo.childFileURL(fileName: "API.swift") - - let graphQLFolderURL = targetRootURL.apollo.childFolderURL(folderName: "graphql") - let schema = try! graphQLFolderURL.apollo.childFileURL(fileName: "schema.docs.graphql") - let operationIDsURL = try! graphQLFolderURL.apollo.childFileURL(fileName: "operationIDs.json") - return ApolloCodegenOptions(includes: "graphql/Queries/**/*.graphql", - mergeInFieldsFromFragmentSpreads: true, - operationIDsURL: operationIDsURL, - outputFormat: .singleFile(atFileURL: outputFileURL), - suppressSwiftMultilineStringLiterals: true, - urlToSchemaFile: schema) - } - } -} diff --git a/SwiftScripts/Sources/Codegen/main.swift b/SwiftScripts/Sources/Codegen/main.swift deleted file mode 100644 index fa82ac4778..0000000000 --- a/SwiftScripts/Sources/Codegen/main.swift +++ /dev/null @@ -1,58 +0,0 @@ -import Foundation -import ApolloCodegenLib -import ArgumentParser - -// In a typical app, you'll only need to do this for one target, so you'd -// set these up directly within this file. Here, we're using more than one -// target, so we're using an arg parser to figure out which one to build, -// and an enum to hold related options. -struct Codegen: ParsableCommand { - - enum ArgumentError: Error, LocalizedError { - case invalidTargetName(name: String) - - var errorDescription: String? { - switch self { - case .invalidTargetName(let name): - return "The target \"\(name)\" was invalid. Please try again." - } - } - } - - @Option(name: [.customLong("target"), .customShort("t")], help: "The target to generate code for. Required.") - var targetName: String - - mutating func run() throws { - guard let target = Target(name: targetName) else { - throw ArgumentError.invalidTargetName(name: targetName) - } - - // Grab the parent folder of this file on the filesystem - let parentFolderOfScriptFile = FileFinder.findParentFolder() - - // Use that to calculate the source root - let sourceRootURL = parentFolderOfScriptFile - .apollo.parentFolderURL() // Sources - .apollo.parentFolderURL() // SwiftScripts - .apollo.parentFolderURL() // apollo-ios - - let targetURL = target.targetRootURL(fromSourceRoot: sourceRootURL) - let options = target.options(fromSourceRoot: sourceRootURL) - - // This more necessary if you're using a sub-folder, but make sure - // there's actually a place to write out what you're doing. - try FileManager.default.apollo.createFolderIfNeeded(at: targetURL) - - // Calculate where you want to download the CLI folder. - let cliFolderURL = sourceRootURL - .apollo.childFolderURL(folderName: "SwiftScripts") - .apollo.childFolderURL(folderName: "ApolloCLI") - - // Actually attempt to generate code. - try ApolloCodegen.run(from: targetURL, - with: cliFolderURL, - options: options) - } -} - -Codegen.main() diff --git a/SwiftScripts/Sources/DocumentationGenerator/main.swift b/SwiftScripts/Sources/DocumentationGenerator/main.swift deleted file mode 100644 index 8417e897c5..0000000000 --- a/SwiftScripts/Sources/DocumentationGenerator/main.swift +++ /dev/null @@ -1,66 +0,0 @@ -import Foundation -import SourceDocsLib -import ApolloCodegenLib - -enum Target: String, CaseIterable { - case Apollo - case ApolloAPI - case ApolloUtils - case ApolloSQLite - case ApolloWebSocket - case ApolloCodegenLib - - var name: String { - self.rawValue - } - - var scheme: String { - self.rawValue - } - - var outputFolder: String { - self.rawValue - } -} - -// Grab the parent folder of this file on the filesystem -let parentFolderOfScriptFile = FileFinder.findParentFolder() - -// Use that to calculate the source root -let sourceRootURL = parentFolderOfScriptFile - .deletingLastPathComponent() // Sources - .deletingLastPathComponent() // SwiftScripts - .deletingLastPathComponent() // apollo-ios - -for target in Target.allCases { - // Figure out where to put the docs for the current target. - let outputURL = sourceRootURL - .appendingPathComponent("docs") - .appendingPathComponent("source") - .appendingPathComponent("api") - .appendingPathComponent(target.outputFolder) - - let options = DocumentOptions(allModules: false, - spmModule: nil, - moduleName: target.name, - linkEndingText: "/", - inputFolder: sourceRootURL.path, - outputFolder: outputURL.path, - clean: true, - xcodeArguments: [ - "-scheme", - target.scheme, - "-project", - "Apollo.xcodeproj" - ], - reproducibleDocs: true) - - do { - try SourceDocsLib.DocumentationGenerator(options: options).run() - CodegenLogger.log("Generated docs for \(target.name)") - } catch { - CodegenLogger.log("Error generating docs for \(target.name): \(error)", logLevel: .error) - exit(1) - } -} - diff --git a/SwiftScripts/Sources/SchemaDownload/main.swift b/SwiftScripts/Sources/SchemaDownload/main.swift deleted file mode 100644 index 89ec5170a1..0000000000 --- a/SwiftScripts/Sources/SchemaDownload/main.swift +++ /dev/null @@ -1,35 +0,0 @@ -import Foundation -import ApolloCodegenLib - -// Grab the parent folder of this file on the filesystem -let parentFolderOfScriptFile = FileFinder.findParentFolder() - -// Use that to calculate the source root -let sourceRootURL = parentFolderOfScriptFile - .deletingLastPathComponent() // Sources - .deletingLastPathComponent() // SwiftScripts - .deletingLastPathComponent() // apollo-ios - -let endpoint = URL(string: "http://localhost:4000/")! - -let output = sourceRootURL - .appendingPathComponent("Sources") - .appendingPathComponent("UploadAPI") - -// Introspection download: -let configuration = ApolloSchemaDownloadConfiguration(using: .introspection(endpointURL: endpoint), - outputFolderURL: output, - schemaFilename: "schema") - -// Registry download: -//let registrySettings = ApolloSchemaDownloadConfiguration.DownloadMethod.RegistrySettings(apiKey: <#Replace Me For Testing#>, -// graphID: "Apollo-Fullstack-8zo5jl") -// -//let configuration = ApolloSchemaDownloadConfiguration(using: .registry(registrySettings), -// outputFolderURL: output) - -do { - try ApolloSchemaDownloader.fetch(with: configuration) -} catch { - exit(1) -} diff --git a/SwiftScripts/Tests/CodegenTests/CodegenTests.swift b/SwiftScripts/Tests/CodegenTests/CodegenTests.swift deleted file mode 100644 index 732f78bc77..0000000000 --- a/SwiftScripts/Tests/CodegenTests/CodegenTests.swift +++ /dev/null @@ -1,47 +0,0 @@ -import XCTest -import class Foundation.Bundle - -final class CodegenTests: XCTestCase { - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct - // results. - - // Some of the APIs that we use below are available in macOS 10.13 and above. - guard #available(macOS 10.13, *) else { - return - } - - let fooBinary = productsDirectory.appendingPathComponent("Codegen") - - let process = Process() - process.executableURL = fooBinary - - let pipe = Pipe() - process.standardOutput = pipe - - try process.run() - process.waitUntilExit() - - let data = pipe.fileHandleForReading.readDataToEndOfFile() - let output = String(data: data, encoding: .utf8) - - XCTAssertEqual(output, "Hello, world!\n") - } - - /// Returns path to the built products directory. - var productsDirectory: URL { - #if os(macOS) - for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { - return bundle.bundleURL.deletingLastPathComponent() - } - fatalError("couldn't find the products directory") - #else - return Bundle.main.bundleURL - #endif - } - - static var allTests = [ - ("testExample", testExample), - ] -} diff --git a/Tests/ApolloCodegenTests/ApolloCodegenTests.swift b/Tests/ApolloCodegenTests/ApolloCodegenTests.swift deleted file mode 100644 index 507bd85d7d..0000000000 --- a/Tests/ApolloCodegenTests/ApolloCodegenTests.swift +++ /dev/null @@ -1,209 +0,0 @@ -// -// ApolloCodegenTests.swift -// ApolloCodegenTests -// -// Created by Ellen Shapiro on 10/7/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import XCTest -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class ApolloCodegenTests: XCTestCase { - - override func setUp() { - super.setUp() - CodegenTestHelper.deleteExistingOutputFolder() - } - - override func tearDown() { - CodegenTestHelper.deleteExistingOutputFolder() - super.tearDown() - } - - func testCreatingOptionsWithDefaultParameters() throws { - let sourceRoot = CodegenTestHelper.sourceRootURL() - let output = sourceRoot.appendingPathComponent("API.swift") - let schema = sourceRoot.appendingPathComponent("schema.json") - - let options = ApolloCodegenOptions(outputFormat: .singleFile(atFileURL: output), - urlToSchemaFile: schema) - - - XCTAssertEqual(options.includes, "./**/*.graphql") - XCTAssertTrue(options.mergeInFieldsFromFragmentSpreads) - XCTAssertNil(options.namespace) - XCTAssertNil(options.only) - XCTAssertNil(options.operationIDsURL) - switch options.outputFormat { - case .singleFile(let fileURL): - XCTAssertEqual(fileURL, output) - case .multipleFiles: - XCTFail("Nope, this should be a single file!") - } - XCTAssertFalse(options.omitDeprecatedEnumCases) - XCTAssertEqual(options.customScalarFormat, .none) - XCTAssertEqual(options.urlToSchemaFile, schema) - XCTAssertEqual(options.modifier, .public) - - XCTAssertEqual(options.arguments, [ - "codegen:generate", - "--target=swift", - "--addTypename", - "--includes='./**/*.graphql'", - "--localSchemaFile='\(schema.path)'", - "--mergeInFieldsFromFragmentSpreads", - "'\(output.path)'", - ]) - } - - func testCreatingOptionsWithAllParameters() throws { - let sourceRoot = CodegenTestHelper.sourceRootURL() - let output = sourceRoot.appendingPathComponent("API") - let schema = sourceRoot.appendingPathComponent("schema.json") - let only = sourceRoot.appendingPathComponent("only.graphql") - let operationIDsURL = sourceRoot.appendingPathComponent("operationIDs.json") - let namespace = "ANameSpace" - let prefix = "MyPrefix" - - let options = ApolloCodegenOptions(codegenEngine: .typescript, - includes: "*.graphql", - excludes: "*.*.graphql", - mergeInFieldsFromFragmentSpreads: false, - modifier: .internal, - namespace: namespace, - omitDeprecatedEnumCases: true, - only: only, - operationIDsURL: operationIDsURL, - outputFormat: .multipleFiles(inFolderAtURL: output), - customScalarFormat: .passthroughWithPrefix(prefix), - urlToSchemaFile: schema) - XCTAssertEqual(options.includes, "*.graphql") - XCTAssertFalse(options.mergeInFieldsFromFragmentSpreads) - XCTAssertEqual(options.namespace, namespace) - XCTAssertEqual(options.only, only) - XCTAssertEqual(options.operationIDsURL, operationIDsURL) - switch options.outputFormat { - case .singleFile: - XCTFail("This should be multiple files!") - case .multipleFiles(let folderURL): - XCTAssertEqual(folderURL, output) - } - XCTAssertEqual(options.customScalarFormat, .passthroughWithPrefix(prefix)) - XCTAssertEqual(options.urlToSchemaFile, schema) - XCTAssertTrue(options.omitDeprecatedEnumCases) - XCTAssertEqual(options.modifier, .internal) - - - XCTAssertEqual(options.arguments, [ - "codegen:generate", - "--target=swift", - "--addTypename", - "--includes='*.graphql'", - "--localSchemaFile='\(schema.path)'", - "--namespace=\(namespace)", - "--only='\(only.path)'", - "--operationIdsPath='\(operationIDsURL.path)'", - "--excludes='*.*.graphql'", - "--omitDeprecatedEnumCases", - "--passthroughCustomScalars", - "--customScalarsPrefix='\(prefix)'", - "'\(output.path)'", - ]) - } - - func testTryingToUseAFileURLToOutputMultipleFilesFails() { - let scriptFolderURL = CodegenTestHelper.cliFolderURL() - let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL() - let starWarsSchemaFileURL = CodegenTestHelper.starWarsSchemaFileURL() - let outputFolder = CodegenTestHelper.outputFolderURL() - let outputFile = outputFolder.appendingPathComponent("API.swift") - - let options = ApolloCodegenOptions(outputFormat: .multipleFiles(inFolderAtURL: outputFile), - urlToSchemaFile: starWarsSchemaFileURL, - downloadTimeout: CodegenTestHelper.timeout) - do { - _ = try ApolloCodegen.run(from: starWarsFolderURL, - with: scriptFolderURL, - options: options) - } catch { - switch error { - case ApolloCodegen.CodegenError.multipleFilesButNotDirectoryURL(let url): - XCTAssertEqual(url, outputFile) - default: - XCTFail("Unexpected error running codegen: \(error.localizedDescription)") - - } - } - } - - func testTryingToUseAFolderURLToOutputASingleFileFails() { - let scriptFolderURL = CodegenTestHelper.cliFolderURL() - let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL() - let starWarsSchemaFileURL = CodegenTestHelper.starWarsSchemaFileURL() - let outputFolder = CodegenTestHelper.outputFolderURL() - - let options = ApolloCodegenOptions(outputFormat: .singleFile(atFileURL: outputFolder), - urlToSchemaFile: starWarsSchemaFileURL, - downloadTimeout: CodegenTestHelper.timeout) - do { - _ = try ApolloCodegen.run(from: starWarsFolderURL, - with: scriptFolderURL, - options: options) - } catch { - switch error { - case ApolloCodegen.CodegenError.singleFileButNotSwiftFileURL(let url): - XCTAssertEqual(url, outputFolder) - default: - XCTFail("Unexpected error running codegen: \(error.localizedDescription)") - } - } - } - - func testCodegenWithSingleFileOutputsSingleFile() throws { - let scriptFolderURL = CodegenTestHelper.cliFolderURL() - let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL() - let starWarsSchemaFileURL = CodegenTestHelper.starWarsSchemaFileURL() - let outputFolder = CodegenTestHelper.outputFolderURL() - let outputFile = outputFolder.appendingPathComponent("API.swift") - - let options = ApolloCodegenOptions(outputFormat: .singleFile(atFileURL: outputFile), - urlToSchemaFile: starWarsSchemaFileURL, - downloadTimeout: CodegenTestHelper.timeout) - do { - _ = try ApolloCodegen.run(from: starWarsFolderURL, - with: scriptFolderURL, - options: options) - } catch { - XCTFail("Error running codegen: \(error.localizedDescription)") - return - } - - XCTAssertTrue(FileManager.default.apollo.folderExists(at: outputFolder)) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: outputFile)) - - let contents = try FileManager.default.contentsOfDirectory(atPath: outputFolder.path) - XCTAssertEqual(contents.count, 1) - } - - func testCodegenWithMultipleFilesOutputsMultipleFiles() throws { - let scriptFolderURL = CodegenTestHelper.cliFolderURL() - let starWarsFolderURL = CodegenTestHelper.starWarsFolderURL() - let starWarsSchemaFileURL = CodegenTestHelper.starWarsSchemaFileURL() - let outputFolder = CodegenTestHelper.outputFolderURL() - - let options = ApolloCodegenOptions(outputFormat: .multipleFiles(inFolderAtURL: outputFolder), - urlToSchemaFile: starWarsSchemaFileURL, - downloadTimeout: CodegenTestHelper.timeout) - - _ = try ApolloCodegen.run(from: starWarsFolderURL, - with: scriptFolderURL, - options: options) - - XCTAssertTrue(FileManager.default.apollo.folderExists(at: outputFolder)) - - let contents = try FileManager.default.contentsOfDirectory(atPath: outputFolder.path) - XCTAssertEqual(contents.count, 18) - } -} diff --git a/Tests/ApolloCodegenTests/ApolloSchemaInternalTests.swift b/Tests/ApolloCodegenTests/ApolloSchemaInternalTests.swift deleted file mode 100644 index 47fc4f4ab6..0000000000 --- a/Tests/ApolloCodegenTests/ApolloSchemaInternalTests.swift +++ /dev/null @@ -1,126 +0,0 @@ -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class ApolloSchemaInternalTests: XCTestCase { - func testFormatConversion_givenIntrospectionJSON_shouldOutputValidSDL() throws { - let bundle = Bundle(for: type(of: self)) - guard let jsonURL = bundle.url(forResource: "introspection_response", withExtension: "json") else { - throw XCTFailure("Missing resource file!", file: #file, line: #line) - } - - try FileManager.default.apollo.createFolderIfNeeded(at: CodegenTestHelper.outputFolderURL()) - let configuration = ApolloSchemaDownloadConfiguration(using: .introspection(endpointURL: TestURL.mockPort8080.url), - outputFolderURL: CodegenTestHelper.outputFolderURL()) - - try ApolloSchemaDownloader.convertFromIntrospectionJSONToSDLFile(jsonFileURL: jsonURL, configuration: configuration) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: configuration.outputURL)) - - let frontend = try ApolloCodegenFrontend() - let source = try frontend.makeSource(from: configuration.outputURL) - let schema = try frontend.loadSchemaFromSDL(source) - - let authorType = try schema.getType(named: "Author") - XCTAssertEqual(authorType?.name, "Author") - - let postType = try schema.getType(named: "Post") - XCTAssertEqual(postType?.name, "Post") - } - - func testConfiguration_usingOnlyOutputFolders_shouldGenerateCompatibleFilenames() { - let downloadConfiguration = ApolloSchemaDownloadConfiguration(using: .introspection(endpointURL: TestURL.mockPort8080.url), - outputFolderURL: CodegenTestHelper.outputFolderURL()) - let codegenOptions = ApolloCodegenOptions(targetRootURL: CodegenTestHelper.outputFolderURL()) - - XCTAssertEqual(downloadConfiguration.outputURL, codegenOptions.urlToSchemaFile) - } - - func testRequest_givenIntrospectionGETDownload_shouldOutputGETRequest() throws { - let url = ApolloTestSupport.TestURL.mockServer.url - let queryParameterName = "customParam" - let headers: [ApolloSchemaDownloadConfiguration.HTTPHeader] = [ - .init(key: "key1", value: "value1"), - .init(key: "key2", value: "value2") - ] - - let request = try ApolloSchemaDownloader.introspectionRequest(from: url, - httpMethod: .GET(queryParameterName: queryParameterName), - headers: headers) - - XCTAssertEqual(request.httpMethod, "GET") - XCTAssertNil(request.httpBody) - - XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "application/json") - for header in headers { - XCTAssertEqual(request.allHTTPHeaderFields?[header.key], header.value) - } - - var components = URLComponents(url: url, resolvingAgainstBaseURL: true) - components?.queryItems = [URLQueryItem(name: queryParameterName, value: ApolloSchemaDownloader.IntrospectionQuery)] - - XCTAssertNotNil(components?.url) - XCTAssertEqual(request.url, components?.url) - } - - func testRequest_givenIntrospectionPOSTDownload_shouldOutputPOSTRequest() throws { - let url = ApolloTestSupport.TestURL.mockServer.url - let headers: [ApolloSchemaDownloadConfiguration.HTTPHeader] = [ - .init(key: "key1", value: "value1"), - .init(key: "key2", value: "value2") - ] - - let request = try ApolloSchemaDownloader.introspectionRequest(from: url, httpMethod: .POST, headers: headers) - - XCTAssertEqual(request.httpMethod, "POST") - XCTAssertEqual(request.url, url) - - XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "application/json") - for header in headers { - XCTAssertEqual(request.allHTTPHeaderFields?[header.key], header.value) - } - - let requestBody = UntypedGraphQLRequestBodyCreator.requestBody(for: ApolloSchemaDownloader.IntrospectionQuery, - variables: nil, - operationName: "IntrospectionQuery") - let bodyData = try JSONSerialization.data(withJSONObject: requestBody, options: [.sortedKeys]) - - XCTAssertEqual(request.httpBody, bodyData) - } - - func testRequest_givenRegistryDownload_shouldOutputPOSTRequest() throws { - let apiKey = "custom-api-key" - let graphID = "graph-id" - let variant = "a-variant" - let headers: [ApolloSchemaDownloadConfiguration.HTTPHeader] = [ - .init(key: "key1", value: "value1"), - .init(key: "key2", value: "value2"), - ] - - let request = try ApolloSchemaDownloader.registryRequest(with: .init(apiKey: apiKey, - graphID: graphID, - variant: variant), - headers: headers) - - XCTAssertEqual(request.httpMethod, "POST") - XCTAssertEqual(request.url, ApolloSchemaDownloader.RegistryEndpoint) - - XCTAssertEqual(request.allHTTPHeaderFields?["Content-Type"], "application/json") - XCTAssertEqual(request.allHTTPHeaderFields?["x-api-key"], apiKey) - for header in headers { - XCTAssertEqual(request.allHTTPHeaderFields?[header.key], header.value) - } - - let variables: [String: String] = [ - "graphID": graphID, - "variant": variant - ] - let requestBody = UntypedGraphQLRequestBodyCreator.requestBody(for: ApolloSchemaDownloader.RegistryDownloadQuery, - variables: variables, - operationName: "DownloadSchema") - let bodyData = try JSONSerialization.data(withJSONObject: requestBody, options: [.sortedKeys]) - - XCTAssertEqual(request.httpBody, bodyData) - } -} - diff --git a/Tests/ApolloCodegenTests/ApolloSchemaPublicTests.swift b/Tests/ApolloCodegenTests/ApolloSchemaPublicTests.swift deleted file mode 100644 index 5bb084669c..0000000000 --- a/Tests/ApolloCodegenTests/ApolloSchemaPublicTests.swift +++ /dev/null @@ -1,55 +0,0 @@ -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -import ApolloCodegenLib - -class ApolloSchemaPublicTests: XCTestCase { - private var defaultOutputURL: URL { - return CodegenTestHelper.outputFolderURL() - .appendingPathComponent("schema.graphqls") - } - - func testCreatingSchemaDownloadConfiguration_forIntrospectionDownload_usingDefaultParameters() throws { - let configuration = ApolloSchemaDownloadConfiguration(using: .introspection(endpointURL: TestURL.mockPort8080.url), - outputFolderURL: CodegenTestHelper.outputFolderURL()) - - XCTAssertEqual(configuration.downloadMethod, .introspection(endpointURL: TestURL.mockPort8080.url)) - XCTAssertEqual(configuration.outputURL, self.defaultOutputURL) - XCTAssertTrue(configuration.headers.isEmpty) - } - - func testCreatingSchemaDownloadConfiguration_forRegistryDownload_usingDefaultParameters() throws { - let settings = ApolloSchemaDownloadConfiguration.DownloadMethod.ApolloRegistrySettings(apiKey: "Fake_API_Key", - graphID: "Fake_Graph_ID") - let configuration = ApolloSchemaDownloadConfiguration(using: .apolloRegistry(settings), - outputFolderURL: CodegenTestHelper.outputFolderURL()) - - XCTAssertEqual(configuration.downloadMethod, .apolloRegistry(settings)) - XCTAssertEqual(configuration.outputURL, self.defaultOutputURL) - XCTAssertTrue(configuration.headers.isEmpty) - } - - func testCreatingSchemaDownloadConfiguration_forRegistryDownload_usingAllParameters() throws { - let sourceRoot = CodegenTestHelper.sourceRootURL() - let settings = ApolloSchemaDownloadConfiguration.DownloadMethod.ApolloRegistrySettings(apiKey: "Fake_API_Key", - graphID: "Fake_Graph_ID", - variant: "Fake_Variant") - let headers = [ - ApolloSchemaDownloadConfiguration.HTTPHeader(key: "Authorization", value: "Bearer tokenGoesHere"), - ApolloSchemaDownloadConfiguration.HTTPHeader(key: "Custom-Header", value: "Custom_Customer") - ] - - let schemaFileName = "different_name" - let configuration = ApolloSchemaDownloadConfiguration(using: .apolloRegistry(settings), - headers: headers, - outputFolderURL: sourceRoot, - schemaFilename: schemaFileName) - - XCTAssertEqual(configuration.downloadMethod, .apolloRegistry(settings)) - XCTAssertEqual(configuration.headers, headers) - - let expectedOutputURL = sourceRoot.appendingPathComponent("\(schemaFileName).graphqls") - XCTAssertEqual(configuration.outputURL, expectedOutputURL) - } -} - diff --git a/Tests/ApolloCodegenTests/CLIDownloaderTests.swift b/Tests/ApolloCodegenTests/CLIDownloaderTests.swift deleted file mode 100644 index 51949ed3a4..0000000000 --- a/Tests/ApolloCodegenTests/CLIDownloaderTests.swift +++ /dev/null @@ -1,45 +0,0 @@ -@testable import ApolloCodegenLib -import ApolloCodegenTestSupport -import XCTest - -class CLIDownloaderTests: XCTestCase { - func testForceRedownloading_withExistingFile_shouldOverwriteWithExpectedChecksum() throws { - let scriptsURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: scriptsURL) - - try "Dummy file".data(using: .utf8)?.write(to: zipFileURL) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: zipFileURL), "Created dummy file to be overwritten") - - try CLIDownloader.forceRedownload(to: scriptsURL, timeout: CodegenTestHelper.timeout) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: zipFileURL), "Downloaded Apollo CLI") - XCTAssertEqual(try FileManager.default.apollo.shasum(at: zipFileURL), CLIExtractor.expectedSHASUM) - } - - func testDownloading_toFolderThatDoesNotExist_shouldCreateFolder() throws { - let scriptsURL = CodegenTestHelper.cliFolderURL() - try FileManager.default.apollo.deleteFolder(at: scriptsURL) - XCTAssertFalse(FileManager.default.apollo.folderExists(at: scriptsURL)) - - try CLIDownloader.downloadIfNeeded(to: scriptsURL, timeout: 90.0) - XCTAssertTrue(FileManager.default.apollo.folderExists(at: scriptsURL)) - } - - func testTimeout_shouldThrowCorrectError() throws { - let scriptsURL = CodegenTestHelper.cliFolderURL() - - do { - try CLIDownloader.forceRedownload(to: scriptsURL, timeout: 0.5) - } catch { - guard - let DownloadError = error as? URLDownloader.DownloadError, - case .downloadTimedOut(let seconds) = DownloadError - else { - XCTFail("Wrong type of error") - return - } - - XCTAssertEqual(seconds, 0.5, accuracy: 0.0001) - } - } -} - diff --git a/Tests/ApolloCodegenTests/CLIExtractorTests.swift b/Tests/ApolloCodegenTests/CLIExtractorTests.swift deleted file mode 100644 index e27c229221..0000000000 --- a/Tests/ApolloCodegenTests/CLIExtractorTests.swift +++ /dev/null @@ -1,192 +0,0 @@ -// -// CLIExtractorTests.swift -// ApolloCodegenTests -// -// Created by Ellen Shapiro on 10/7/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import XCTest -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class CLIExtractorTests: XCTestCase { - - override func setUp() { - super.setUp() - CodegenTestHelper.downloadCLIIfNeeded() - CodegenTestHelper.deleteExistingApolloFolder() - } - - private func checkSHASUMFileContentsDirectly(at url: URL, - match expected: String, - file: StaticString = #filePath, - line: UInt = #line) { - guard let contents = try? String(contentsOf: url, encoding: .utf8) else { - XCTFail("Could not load file at \(url.path)", - file: file, - line: line) - return - } - - XCTAssertEqual(contents, - expected, - "Direct check of SHASUM failed. Got \(contents), expected \(expected)", - file: #file, - line: #line) - } - - private func validateSHASUMFile(shouldBeValid: Bool, - apolloFolderURL: URL, - match expected: String, - file: StaticString = #filePath, - line: UInt = #line) { - do { - let isValid = try CLIExtractor.validateSHASUMInExtractedFile(apolloFolderURL: apolloFolderURL, expected: expected) - XCTAssertEqual(isValid, - shouldBeValid, - file: file, - line: line) - } catch { - XCTFail("Error validating shasum in extracted file: \(error)", - file: file, - line: line) - } - } - - func validateCLIIsExtractedWithRealSHASUM(file: StaticString = #filePath, - line: UInt = #line) { - let binaryFolderURL = CodegenTestHelper.binaryFolderURL() - XCTAssertTrue(FileManager.default.apollo.folderExists(at: binaryFolderURL), - "Binary folder doesn't exist at \(binaryFolderURL)", - file: file, - line: line) - let binaryURL = ApolloFilePathHelper.binaryURL(fromBinaryFolder: binaryFolderURL) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: binaryURL), - "Binary doesn't exist at \(binaryURL)", - file: file, - line: line) - let shasumFileURL = CodegenTestHelper.shasumFileURL() - self.checkSHASUMFileContentsDirectly(at: shasumFileURL, - match: CLIExtractor.expectedSHASUM, - file: file, - line: line) - } - - func testValidatingSHASUMWithMatchingWorks() throws { - let cliFolderURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - try CLIExtractor.validateZipFileSHASUM(at: zipFileURL, expected: CLIExtractor.expectedSHASUM) - } - - func testValidatingSHASUMFailsWithoutMatch() throws { - let cliFolderURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - let bogusSHASUM = CLIExtractor.expectedSHASUM + "NOPE" - do { - try CLIExtractor.validateZipFileSHASUM(at: zipFileURL, expected: bogusSHASUM) - XCTFail("This should not have validated!") - } catch { - switch error { - case CLIExtractor.CLIExtractorError.zipFileHasInvalidSHASUM(let expectedSHASUM, let gotSHASUM): - XCTAssertEqual(expectedSHASUM, bogusSHASUM) - XCTAssertEqual(gotSHASUM, CLIExtractor.expectedSHASUM) - default: - XCTFail("Unexpected error: \(error)") - } - } - } - - func testExtractingZip() throws { - // Check that the binary hasn't already been extracted - // (it should be getting deleted in `setUp`) - let binaryFolderURL = CodegenTestHelper.binaryFolderURL() - XCTAssertFalse(FileManager.default.apollo.folderExists(at: binaryFolderURL)) - - // Actually extract the CLI - let cliFolderURL = CodegenTestHelper.cliFolderURL() - let extractedURL = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - - // Make sure we're getting the binary folder path back and that something's now there. - XCTAssertEqual(extractedURL.path, binaryFolderURL.path) - self.validateCLIIsExtractedWithRealSHASUM() - - // Make sure the validator is working - let apolloFolderURL = CodegenTestHelper.apolloFolderURL() - self.validateSHASUMFile(shouldBeValid: true, - apolloFolderURL: apolloFolderURL, - match: CLIExtractor.expectedSHASUM) - self.validateSHASUMFile(shouldBeValid: false, - apolloFolderURL: apolloFolderURL, - match: "NOPE") - } - - func testReExtractingZipWithDifferentSHA() throws { - // Extract the existing CLI - let cliFolderURL = CodegenTestHelper.cliFolderURL() - _ = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - - // Validate that it extracted and has the correct shasum - self.validateCLIIsExtractedWithRealSHASUM() - - // Replace the SHASUM file URL with a fake that doesn't match - let shasumFileURL = CodegenTestHelper.shasumFileURL() - let fakeSHASUM = "Old Shasum" - try fakeSHASUM.write(to: shasumFileURL, atomically: true, encoding: .utf8) - - // Validation should now fail since the SHASUMs don't match - let apolloFolderURL = CodegenTestHelper.apolloFolderURL() - XCTAssertFalse(try CLIExtractor.validateSHASUMInExtractedFile(apolloFolderURL: apolloFolderURL)) - - // Now try extracting again, and check SHASUM is now real again - _ = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - self.validateCLIIsExtractedWithRealSHASUM() - } - - func testFolderExistsButMissingSHASUMFileReExtractionWorks() throws { - // Make sure there is an apollo folder but no `.shasum` file - let apolloFolder = CodegenTestHelper.apolloFolderURL() - try FileManager.default.apollo.createFolderIfNeeded(at: apolloFolder) - - let cliFolderURL = CodegenTestHelper.cliFolderURL() - - // Now try extracting again, and check SHASUM is now real again - _ = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - self.validateCLIIsExtractedWithRealSHASUM() - } - - func testCorrectSHASUMButMissingBinaryReExtractionWorks() throws { - // Write just the SHASUM file, but nothing else - try CodegenTestHelper.writeSHASUMOnly(CLIExtractor.expectedSHASUM) - - // Make sure the binary folder's not there - let binaryFolderURL = CodegenTestHelper.binaryFolderURL() - XCTAssertFalse(FileManager.default.apollo.folderExists(at: binaryFolderURL)) - - // Re-extract and now everything should be there - let cliFolderURL = CodegenTestHelper.cliFolderURL() - _ = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - self.validateCLIIsExtractedWithRealSHASUM() - } - - func testMissingSHASUMFileButCorrectZipFileCreatesSHASUMFile() throws { - let shasumFileURL = CodegenTestHelper.shasumFileURL() - try FileManager.default.apollo.deleteFile(at: shasumFileURL) - - XCTAssertFalse(FileManager.default.apollo.fileExists(at: shasumFileURL)) - - let cliFolderURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - - XCTAssertTrue(FileManager.default.apollo.fileExists(at: zipFileURL)) - - let binaryURL = try CLIExtractor.extractCLIIfNeeded(from: cliFolderURL) - - /// Was the binary extracted? - XCTAssertTrue(FileManager.default.apollo.folderExists(at: binaryURL)) - - /// Did the SHASUM file get created? - XCTAssertTrue(FileManager.default.apollo.fileExists(at: shasumFileURL)) - self.validateCLIIsExtractedWithRealSHASUM() - } -} diff --git a/Tests/ApolloCodegenTests/FileManagerExtensionsTests.swift b/Tests/ApolloCodegenTests/FileManagerExtensionsTests.swift deleted file mode 100644 index 0a75885dde..0000000000 --- a/Tests/ApolloCodegenTests/FileManagerExtensionsTests.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// FileManagerExtensionsTests.swift -// ApolloCodegenTests -// -// Created by Ellen Shapiro on 10/7/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import Foundation -import XCTest -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class FileManagerExtensionsTests: XCTestCase { - - override func setUp() { - super.setUp() - CodegenTestHelper.downloadCLIIfNeeded() - CodegenTestHelper.deleteExistingApolloFolder() - } - - func testsFileExistsForZipFileURL() throws { - let cliFolderURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: zipFileURL)) - } - - func testFolderDoesNotExistForZipFileURL() throws { - let cliFolderURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: cliFolderURL) - XCTAssertFalse(FileManager.default.apollo.folderExists(at: zipFileURL)) - } - - func testFolderExistsForCLIFolderURL() throws { - let cliFolderURL = CodegenTestHelper.cliFolderURL() - XCTAssertTrue(FileManager.default.apollo.folderExists(at: cliFolderURL)) - } - - func testFileDoesNotExistForCLIFolderURL() throws { - let cliFolderURL = CodegenTestHelper.cliFolderURL() - XCTAssertFalse(FileManager.default.apollo.fileExists(at: cliFolderURL)) - } - - func testSHASUMOfIncludedBinaryMatchesExpected() throws { - let clifolderURL = CodegenTestHelper.cliFolderURL() - let zipFileURL = ApolloFilePathHelper.zipFileURL(fromCLIFolder: clifolderURL) - let shasum = try FileManager.default.apollo.shasum(at: zipFileURL) - XCTAssertEqual(shasum, CLIExtractor.expectedSHASUM) - } -} - diff --git a/Tests/ApolloCodegenTests/Frontend/CompilationTests.swift b/Tests/ApolloCodegenTests/Frontend/CompilationTests.swift deleted file mode 100644 index ce73c10bca..0000000000 --- a/Tests/ApolloCodegenTests/Frontend/CompilationTests.swift +++ /dev/null @@ -1,84 +0,0 @@ -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class CompilationTests: XCTestCase { - - var codegenFrontend: ApolloCodegenFrontend! - var schema: GraphQLSchema! - - override func setUpWithError() throws { - try super.setUpWithError() - - codegenFrontend = try ApolloCodegenFrontend() - - let introspectionResult = try String(contentsOf: XCTUnwrap(starWarsAPIBundle.url(forResource: "schema", withExtension: "json"))) - - schema = try codegenFrontend.loadSchemaFromIntrospectionResult(introspectionResult) - } - - override func tearDown() { - codegenFrontend = nil - schema = nil - - super.tearDown() - } - - func testCompileSingleQuery() throws { - let source = try codegenFrontend.makeSource(""" - query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - name - friends { - name - } - } - } - """, filePath: "HeroAndFriendsNames.graphql") - - let document = try codegenFrontend.parseDocument(source) - - let compilationResult = try codegenFrontend.compile(schema: schema, document: document) - - let operation = try XCTUnwrap(compilationResult.operations.first) - XCTAssertEqual(operation.name, "HeroAndFriendsNames") - XCTAssertEqual(operation.operationType, .query) - XCTAssertEqual(operation.rootType.name, "Query") - - XCTAssertEqual(operation.variables[0].name, "episode") - XCTAssertEqual(operation.variables[0].type.typeReference, "Episode") - - let heroField = try XCTUnwrap(operation.selectionSet.firstField(for: "hero")) - XCTAssertEqual(heroField.name, "hero") - XCTAssertEqual(heroField.type.typeReference, "Character") - - let episodeArgument = try XCTUnwrap(heroField.arguments?.first) - XCTAssertEqual(episodeArgument.name, "episode") - XCTAssertEqual(episodeArgument.value, .variable("episode")) - - let friendsField = try XCTUnwrap(heroField.selectionSet?.firstField(for: "friends")) - XCTAssertEqual(friendsField.name, "friends") - XCTAssertEqual(friendsField.type.typeReference, "[Character]") - - XCTAssertEqualUnordered(compilationResult.referencedTypes.map(\.name), ["Episode", "Character", "String"]) - } -} - -fileprivate extension CompilationResult.SelectionSet { - // This is a helper method that is really only suitable for testing because getting just the first - // occurrence of a field is of limited use when generating code. - func firstField(for responseKey: String) -> CompilationResult.Field? { - for selection in selections { - guard case let .field(field) = selection else { - continue - } - - if field.responseKey == responseKey { - return field - } - } - - return nil - } -} diff --git a/Tests/ApolloCodegenTests/Frontend/DocumentParsingAndValidationTests.swift b/Tests/ApolloCodegenTests/Frontend/DocumentParsingAndValidationTests.swift deleted file mode 100644 index 94af3c7167..0000000000 --- a/Tests/ApolloCodegenTests/Frontend/DocumentParsingAndValidationTests.swift +++ /dev/null @@ -1,175 +0,0 @@ -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class DocumentParsingAndValidationTests: XCTestCase { - - var codegenFrontend: ApolloCodegenFrontend! - var schema: GraphQLSchema! - - override func setUpWithError() throws { - try super.setUpWithError() - - codegenFrontend = try ApolloCodegenFrontend() - - let introspectionResult = try String(contentsOf: XCTUnwrap(starWarsAPIBundle.url(forResource: "schema", withExtension: "json"))) - - schema = try codegenFrontend.loadSchemaFromIntrospectionResult(introspectionResult) - } - - override func tearDown() { - codegenFrontend = nil - schema = nil - - super.tearDown() - } - - func testParseDocument() throws { - let source = try codegenFrontend.makeSource(""" - query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - name - friends { - name - } - } - } - """, filePath: "HeroAndFriendsNames.graphql") - - let document = try codegenFrontend.parseDocument(source) - - XCTAssertEqual(document.filePath, "HeroAndFriendsNames.graphql") - } - - func testParseDocumentWithSyntaxError() throws { - let source = try codegenFrontend.makeSource(""" - query HeroAndFriendsNames($episode: Episode) { - hero[episode: foo] - } - """, filePath: "HeroAndFriendsNames.graphql") - - XCTAssertThrowsError(try codegenFrontend.parseDocument(source)) { error in - whileRecordingErrors { - let error = try XCTDowncast(error as AnyObject, to: GraphQLError.self) - XCTAssert(try XCTUnwrap(error.message).starts(with: "Syntax Error")) - - let sourceLocations = try XCTUnwrap(error.sourceLocations) - XCTAssertEqual(sourceLocations.count, 1) - - XCTAssertEqual(sourceLocations[0].filePath, "HeroAndFriendsNames.graphql") - XCTAssertEqual(sourceLocations[0].lineNumber, 2) - } - } - } - - func testValidateDocument() throws { - let source = try codegenFrontend.makeSource(""" - query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - name - email - ...FriendsNames - } - } - """, filePath: "HeroAndFriendsNames.graphql") - - let document = try codegenFrontend.parseDocument(source) - - let validationErrors = try codegenFrontend.validateDocument(schema: schema, document: document) - - XCTAssertEqual(validationErrors.map(\.message), [ - """ - Cannot query field "email" on type "Character". - """, - """ - Unknown fragment "FriendsNames". - """ - ]) - - XCTAssertEqual(document.filePath, "HeroAndFriendsNames.graphql") - } - - func testParseAndValidateMultipleDocuments() throws { - let source1 = try codegenFrontend.makeSource(""" - query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - name - ...FriendsNames - } - } - """, filePath: "HeroAndFriendsNames.graphql") - - let source2 = try codegenFrontend.makeSource(""" - query HeroName($episode: Episode) { - hero(episode: $episode) { - name - } - } - """, filePath: "HeroName.graphql") - - let source3 = try codegenFrontend.makeSource(""" - fragment FriendsNames on Character { - friends { - name - } - } - """, filePath: "FriendsNames.graphql") - - let document1 = try codegenFrontend.parseDocument(source1) - let document2 = try codegenFrontend.parseDocument(source2) - let document3 = try codegenFrontend.parseDocument(source3) - - let document = try codegenFrontend.mergeDocuments([document1, document2, document3]) - XCTAssertEqual(document.definitions.count, 3) - - let validationErrors = try codegenFrontend.validateDocument(schema: schema, document: document) - XCTAssertEqual(validationErrors, []) - } - - // Errors during validation may contain multiple source locations. In the case of a field conflict - // for example, both fields would be associated with the same error. These locations - // may even come from different source files, so we need to test for that explicitly because - // handling that situation required a workaround (see `GraphQLError.sourceLocations`). - func testValidationErrorThatSpansMultipleDocuments() throws { - let source1 = try codegenFrontend.makeSource(""" - query HeroName($episode: Episode) { - hero(episode: $episode) { - foo: appearsIn - ...HeroName - } - } - """, filePath: "HeroName.graphql") - - let source2 = try codegenFrontend.makeSource(""" - fragment HeroName on Character { - foo: name - } - """, filePath: "HeroNameFragment.graphql") - - let document1 = try codegenFrontend.parseDocument(source1) - let document2 = try codegenFrontend.parseDocument(source2) - - let document = try codegenFrontend.mergeDocuments([document1, document2]) - XCTAssertEqual(document.definitions.count, 2) - - let validationErrors = try codegenFrontend.validateDocument(schema: schema, document: document) - - XCTAssertEqual(validationErrors.count, 1) - let validationError = validationErrors[0] - - XCTAssertEqual(validationError.message, """ - Fields "foo" conflict because "appearsIn" and "name" are different fields. \ - Use different aliases on the fields to fetch both if this was intentional. - """) - - let sourceLocations = try XCTUnwrap(validationError.sourceLocations) - XCTAssertEqual(sourceLocations.count, 2) - - XCTAssertEqual(sourceLocations[0].filePath, "HeroName.graphql") - XCTAssertEqual(sourceLocations[0].lineNumber, 3) - - XCTAssertEqual(sourceLocations[1].filePath, "HeroNameFragment.graphql") - XCTAssertEqual(sourceLocations[1].lineNumber, 2) - } -} diff --git a/Tests/ApolloCodegenTests/Frontend/Helpers.swift b/Tests/ApolloCodegenTests/Frontend/Helpers.swift deleted file mode 100644 index 3779c8d53a..0000000000 --- a/Tests/ApolloCodegenTests/Frontend/Helpers.swift +++ /dev/null @@ -1,3 +0,0 @@ -import XCTest - -var starWarsAPIBundle = Bundle(identifier: "com.apollographql.StarWarsAPI.macosx")! diff --git a/Tests/ApolloCodegenTests/Frontend/SchemaIntrospectionTests.swift b/Tests/ApolloCodegenTests/Frontend/SchemaIntrospectionTests.swift deleted file mode 100644 index b58c95c0d9..0000000000 --- a/Tests/ApolloCodegenTests/Frontend/SchemaIntrospectionTests.swift +++ /dev/null @@ -1,90 +0,0 @@ -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class SchemaIntrospectionTests: XCTestCase { - - var codegenFrontend: ApolloCodegenFrontend! - var schema: GraphQLSchema! - - override func setUpWithError() throws { - try super.setUpWithError() - - codegenFrontend = try ApolloCodegenFrontend() - - let introspectionResult = try String(contentsOf: XCTUnwrap(starWarsAPIBundle.url(forResource: "schema", withExtension: "json"))) - schema = try codegenFrontend.loadSchemaFromIntrospectionResult(introspectionResult) - } - - override func tearDown() { - codegenFrontend = nil - schema = nil - - super.tearDown() - } - - func testGetFieldsForObjectType() throws { - let droidType = try XCTDowncast(XCTUnwrap(schema.getType(named: "Droid")), to: GraphQLObjectType.self) - XCTAssertEqual(droidType.name, "Droid") - - let fields = droidType.fields - - XCTAssertEqual(fields["name"]?.name, "name") - XCTAssertEqual(fields["name"]?.type.typeReference, "String!") - - XCTAssertEqual(fields["friends"]?.name, "friends") - XCTAssertEqual(fields["friends"]?.type.typeReference, "[Character]") - } - - func testGetPossibleTypesForInterface() throws { - let characterType = try XCTDowncast(XCTUnwrap(schema.getType(named: "Character")), to: GraphQLAbstractType.self) - XCTAssertEqual(characterType.name, "Character") - - try XCTAssertEqualUnordered(schema.getPossibleTypes(characterType).map(\.name), ["Human", "Droid"]) - } - - func testGetPossibleTypesForUnion() throws { - let searchResultType = try XCTDowncast(XCTUnwrap(schema.getType(named: "SearchResult")), to: GraphQLAbstractType.self) - XCTAssertEqual(searchResultType.name, "SearchResult") - - try XCTAssertEqualUnordered(schema.getPossibleTypes(searchResultType).map(\.name), ["Human", "Droid", "Starship"]) - } - - func testGetTypesForUnion() throws { - let searchResultType = try XCTDowncast(XCTUnwrap(schema.getType(named: "SearchResult")), to: GraphQLUnionType.self) - XCTAssertEqual(searchResultType.name, "SearchResult") - - XCTAssertEqualUnordered(searchResultType.types.map(\.name), ["Human", "Droid", "Starship"]) - } - - func testEnumType() throws { - let episodeType = try XCTDowncast(XCTUnwrap(schema.getType(named: "Episode")), to: GraphQLEnumType.self) - XCTAssertEqual(episodeType.name, "Episode") - - XCTAssertEqual(episodeType.description, "The episodes in the Star Wars trilogy") - - XCTAssertEqual(episodeType.values.map(\.name), ["NEWHOPE", "EMPIRE", "JEDI"]) - XCTAssertEqual(episodeType.values.map(\.description), [ - "Star Wars Episode IV: A New Hope, released in 1977.", - "Star Wars Episode V: The Empire Strikes Back, released in 1980.", - "Star Wars Episode VI: Return of the Jedi, released in 1983." - ]) - } - - func testInputObjectType() throws { - let episodeType = try XCTDowncast(XCTUnwrap(schema.getType(named: "ReviewInput")), to: GraphQLInputObjectType.self) - XCTAssertEqual(episodeType.name, "ReviewInput") - - XCTAssertEqual(episodeType.description, "The input object sent when someone is creating a new review") - - XCTAssertEqual(episodeType.fields["stars"]?.type.typeReference, "Int!") - XCTAssertEqual(episodeType.fields["stars"]?.description, "0-5 stars") - - XCTAssertEqual(episodeType.fields["commentary"]?.type.typeReference, "String") - XCTAssertEqual(episodeType.fields["commentary"]?.description, "Comment about the movie, optional") - - XCTAssertEqual(episodeType.fields["favorite_color"]?.type.typeReference, "ColorInput") - XCTAssertEqual(episodeType.fields["favorite_color"]?.description, "Favorite color, optional") - } -} diff --git a/Tests/ApolloCodegenTests/Frontend/SchemaLoadingTests.swift b/Tests/ApolloCodegenTests/Frontend/SchemaLoadingTests.swift deleted file mode 100644 index 8f04b5292e..0000000000 --- a/Tests/ApolloCodegenTests/Frontend/SchemaLoadingTests.swift +++ /dev/null @@ -1,77 +0,0 @@ -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class SchemaLoadingTests: XCTestCase { - - var codegenFrontend: ApolloCodegenFrontend! - - override func setUpWithError() throws { - try super.setUpWithError() - - codegenFrontend = try ApolloCodegenFrontend() - } - - override func tearDown() { - codegenFrontend = nil - - super.tearDown() - } - - func testParseSchemaFromIntrospectionResult() throws { - let introspectionResult = try String(contentsOf: XCTUnwrap(starWarsAPIBundle.url(forResource: "schema", withExtension: "json"))) - - let schema = try codegenFrontend.loadSchemaFromIntrospectionResult(introspectionResult) - - let characterType = try XCTUnwrap(schema.getType(named: "Character")) - XCTAssertEqual(characterType.name, "Character") - } - - func testParseSchemaFromSDL() throws { - let source = try codegenFrontend.makeSource(from: XCTUnwrap(starWarsAPIBundle.url(forResource: "schema", withExtension: "graphqls"))) - let schema = try codegenFrontend.loadSchemaFromSDL(source) - - let characterType = try XCTUnwrap(schema.getType(named: "Character")) - XCTAssertEqual(characterType.name, "Character") - } - - func testParseSchemaFromSDLWithSyntaxError() throws { - let source = try codegenFrontend.makeSource(""" - type Query { - foo - } - """, filePath: "schema.graphqls") - - XCTAssertThrowsError(try codegenFrontend.loadSchemaFromSDL(source)) { error in - whileRecordingErrors { - let error = try XCTDowncast(error as AnyObject, to: GraphQLError.self) - XCTAssert(try XCTUnwrap(error.message).starts(with: "Syntax Error")) - - XCTAssertEqual(error.sourceLocations.count, 1) - XCTAssertEqual(error.sourceLocations[0].filePath, "schema.graphqls") - XCTAssertEqual(error.sourceLocations[0].lineNumber, 3) - } - } - } - - func testParseSchemaFromSDLWithValidationErrors() throws { - let source = try codegenFrontend.makeSource(""" - type Query { - foo: Foo - bar: Bar - } - """, filePath: "schema.graphqls") - - XCTAssertThrowsError(try codegenFrontend.loadSchemaFromSDL(source)) { error in - whileRecordingErrors { - let error = try XCTDowncast(error as AnyObject, to: GraphQLSchemaValidationError.self) - - let validationErrors = error.validationErrors - XCTAssertEqual(validationErrors.count, 2) - XCTAssertEqual(validationErrors[0].message, "Unknown type \"Foo\".") - XCTAssertEqual(validationErrors[1].message, "Unknown type \"Bar\".") - } - } - } -} diff --git a/Tests/ApolloCodegenTests/Info.plist b/Tests/ApolloCodegenTests/Info.plist deleted file mode 100644 index 64d65ca495..0000000000 --- a/Tests/ApolloCodegenTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Tests/ApolloCodegenTests/LineByLineComparison.swift b/Tests/ApolloCodegenTests/LineByLineComparison.swift deleted file mode 100644 index 4409590407..0000000000 --- a/Tests/ApolloCodegenTests/LineByLineComparison.swift +++ /dev/null @@ -1,90 +0,0 @@ -// -// LineByLineComparison.swift -// ApolloCodegenTests -// -// Created by Ellen Shapiro on 3/9/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import Foundation -import XCTest -import ApolloCodegenTestSupport - -struct LineByLineComparison { - - /// Compares line-by-line between the contents of a file and a received string - /// NOTE: Will trim whitespace from the file since Xcode auto-adds a newline - /// - /// - Parameters: - /// - received: The string received from the test - /// - expectedFileURL: The file URL to the file with the expected contents of the received string - /// - trimImports: If imports at the top of the file should be trimmed before the comparison. Defaults to false. - /// - file: The file where this function is being called. Defaults to the direct caller - /// - line: The line where this function is being called. Defaults to the direct caller - static func between(received: String, - expectedFileURL: URL, - trimImports: Bool = false, - file: StaticString = #filePath, - line: UInt = #line) { - guard FileManager.default.apollo.fileExists(at: expectedFileURL) else { - XCTFail("File not found at \(expectedFileURL)", - file: file, - line: line) - return - } - - let expected: String - do { - var fileContents = try String(contentsOf: expectedFileURL) - if trimImports { - fileContents = fileContents - .components(separatedBy: "\n") - .filter { !$0.hasPrefix("import ") } - .joined(separator: "\n") - } - - expected = fileContents.trimmingCharacters(in: .whitespacesAndNewlines) - } catch { - CodegenTestHelper.handleFileLoadError(error, - file: file, - line: line) - return - } - - self.between(received: received, - expected: expected, - file: file, - line: line) - } - - /// Compares two strings line-by-line. - /// - /// - Parameters: - /// - received: The string received from the test - /// - expectedFileURL: The string you expected to receive from the test - /// - file: The file where this function is being called. Defaults to the direct caller - /// - line: The line where this function is being called. Defaults to the direct caller - static func between(received: String, - expected: String, - file: StaticString = #filePath, - line: UInt = #line) { - - let receivedLines = received.components(separatedBy: "\n") - let expectedLines = expected.components(separatedBy: "\n") - - guard receivedLines.count == expectedLines.count else { - XCTFail("Expected \(expectedLines.count) lines, received \(receivedLines.count) lines.\nExpected: \n\(expected)\nReceived: \n\(received)", - file: file, - line: line) - return - } - - for (index, receivedLine) in receivedLines.enumerated() { - XCTAssertEqual(receivedLine, - expectedLines[index], - "Line \(index + 1) did not match", // correct for 0-indexing - file: file, - line: line) - } - } -} diff --git a/Tests/ApolloCodegenTests/Resources/introspection_response.json b/Tests/ApolloCodegenTests/Resources/introspection_response.json deleted file mode 100644 index a860f3deb2..0000000000 --- a/Tests/ApolloCodegenTests/Resources/introspection_response.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":{"name":"Mutation"},"subscriptionType":null,"types":[{"kind":"OBJECT","name":"Query","description":"the schema allows the following query:","fields":[{"name":"posts","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Post","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"author","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Author","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Post","description":"","fields":[{"name":"id","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"title","description":"","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"author","description":"","args":[],"type":{"kind":"OBJECT","name":"Author","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"votes","description":"","args":[],"type":{"kind":"SCALAR","name":"Int","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"Int","description":"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"SCALAR","name":"String","description":"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Author","description":"","fields":[{"name":"id","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"firstName","description":"","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"lastName","description":"","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"posts","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"OBJECT","name":"Post","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"Mutation","description":"this schema allows the following mutation:","fields":[{"name":"upvotePost","description":"","args":[{"name":"postId","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Post","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Schema","description":"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.","fields":[{"name":"types","description":"A list of all types supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"queryType","description":"The type that query operations will be rooted at.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"mutationType","description":"If this server supports mutation, the type that mutation operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"subscriptionType","description":"If this server support subscription, the type that subscription operations will be rooted at.","args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"directives","description":"A list of all directives supported by this server.","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Directive","ofType":null}}}},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Type","description":"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.","fields":[{"name":"kind","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__TypeKind","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"name","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"fields","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Field","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"interfaces","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"possibleTypes","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"enumValues","description":null,"args":[{"name":"includeDeprecated","description":null,"type":{"kind":"SCALAR","name":"Boolean","ofType":null},"defaultValue":"false"}],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__EnumValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"inputFields","description":null,"args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}},"isDeprecated":false,"deprecationReason":null},{"name":"ofType","description":null,"args":[],"type":{"kind":"OBJECT","name":"__Type","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__TypeKind","description":"An enum describing what kind of type a given `__Type` is.","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"SCALAR","description":"Indicates this type is a scalar.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Indicates this type is an object. `fields` and `interfaces` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Indicates this type is a union. `possibleTypes` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Indicates this type is an enum. `enumValues` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Indicates this type is an input object. `inputFields` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"LIST","description":"Indicates this type is a list. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null},{"name":"NON_NULL","description":"Indicates this type is a non-null. `ofType` is a valid field.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null},{"kind":"SCALAR","name":"Boolean","description":"The `Boolean` scalar type represents `true` or `false`.","fields":null,"inputFields":null,"interfaces":null,"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Field","description":"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__InputValue","description":"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"type","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__Type","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"defaultValue","description":"A GraphQL-formatted string representing the default value for this input value.","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__EnumValue","description":"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"isDeprecated","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"deprecationReason","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"OBJECT","name":"__Directive","description":"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.","fields":[{"name":"name","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"description","description":null,"args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"locations","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"__DirectiveLocation","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"args","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"LIST","name":null,"ofType":{"kind":"NON_NULL","name":null,"ofType":{"kind":"OBJECT","name":"__InputValue","ofType":null}}}},"isDeprecated":false,"deprecationReason":null},{"name":"onOperation","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onFragment","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."},{"name":"onField","description":null,"args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"isDeprecated":true,"deprecationReason":"Use `locations`."}],"inputFields":null,"interfaces":[],"enumValues":null,"possibleTypes":null},{"kind":"ENUM","name":"__DirectiveLocation","description":"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.","fields":null,"inputFields":null,"interfaces":null,"enumValues":[{"name":"QUERY","description":"Location adjacent to a query operation.","isDeprecated":false,"deprecationReason":null},{"name":"MUTATION","description":"Location adjacent to a mutation operation.","isDeprecated":false,"deprecationReason":null},{"name":"SUBSCRIPTION","description":"Location adjacent to a subscription operation.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD","description":"Location adjacent to a field.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_DEFINITION","description":"Location adjacent to a fragment definition.","isDeprecated":false,"deprecationReason":null},{"name":"FRAGMENT_SPREAD","description":"Location adjacent to a fragment spread.","isDeprecated":false,"deprecationReason":null},{"name":"INLINE_FRAGMENT","description":"Location adjacent to an inline fragment.","isDeprecated":false,"deprecationReason":null},{"name":"SCHEMA","description":"Location adjacent to a schema definition.","isDeprecated":false,"deprecationReason":null},{"name":"SCALAR","description":"Location adjacent to a scalar definition.","isDeprecated":false,"deprecationReason":null},{"name":"OBJECT","description":"Location adjacent to an object type definition.","isDeprecated":false,"deprecationReason":null},{"name":"FIELD_DEFINITION","description":"Location adjacent to a field definition.","isDeprecated":false,"deprecationReason":null},{"name":"ARGUMENT_DEFINITION","description":"Location adjacent to an argument definition.","isDeprecated":false,"deprecationReason":null},{"name":"INTERFACE","description":"Location adjacent to an interface definition.","isDeprecated":false,"deprecationReason":null},{"name":"UNION","description":"Location adjacent to a union definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM","description":"Location adjacent to an enum definition.","isDeprecated":false,"deprecationReason":null},{"name":"ENUM_VALUE","description":"Location adjacent to an enum value definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_OBJECT","description":"Location adjacent to an input object type definition.","isDeprecated":false,"deprecationReason":null},{"name":"INPUT_FIELD_DEFINITION","description":"Location adjacent to an input object field definition.","isDeprecated":false,"deprecationReason":null}],"possibleTypes":null}],"directives":[{"name":"skip","description":"Directs the executor to skip this field or fragment when the `if` argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"include","description":"Directs the executor to include this field or fragment only when the `if` argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"deprecated","description":"Marks an element of a GraphQL schema as no longer supported.","locations":["FIELD_DEFINITION","ENUM_VALUE"],"args":[{"name":"reason","description":"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"\"No longer supported\""}]}]}}} diff --git a/Tests/ApolloCodegenTests/SourcePackages/.keep b/Tests/ApolloCodegenTests/SourcePackages/.keep deleted file mode 100644 index f31659afa4..0000000000 --- a/Tests/ApolloCodegenTests/SourcePackages/.keep +++ /dev/null @@ -1 +0,0 @@ -This file exists to preserve folder structure in git. diff --git a/Tests/ApolloCodegenTests/URLDownloaderTests.swift b/Tests/ApolloCodegenTests/URLDownloaderTests.swift deleted file mode 100644 index 3ec8d280cc..0000000000 --- a/Tests/ApolloCodegenTests/URLDownloaderTests.swift +++ /dev/null @@ -1,139 +0,0 @@ -@testable import ApolloCodegenLib -import ApolloTestSupport -import ApolloCodegenTestSupport -import XCTest - -fileprivate class FailingNetworkSession: NetworkSession { - func loadData(with urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask? { - XCTFail("You must call setRequestHandler before using downloader!") - - return nil - } -} - -class URLDownloaderTests: XCTestCase { - let urlRequest = URLRequest(url: TestURL.mockServer.url) - let downloadURL = URL(string: "file://anywhere/nowhere/somewhere")! - let defaultTimeout = 0.5 - var downloader: URLDownloader! - var session: NetworkSession! - - override func setUp() { - downloader = URLDownloader(session: FailingNetworkSession()) - session = nil - } - - override func tearDown() { - downloader = nil - session = nil - } - - private func setRequestHandler(statusCode: Int, data: Data? = nil, error: Error? = nil, abandon: Bool = false) { - session = MockNetworkSession(statusCode: statusCode, data: data, error: error, abandon: abandon) - downloader = URLDownloader(session: session) - } - - func testDownloadError_withCustomError_shouldThrow() throws { - let statusCode = 400 - let domain = "ApolloCodegenTests" - let error = NSError(domain: domain, code: NSURLErrorNotConnectedToInternet, userInfo: nil) - - setRequestHandler(statusCode: statusCode, error: error) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch (let error as NSError) { - XCTAssertEqual(error.domain, domain) - XCTAssertEqual(error.code, NSURLErrorNotConnectedToInternet) - } - } - - func testDownloadError_withBadResponse_shouldThrow() throws { - let statusCode = 500 - let responseString = "Internal Error" - - setRequestHandler(statusCode: statusCode, data: responseString.data(using: .utf8)) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch URLDownloader.DownloadError.badResponse(let code, let response) { - XCTAssertEqual(code, statusCode) - XCTAssertEqual(response, responseString) - } catch { - XCTFail("Unexpected error received: \(error)") - } - } - - func testDownloadError_withEmptyResponseData_shouldThrow() throws { - setRequestHandler(statusCode: 200, data: Data()) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch URLDownloader.DownloadError.emptyDataReceived { - // Expected response - } catch { - XCTFail("Unexpected error received: \(error)") - } - } - - func testDownloadError_withNoResponseData_shouldThrow() throws { - setRequestHandler(statusCode: 200) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch URLDownloader.DownloadError.noDataReceived { - // Expected response - } catch { - XCTFail("Unexpected error received: \(error)") - } - } - - func testDownloadError_whenExceedingTimeout_shouldThrow() throws { - setRequestHandler(statusCode: 200, abandon: true) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch URLDownloader.DownloadError.downloadTimedOut(let timeout) { - XCTAssertEqual(timeout, defaultTimeout) - } catch { - XCTFail("Unexpected error received: \(error)") - } - } - - func testDownloadError_withIncorrectResponseType_shouldThrow() throws { - class CustomNetworkSession: NetworkSession { - func loadData(with urlRequest: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask? { - completionHandler(nil, URLResponse(), nil) - - return nil - } - } - - let downloader = URLDownloader(session: CustomNetworkSession()) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch URLDownloader.DownloadError.responseNotHTTPResponse { - // Expected response - } catch { - XCTFail("Unexpected error received: \(error)") - } - } - - func testDownloader_withCorrectResponse_shouldNotThrow() { - let statusCode = 200 - let responseString = "Success!" - let downloadURL = CodegenTestHelper.outputFolderURL().appendingPathComponent("urldownloader.txt") - - setRequestHandler(statusCode: statusCode, data: responseString.data(using: .utf8)) - - do { - try downloader.downloadSynchronously(with: urlRequest, to: downloadURL, timeout: defaultTimeout) - } catch { - XCTFail("Unexpected error received: \(error)") - } - - let output = try? String(contentsOf: downloadURL) - XCTAssertEqual(output, responseString) - } -} diff --git a/Tests/ApolloCodegenTests/URLExtensionsTests.swift b/Tests/ApolloCodegenTests/URLExtensionsTests.swift deleted file mode 100644 index ed81790c02..0000000000 --- a/Tests/ApolloCodegenTests/URLExtensionsTests.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// URLExtensionsTests.swift -// ApolloCodegenTests -// -// Created by Ellen Shapiro on 6/7/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import Foundation -import XCTest -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib -import ApolloUtils - -class URLExtensionsTests: XCTestCase { - - func testGettingParentFolderURL() { - let apolloCodegenTests = FileFinder.findParentFolder() - - let expectedParent = CodegenTestHelper.sourceRootURL() - .appendingPathComponent("Tests") - - let parent = apolloCodegenTests.apollo.parentFolderURL() - XCTAssertEqual(parent, expectedParent) - } - - func testGettingChildFolderURL() { - let testsFolderURL = CodegenTestHelper.sourceRootURL() - .appendingPathComponent("Tests") - - let expectedChild = FileFinder.findParentFolder() - - let child = testsFolderURL.apollo.childFolderURL(folderName: "ApolloCodegenTests") - XCTAssertEqual(child, expectedChild) - } - - func testGettingChildFileURL() throws { - let apolloCodegenTests = FileFinder.findParentFolder() - - let expectedFileURL = URL(fileURLWithPath: #file) - - let fileURL = try apolloCodegenTests.apollo.childFileURL(fileName: "URLExtensionsTests.swift") - - XCTAssertEqual(fileURL, expectedFileURL) - } - - func testGettingChildFileURLWithEmptyFilenameThrows() { - let starWars = CodegenTestHelper.starWarsFolderURL() - - do { - _ = try starWars.apollo.childFileURL(fileName: "") - XCTFail("That should have thrown") - } catch { - switch error { - case ApolloURLError.fileNameIsEmpty: - // This is what we want - break - default: - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGettingHiddenChildFileURL() throws { - let url = CodegenTestHelper.apolloFolderURL() - - let expectedFile = CodegenTestHelper.shasumFileURL() - let child = try url.apollo.childFileURL(fileName: ".shasum") - - XCTAssertEqual(child, expectedFile) - } - - func testIsDirectoryForExistingDirectory() { - let parentDirectory = FileFinder.findParentFolder() - XCTAssertTrue(FileManager.default.apollo.folderExists(at: parentDirectory)) - XCTAssertTrue(parentDirectory.apollo.isDirectoryURL) - } - - func testIsDirectoryForExistingFile() { - let currentFileURL = FileFinder.fileURL() - XCTAssertTrue(FileManager.default.apollo.fileExists(at: currentFileURL)) - XCTAssertFalse(currentFileURL.apollo.isDirectoryURL) - } - - func testIsSwiftFileForExistingFile() { - let currentFileURL = FileFinder.fileURL() - XCTAssertTrue(FileManager.default.apollo.fileExists(at: currentFileURL)) - XCTAssertTrue(currentFileURL.apollo.isSwiftFileURL) - } - - func testIsSwiftFileForNonExistentFileWithSingleExtension() { - let currentDirectory = FileFinder.findParentFolder() - let doesntExist = currentDirectory.appendingPathComponent("test.swift") - - XCTAssertFalse(FileManager.default.apollo.fileExists(at: doesntExist)) - XCTAssertTrue(doesntExist.apollo.isSwiftFileURL) - } - - func testIsSwiftFileForNonExistentFileWithMultipleExtensions() { - let currentDirectory = FileFinder.findParentFolder() - let doesntExist = currentDirectory.appendingPathComponent("test.graphql.swift") - - XCTAssertFalse(FileManager.default.apollo.fileExists(at: doesntExist)) - XCTAssertTrue(doesntExist.apollo.isSwiftFileURL) - } - -} diff --git a/Tests/ApolloPerformanceTests/Info.plist b/Tests/ApolloPerformanceTests/Info.plist deleted file mode 100644 index 64d65ca495..0000000000 --- a/Tests/ApolloPerformanceTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Tests/ApolloPerformanceTests/ParsingPerformanceTests.swift b/Tests/ApolloPerformanceTests/ParsingPerformanceTests.swift deleted file mode 100644 index 2d32a3c6ba..0000000000 --- a/Tests/ApolloPerformanceTests/ParsingPerformanceTests.swift +++ /dev/null @@ -1,52 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import GitHubAPI - -class ParsingPerformanceTests: XCTestCase { - - func testParseResult() throws { - let query = IssuesAndCommentsForRepositoryQuery() - - let response = try loadResponse(for: query) - - measure { - whileRecordingErrors { - let (result, _) = try response.parseResult() - - let data = try XCTUnwrap(result.data) - XCTAssertEqual(data.repository?.name, "apollo-ios") - } - } - } - - func testParseResultFast() throws { - let query = IssuesAndCommentsForRepositoryQuery() - - let response = try loadResponse(for: query) - - measure { - whileRecordingErrors { - let result = try response.parseResultFast() - - let data = try XCTUnwrap(result.data) - XCTAssertEqual(data.repository?.name, "apollo-ios") - } - } - } - - // MARK - Helpers - - func loadResponse(for query: Query, file: StaticString = #file, line: UInt = #line) throws -> GraphQLResponse { - let bundle = Bundle(for: type(of: self)) - - guard let url = bundle.url(forResource: query.operationName, withExtension: "json") else { - throw XCTFailure("Missing response file for query: \(query.operationName)", file: file, line: line) - } - - let data = try Data(contentsOf: url) - let body = try JSONSerialization.jsonObject(with: data, options: []) as! JSONObject - - return GraphQLResponse(operation: query, body: body) - } -} diff --git a/Tests/ApolloPerformanceTests/Responses/IssuesAndCommentsForRepository.json b/Tests/ApolloPerformanceTests/Responses/IssuesAndCommentsForRepository.json deleted file mode 100644 index 1d4ee36aeb..0000000000 --- a/Tests/ApolloPerformanceTests/Responses/IssuesAndCommentsForRepository.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"repository":{"__typename":"Repository","name":"apollo-ios","issues":{"__typename":"IssueConnection","nodes":[{"__typename":"Issue","title":"Xcode 12 Beta Archive issue ","author":{"__typename":"User","login":"nkmrh","id":"MDQ6VXNlcjU2NDQ0MjA=","name":"Hajime Nakamura"},"body":"I failed to archive app with 12.0 beta 2 and I found that other libraries have similar issues.\r\n\r\n- https://github.com/airbnb/lottie-ios/issues/1214\r\n- https://github.com/Alamofire/Alamofire/issues/3240\r\n\r\n# Error message\r\n\r\n```\r\nUndefined symbols for architecture armv7:\r\n \"type metadata for Swift._StringObject.Variant\", referenced from:\r\n outlined init with take of Swift._StringObject.Variant in ApolloStore.o\r\nld: symbol(s) not found for architecture armv7\r\nclang: error: linker command failed with exit code 1 (use -v to see invocation)\r\n```\r\n\r\n# Environment\r\nApollo version: 0.28.0\r\nXcode version: 12.0 beta 2 (12A6163b)\r\nSwift version: 5.3 (swiftlang-1200.0.16.13 clang-1200.0.22.25)\r\nPlatform(s) running Apollo: iOS\r\nmacOS version running Xcode: 10.15.5","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Weird! I'm literally testing the new beta right now, and I was just able to build and test `0.29.1` with Xcode 12 b2 without any problem. Have you cleaned your build folder and/or done the [derived data dance](http://derivedata.dance) recently? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":">Have you cleaned your build folder and/or done the derived data dance recently?\r\n\r\nI've tried it but it hasn't helped...\r\n\r\nCould you try setting the build configuration to release? ~~It seems that the optimization level is related.~~ Or try archive.","author":{"__typename":"User","login":"nkmrh","id":"MDQ6VXNlcjU2NDQ0MjA=","name":"Hajime Nakamura"}},{"__typename":"IssueComment","body":"Can't really do archive on a framework, but can confirm this is showing up if I switch the Run action to build for release. \r\n\r\nIt looks like the issue is [some kind of bug with substrings in the beta](https://developer.apple.com/forums/thread/649918?answerId=614735022#614735022). Unfortunately because we support older versions of iOS, disabling armv7 support in the library isn't really a good option for us. \r\n\r\nIt also looks like the workaround for our library isn't as simple as [Lottie's](https://github.com/airbnb/lottie-ios/pull/1215) - we're not using `prefix` and `suffix` methods on `String` anywhere in the main `Apollo` lib, and I'm getting an error on compilation in release mode with a totally different file than you are (`GraphQLResultNormalizer.o`) that's not doing any super-obvious string manipulation. \r\n\r\nIf you have some time to dig around, I'd encourage you to. At this point I've got enough on my plate that something clearly acknowledged by Apple as a bug and which only affects release builds on a beta Xcode is not going to be something I prioritize digging into on my own. Will definitely check back in on this with subsequent beta releases though. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"https://github.com/zhangao0086/DKImagePickerController/issues/669","author":{"__typename":"User","login":"OmarJalil","id":"MDQ6VXNlcjI1NTIwMDE1","name":"Jalil"}},{"__typename":"IssueComment","body":"@designatednerd Thank you for your research. I want to wait for this bug to be fixed in a future Xcode version.","author":{"__typename":"User","login":"nkmrh","id":"MDQ6VXNlcjU2NDQ0MjA=","name":"Hajime Nakamura"}},{"__typename":"IssueComment","body":"I am experiencing this issue as well, which prevented Carthage from building Apollo. I mentioned the issue in the Xcode 12 thread: https://github.com/apollographql/apollo-ios/pull/1280\r\n\r\nI fixed the issue here: https://github.com/danl3v/apollo-ios/tree/0.29.1-xcode12 and it works fine. Feel free to cherry-pick the latest commit to another version of apollo as required. Hopefully Apple will fix its substring issue","author":{"__typename":"User","login":"danl3v","id":"MDQ6VXNlcjg4MzE4OA==","name":"Daniel Levy"}},{"__typename":"IssueComment","body":"Xcode 12 beta 3 just came out, and I am now no longer able to reproduce this by switching the run action to build for release. \r\n\r\n@danl3v @nkmrh Can you please confirm that this is no longer an issue on the `betas/xcode-12` branch for you? Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Will do early next week","author":{"__typename":"User","login":"danl3v","id":"MDQ6VXNlcjg4MzE4OA==","name":"Daniel Levy"}},{"__typename":"IssueComment","body":"@designatednerd @danl3v I confirmed the issue on the `betas/xcode-12 ` branch with Xcode 12.0 beta 3. Unfortunately the one reproduced :(","author":{"__typename":"User","login":"nkmrh","id":"MDQ6VXNlcjU2NDQ0MjA=","name":"Hajime Nakamura"}},{"__typename":"IssueComment","body":"@nkmrh Weird! Did you do `Clean Build Folder` before trying to archive? I double-checked that I'd done that before trying to do the run action as build for release and it still worked. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd I checked the betas/xcode-12 branch again and the build was successful but when I add it to a simple project with cocoapods, it still fails to build... (archive is still failing)","author":{"__typename":"User","login":"nkmrh","id":"MDQ6VXNlcjU2NDQ0MjA=","name":"Hajime Nakamura"}},{"__typename":"IssueComment","body":"Interesting....I'll poke at that today. Thanks!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd I tried it with Xcode 12 beta 4, it solved!","author":{"__typename":"User","login":"nkmrh","id":"MDQ6VXNlcjU2NDQ0MjA=","name":"Hajime Nakamura"}},{"__typename":"IssueComment","body":"Excellent! I'm going to close this issue out then - if anyone has issues archiving on Beta 4 or after, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Beta 4 works for us!","author":{"__typename":"User","login":"danl3v","id":"MDQ6VXNlcjg4MzE4OA==","name":"Daniel Levy"}}]}},{"__typename":"Issue","title":"[Web] - Installation panel doesn't expand content","author":{"__typename":"User","login":"wongzigii","id":"MDQ6VXNlcjczODQyODg=","name":"Zigii Wong"},"body":"![image](https://user-images.githubusercontent.com/7384288/86875928-2ad0f500-c116-11ea-8d1f-804f25c74d0f.png)\r\n\r\nClicking the Installation panel doesn't show the content.\r\n\r\nChrome 83.0.4103.116 64-bit","comments":{"__typename":"IssueCommentConnection","nodes":[]}},{"__typename":"Issue","title":"[Web] - Installation panel doesn't expand content","author":{"__typename":"User","login":"wongzigii","id":"MDQ6VXNlcjczODQyODg=","name":"Zigii Wong"},"body":"![image](https://user-images.githubusercontent.com/7384288/86875928-2ad0f500-c116-11ea-8d1f-804f25c74d0f.png)\r\n\r\nClicking the Installation panel doesn't show the content.\r\n\r\nChrome 83.0.4103.116 64-bit","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Oops! I'll let our docs team know, thank you for the heads up!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Fixed by https://github.com/apollographql/apollo-ios/pull/1306\r\n\r\nCheck it out here: https://www.apollographql.com/docs/ios/installation/","author":{"__typename":"User","login":"trevorblades","id":"MDQ6VXNlcjEyMTY5MTc=","name":"Trevor Blades"}},{"__typename":"IssueComment","body":"Thanks @trevorblades, you rock!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"通过 CocoaPods 导入 Apollo 丢失 WebSocket","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null},"body":"通过 CocoaPods 导入 Apollo 丢失 WebSocket\r\nPodfile 文件中添加 pod 'Apollo', '~> 0.29.0' 执行pod install 完成后 在工程 Pods 中 只有 Apollo/Core 文件 无法找到 Apollo/WebSocket \r\n引用 import ApolloWebSocket 报错 \" No such module 'ApolloWebSocket' \"\r\n\r\n如下图:\r\nPodfile文件:\r\n\"WeChatf75880a9f15d2f78d3d97ec0cd4bc4d9\"\r\n\r\npod search Apollo\r\n\"pod_search_apollo\"\r\n\r\npod install 完成后\r\n\"pod_install\"\r\n\r\n使用代码\r\n\"code\"\r\n\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Google translated:\r\n\r\n> Importing Apollo via CocoaPods loses WebSocket\r\n> Add pod'Apollo' in the Podfile file,'~> 0.29.0' After executing pod install, only Apollo/Core files cannot be found in the project Pods.\r\n> Quoting import ApolloWebSocket reports error \"No such module'ApolloWebSocket'\"\r\n>\r\n> As shown below:\r\n> Podfile\r\n\r\nYou need to add the `Apollo/WebSocket` subspec in order to access the WebSocket library - it is not included by default, only the core libraries are included by default. So your podfile should look like this if you want to use the web socket library: \r\n\r\n```\r\npod 'Apollo', '~>0.29.0'\r\npod 'Apollo/WebSocket', '~>0.29.0'\r\n```","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"ok","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null}}]}},{"__typename":"Issue","title":"Figure out how to test cache key generation with JSON objects","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"},"body":"#1281 addresses an issue where cache keys were being unstably generated when one of the items was a JSON array. I haven't been able to find an API that takes JSON arrays, so we need to find an alternate method of testing key generation for this. Don't want to hold up an actual fix for the issue until I can figure this out, so making this issue to come back to it.","comments":{"__typename":"IssueCommentConnection","nodes":[]}},{"__typename":"Issue","title":"Fatal error (\"Optional is only JSONEncodable if Wrapped is\") when trying to update SqlNormalizedCache manually after a successful mutation operation","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"},"body":"While using Apollo iOS 0.29.1, I appear to be running into an issue similar to the one reported [here](https://github.com/apollographql/apollo-ios/issues/1271). I asked for help with this issue in [Spectrum](https://spectrum.chat/apollo/apollo-ios/updating-cache-after-insert-mutation~71008cf0-6ccf-4474-95bb-ac22c83e9616), and @designatednerd asked me to create a new issue.\r\n\r\nI'm trying to update the SqlNormalizedCache (which is setup and working properly) using the result of a successful mutation operation:\r\n\r\n```\r\napollo.perform(mutation: InsertTaskResponseMutation(taskId: 1, response: \"\")) { result in\r\n guard\r\n let resultData = try? result.get().data,\r\n let taskResponseDetails = resultData.insertTaskResponses?.returning.first?.fragments.taskResponseDetails\r\n else {\r\n return\r\n }\r\n\r\n apollo.store.withinReadWriteTransaction({ transaction in\r\n try! transaction.write(object: taskResponseDetails, withKey: \"task_responses-\\(taskResponseDetails.id)\")\r\n })\r\n}\r\n```\r\n\r\nThis is throwing a fatal error in \"JSONStandardTypeConversions.swift\" at line 109:\r\n\r\n\"Screen\r\n\r\nPrinting the description of `self`:\r\n\r\n```\r\nPrinting description of self:\r\n▿ Optional\r\n - some : 07/08/2020\r\n```\r\n\r\nIn this case, `self` is a property on the `response` property, which is a custom `jsonb` type. Here's the type alias:\r\n\r\n```\r\npublic typealias jsonb = [String : Any?]\r\n\r\nextension Dictionary: JSONDecodable {\r\n public init(jsonValue value: JSONValue) throws {\r\n guard let dictionary = value as? Dictionary else {\r\n throw JSONDecodingError.couldNotConvert(value: value, to: Dictionary.self)\r\n }\r\n \r\n self = dictionary\r\n }\r\n}\r\n```\r\n\r\nAnd here's the query:\r\n\r\n```\r\nquery ChallengeTaskResponse($taskResponseId: Int) {\r\n challenge_responses(where: {id: {_eq: $taskResponseId}}) {\r\n ...ChallengeTaskResponseDetails\r\n }\r\n}\r\n```\r\n\r\nThe mutation:\r\n\r\n```\r\nmutation InsertTaskResponse($response: jsonb) {\r\n insert_task_responses(objects: {response: $response}) {\r\n returning {\r\n ...TaskResponseDetails\r\n }\r\n }\r\n}\r\n```\r\n\r\nAnd, finally, the fragment that's used by both the query and the mutation:\r\n\r\n```\r\nfragment TaskResponseDetails on task_responses {\r\n id\r\n response // The 'jsonb' custom data type\r\n}\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"The problem definitely seems to be in the fact that the value type in the dictionary is `Optional`, and that's what it's trying to use to create a key. \r\n\r\nDoes it work to typealias it to `[String: JSONDecodable?]` instead?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'll test that here shortly and report back.","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"@nateirwin Were you ever able to get this tested out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd: I started to dive into this, ran into a minor issue (that's project-specific and I just need to push through), then got pulled into another issue altogether. This is still critical for our project and it's next on my list, so I'll get to it soon.\r\n\r\nI'm happy to close this and re-open when I've had the chance to test, if that's helpful.","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"Nah, leave it open for now, I'll keep annoying you about it from time to time 😇","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Ok, reporting back :-)\r\n\r\nSwitching the typealias to `public typealias jsonb = [String : JSONDecodable?]` throws an error when loading a query that has a `jsonb` property on it:\r\n\r\n```\r\nPrinting description of error:\r\n▿ GraphQLResultError\r\n ▿ path : communities.0.organization_community_memberships.1.organization.paper_maps.0.paper_map.status\r\n ▿ head : Optional\r\n ▿ some : \r\n ▿ underlying : JSONDecodingError\r\n ▿ couldNotConvert : 2 elements\r\n ▿ value : 24 elements\r\n ▿ 0 : 2 elements\r\n - key : status\r\n - value : Uploading tiles complete\r\n ▿ 1 : 2 elements\r\n - key : min_zoom\r\n - value : 9\r\n ▿ 2 : 2 elements\r\n - key : extent_max_lon\r\n - value : -100.1\r\n ▿ 3 : 2 elements\r\n - key : extent_min_lat\r\n - value : 37.1\r\n ▿ 4 : 2 elements\r\n - key : tileset\r\n - value : tileset_548\r\n ▿ 5 : 2 elements\r\n - key : pdfPath\r\n - value : https://test.xyz/test.pdf\r\n ▿ 6 : 2 elements\r\n - key : updated_at\r\n - value : 2019-07-29T15:04:09.623Z\r\n ▿ 7 : 2 elements\r\n - key : extent_max_lat\r\n - value : 34.1\r\n ▿ 8 : 2 elements\r\n - key : localTilesPath\r\n - value : https://test.xyz/tiles/\r\n ▿ 9 : 2 elements\r\n - key : geotiff_path\r\n - value : /image_georef.tif\r\n ▿ 10 : 2 elements\r\n - key : geotiff_3857_path\r\n - value : /image_georef_3857.tif\r\n ▿ 11 : 2 elements\r\n - key : name\r\n - value : Name Here\r\n ▿ 12 : 2 elements\r\n - key : max_zoom\r\n - value : 15\r\n ▿ 13 : 2 elements\r\n - key : id\r\n - value : 548\r\n ▿ 14 : 2 elements\r\n - key : temp_georefTilesPath\r\n - value : \r\n - super : NSObject\r\n ▿ 15 : 2 elements\r\n - key : ground_control_points\r\n - value : [[1071.640625,2925.1640625,-122.104733996093,37.714753539402],[1355.44921875,2053.29296875,-122.09752430208,37.7391649876836],[1192.0390625,1299.8125,-122.105021746829,37.7592430319794],[669.765625,594.1796875,-122.124813348055,37.7770496273366]]\r\n ▿ 16 : 2 elements\r\n - key : png_path\r\n - value : /final.png\r\n ▿ 17 : 2 elements\r\n - key : page_number\r\n - value : { ... }\r\n ▿ 18 : 2 elements\r\n - key : image_width\r\n - value : 2550\r\n ▿ 19 : 2 elements\r\n - key : created_at\r\n - value : 2019-07-29T14:57:07.796Z\r\n ▿ 20 : 2 elements\r\n - key : georefTilesPath\r\n - value : https://test.xyz/tiles_georef\r\n ▿ 21 : 2 elements\r\n - key : image_height\r\n - value : 3300\r\n ▿ 22 : 2 elements\r\n - key : extent_min_lon\r\n - value : -115.1\r\n ▿ 23 : 2 elements\r\n - key : file_type\r\n - value : pdf\r\n - to : Swift.Dictionary>\r\n```\r\n\r\nI'm guessing maybe it's bonking on the `null` values? Honestly, we've run into so many issues with this custom `jsonb` scalar type that I'm considering trying to back out of using it altogether.","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"Hm, shouldn't be bonking on nulls, we've got something that [theoretically should be handling that](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/JSONStandardTypeConversions.swift#L89). From the underlying error it looks like it's freaking out about the `status` key which is just a String. \r\n\r\nI think a bigger question this brings up is why this data needs to be returned as an arbitrary JSON blob in the first place - why isn't this data returned as something typed? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Well, `status` is the name of the `jsonb` property, which (I think) should be of type `[String: JSONDecodable?]` because of the type alias:\r\n\r\n```\r\npublic typealias jsonb = [String : JSONDecodable?]\r\n\r\nextension Dictionary: JSONDecodable {\r\n public init(jsonValue value: JSONValue) throws {\r\n guard let dictionary = value as? Dictionary else {\r\n throw JSONDecodingError.couldNotConvert(value: value, to: Dictionary.self)\r\n }\r\n \r\n self = dictionary\r\n }\r\n}\r\n```\r\n\r\nThat's why I'm scratching my head about this. Maybe my next step is setting some more breakpoints in JSONStandardTypeConversions.swift?","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"Looking at the JSON, `status` seems to be a key and value of the dictionary which isn't getting deserialized - can you throw in a breakpoint and print out the raw JSON string (or use a proxying tool to see it) that's coming through? That might help.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Sure, here you go (sorry about the delay):\r\n\r\n```\r\n{\r\n \"data\": {\r\n \"communities\": [\r\n {\r\n \"organization_community_memberships\": [\r\n {\r\n \"id\": 467,\r\n \"organization\": {\r\n \"paper_maps\": [\r\n {\r\n \"id\": 557,\r\n \"paper_map\": {\r\n \"description\": \"null\",\r\n \"id\": 322,\r\n \"name\": \"Name Here\",\r\n \"status\": {\r\n \"id\": 548,\r\n \"name\": \"Name Here\",\r\n \"status\": \"Uploading tiles complete\",\r\n \"pdfPath\": \"https://test.xyz/test.pdf\",\r\n \"max_zoom\": 15,\r\n \"min_zoom\": 9,\r\n \"png_path\": \"/final.png\",\r\n \"file_type\": \"pdf\",\r\n \"created_at\": \"2019-07-29T14:57:07.796Z\",\r\n \"updated_at\": \"2019-07-29T15:04:09.623Z\",\r\n \"image_width\": 2550,\r\n \"page_number\": null,\r\n \"geotiff_path\": \"/image_georef.tif\",\r\n \"image_height\": 3300,\r\n \"extent_max_lat\": \"34.1\",\r\n \"extent_max_lon\": \"-100.1\",\r\n \"extent_min_lat\": \"37.1\",\r\n \"extent_min_lon\": \"-115.1\",\r\n \"localTilesPath\": \"https://test.xyz/tiles/\",\r\n \"mapbox_tileset\": \"trailheadlabs.paper_map_548\",\r\n \"georefTilesPath\": \"https://test.xyz/tiles_georef\",\r\n \"geotiff_3857_path\": \"/image_georef_3857.tif\",\r\n \"temp_georefTilesPath\": null,\r\n \"ground_control_points\": \"[[1071.640625,2925.1640625,-122.104733996093,37.714753539402],[1355.44921875,2053.29296875,-122.09752430208,37.7391649876836],[1192.0390625,1299.8125,-122.105021746829,37.7592430319794],[669.765625,594.1796875,-122.124813348055,37.7770496273366]]\"\r\n }\r\n }\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n}\r\n```","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"Ah, ok, `status` is _also_ the name of the property of the dictionary, not just one of the things in the dictionary. \r\n\r\nOne thing it didn't occur to me to ask: Is your `Dictionary` initializer getting hit at all? I wonder if it may need to be constrained to the key and value types you're using","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"It is getting hit, and it's throwing when that same `status` property that holds the dictionary.","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"Here's a thought - have you got an extension that implements `JSONEncodable`? It looks like you're only implementing `JSONDecodable` above","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hmm, this is what I get when I start to implement `JSONEncodable`:\r\n\r\n\"Screen","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"Aha, [that is indeed implemented in the library](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/JSONStandardTypeConversions.swift#L114). \r\n\r\nOK, I'll mess around with this some to try and figure out what's going on here. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks for your help!","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"@nateirwin please try pulling the branch #1317 is opened from and seeing if that fixes your issue. You can put the `typealias` back to `[String: Any?]`. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yep, that fixes the issue!!!","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}},{"__typename":"IssueComment","body":"This has shipped with `0.30.0` - ready to go for SPM and Carthage, in the process of pushing to trunk on Cocoapods. 🎉","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"More generalized types","author":{"__typename":"User","login":"TimBroddin","id":"MDQ6VXNlcjUyODI4Nw==","name":"Tim Broddin"},"body":"Hi,\r\n\r\nI'm kinda new to Apollo iOS, so sorry if my question is kinda stupid. I'm passing a lot of data around in my (SwiftUI) app and the typing kinda drives me crazy. Right now I'm accepting arguments with types like `LetterPartsQuery.Data.ArtistsSplittedInLetterPart.Artist` & `HomePageQuery.Data.Post.Artist` and it's becoming harder and harder to manage this. \r\n\r\nWhat's the quickest way to having easier types to juggle arround (like just `Artist` in my example above).\r\n\r\nThanks a lot!","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I'm a firm believer in \"There's no such thing as a stupid question, only an asshole answer.\" 😇 That said, this is definitely NOT a stupid question. \r\n\r\nOne thing that helps explain the way we generate this code is that for each operation, we only want to make available those properties and types that you've actually requested, rather than all possible properties and types. This means we have some fairly nested structures like the ones you're seeing. \r\n\r\nOne work around for this is to use [GraphQL fragments](https://graphql.org/learn/queries/#fragments). Our codegen will take anyplace that uses a fragment and generate a fragment type that can be reused across multiple operations. \r\n\r\nThey're still more annoying to use than I'd like (this is something I'm working on in Swift Codegen, but that's slightly blocked at the moment), but they are at least the same reusable type. \r\n\r\nDoes that help? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks a lot! This will make my code readable again 😄 ","author":{"__typename":"User","login":"TimBroddin","id":"MDQ6VXNlcjUyODI4Nw==","name":"Tim Broddin"}}]}},{"__typename":"Issue","title":"Serialize or recreate mutation","author":{"__typename":"User","login":"pggawlowski","id":"MDQ6VXNlcjY0OTY2OTU2","name":null},"body":"What I am trying to achieve is mutation archivization. \r\nMy first try was NSKeyedArchiver.archivedData, however currently it is impossible. \r\nSo I decided to try to serialize and store jsonObject and/or variables and later, when back online, recreate mutation query.\r\n\r\n```\r\nlet object = mutation.variables?.jsonObject ?? [:]\r\ndo {\r\n let recreatedMutation = try TestMutation.Data(jsonObject: object, variables: nil)\r\n} catch {\r\n print(error)\r\n}\r\n```\r\n\r\nHowever it results in `Apollo.JSONDecodingError.missingValue`\r\n\r\nAny suggestions how to serialize and store mutations/queries or recreate them from stored data.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"It'd probably help for me to understand the use case - why do you need to persist the mutation itself?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"We have to deal with cache sync. So one concept is to introduce some kind of mutations persistency. Currently we are successfully mutating cache but we also have to push it away when connection is restored.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"I think I'm a bit confused - are you talking about persisting the **result** of a mutation, or the mutation itself? \r\n\r\nWhat I think is happening is that you're trying to persist the mutation itself so you can push changes you've made locally up to a server. Is that correct? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Exactly! :) ","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"So part of the problem is that you're trying to use the nested `TestMutation.Data` type - that type is used for recreating the **result** of the mutation, not the mutation itself. \r\n\r\nYou basically have to create the mutation the same way you would have if you weren't making it locally. So if your generated initializer is `TestMutation(parameter: String)`, then you want to persist the value of `parameter` and then send that mutation again. \r\n\r\nWhat you're trying to do is persist the variables JSON object, but there isn't an initializer for queries that takes that JSON object that you can pass what you're saving directly to. You could probably make a throwing initializer (in another file so it doesn't get overwritten by codegen) for the mutation that pulls that JSON back out, then tries to make the appropriate query from the JSON. \r\n\r\nYou'd have to have some notion of what query the JSON was for, though - it might be better to have some custom `Codable` types that can persist information about both the query type and the parameter values you need to persist. \r\n\r\nThere is definitely not a built-in way to do this, though. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@pgawlowski Anything else I can help with here? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"It's fine. Thank you very much! ","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"Cool - I'm going to close this issue out then. Thanks!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"How Can I set authorisation header for Apollo Client?","author":{"__typename":"User","login":"Prathap-iOS","id":"MDQ6VXNlcjU4Mzk2NTI2","name":"Prathap Reddy"},"body":"I am using Apollo Client. I got the access token after login. I have set the access token as authorisation header like this.\r\n\r\nfunc setApolloClient(accessToken: String) {\r\n self.apolloClient = {\r\n let authPayloads = [\"Authorization\": \"Bearer \\(accessToken)\"]\r\n let configuration = URLSessionConfiguration.default\r\n configuration.httpAdditionalHeaders = authPayloads\r\n configuration.requestCachePolicy = .reloadIgnoringLocalCacheData\r\n let endpointURL = URL(string: graphEndpoint)!\r\n return ApolloClient(networkTransport: HTTPNetworkTransport(url: endpointURL))\r\n }()\r\n }\r\n\r\nI am sending this authorisation header to a query to get the user details. It return success. But, I have no idea where it went wrong. I am not getting user details. I am getting Try again later. @designatednerd Is there any other way to set authorisation header?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I suspect \r\n\r\n```swift\r\nlet authPayloads = [\"Authorization\": \"Bearer (accessToken)\"]\r\n``` \r\n\r\nshould be \r\n\r\n```swift\r\nlet authPayloads = [\"Authorization\": \"Bearer \\(accessToken)\"]`\r\n```\r\n\r\nOtherwise you're sending the literal string `(accessToken)` as your access token rather than using string interpolation, which looks like what you want to do. \r\n\r\nIf that's not the issue, let me know and I can dig deeper - other than that your setup seems pretty straightforward. \r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd I used let authPayloads = [\"Authorization\": \"Bearer \\ (accessToken)\"]. But this one also not working.","author":{"__typename":"User","login":"Prathap-iOS","id":"MDQ6VXNlcjU4Mzk2NTI2","name":"Prathap Reddy"}},{"__typename":"IssueComment","body":"You still need the `\\` before the first paren in `(accessToken)`, otherwise it'll be sent as a string literal. \r\n\r\nAre you able to use a proxy tool like [Charles](https://www.charlesproxy.com/) or [MiTM Proxy](https://mitmproxy.org/) to see what the final headers going out over the network are? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yeah I used \\ before (accessToken). But There is no proper result. I am not using any proxies.","author":{"__typename":"User","login":"Prathap-iOS","id":"MDQ6VXNlcjU4Mzk2NTI2","name":"Prathap Reddy"}},{"__typename":"IssueComment","body":"I was asking if you could try using a proxy to see if you can see what the final headers are - that way you can see exactly what's going over the network. \r\n\r\nI would also double check with your backend that they take the token as a `Bearer` token - that's standard practice, but I've definitely seen a lot of backends that don't adhere to that.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd my backend team is following the same standard. They taken token as **Bearer** token.","author":{"__typename":"User","login":"Prathap-iOS","id":"MDQ6VXNlcjU4Mzk2NTI2","name":"Prathap Reddy"}},{"__typename":"IssueComment","body":"OK I was double checking what you're doing, and I missed the most obvious thing: The `URLSessionConfiguration` is not being passed into anything, so the configuration you're correctly setting up is not being given to anything to be used. Instead of this at the very end: \r\n\r\n```swift\r\nreturn ApolloClient(networkTransport: HTTPNetworkTransport(url: endpointURL))\r\n```\r\n\r\ntry this: \r\n\r\n```swift\r\nlet client = URLSessionClient(sessionConfiguration: configuration)\r\nreturn ApolloClient(networkTransport: HTTPNetworkTransport(url: endpointURL), client: client)\r\n```","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd Thanks. It's working fine. \r\n\r\nHere is my working code for setting up authorization header.\r\n\r\n`func getApolloClient(headerRequired:Bool = true) -> ApolloClient {\r\n let tokenValue = SessionManager.shared.getToken().TokenValue\r\n let authPayloads = [\"Authorization\": \"Bearer \\(tokenValue)\"]\r\n let configuration = URLSessionConfiguration.default\r\n configuration.httpAdditionalHeaders = authPayloads\r\n configuration.requestCachePolicy = .reloadIgnoringLocalCacheData\r\n let client = URLSessionClient(sessionConfiguration: configuration)\r\n let endpointURL = URL(string: graphEndpoint)!\r\n return ApolloClient(networkTransport: HTTPNetworkTransport(url: endpointURL, client: client))\r\n }`","author":{"__typename":"User","login":"Prathap-iOS","id":"MDQ6VXNlcjU4Mzk2NTI2","name":"Prathap Reddy"}},{"__typename":"IssueComment","body":"@Prathap-iOS great! Mind if we close this out?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Since @Prathap-iOS has noted that solution works, I'm going to go ahead and close this out. If you're having a similar problem, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"How to use the --passthrough-custom-scalar flag","author":{"__typename":"User","login":"ijl0322","id":"MDQ6VXNlcjE1OTAxNTMx","name":"Isabel Lee"},"body":"Hi, \r\n\r\nI'm trying to use the --passthrough-custom-scalar flag:\r\n\r\n`\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --passthrough-custom-scalar --localSchemaFile=\"schema.json\" API.swift`\r\n\r\nAnd getting this error `Error: Unexpected argument: API.swift`\r\n\r\nI'm using Apollo 0.29.1 and Xcode 11.5. Any help would be appreciated, Thanks!\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"It's `--passthroughCustomScalars`, Pascal case instead of kebab case and plural instead of singular. I think that may be causing the parsing to fail.\r\n\r\nIf fixing that doesn't fix it, I'd switch it to after `--localSchemaFile` - that might be looking for multiple arguments but I can't remember off the top of my head. \r\n\r\nLet me know which one (or both) works!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"The Pascal case works !! Thank you so much for your help! ","author":{"__typename":"User","login":"ijl0322","id":"MDQ6VXNlcjE1OTAxNTMx","name":"Isabel Lee"}}]}},{"__typename":"Issue","title":" Getting 'No operations found to generate` error when trying to use `ID` in query","author":{"__typename":"User","login":"dpatel-git","id":"MDQ6VXNlcjY4NDM2NTk1","name":null},"body":"I am working on an iOS application to communicate with our GraphQL backend using Apollo's GraphQL library. With the query below, I am able to generate Swift code that I can use to query backend.\r\n\r\n`query mobileApp {\r\n app(id: \"content/mobileApp\") {\r\n title\r\n } \r\n}`\r\n\r\nI am using the following commands to generate Swift code\r\n\r\n`../../Pods/Apollo/scripts/apollo/bin/run client:codegen --target=swift --includes ../app.graphql --localSchemaFile=./downloaded_schema.json API.swift`\r\n\r\nHowever, if I replace the string literal passed into the app(...) with ID like this\r\n\r\n`query mobileApp {\r\n app(id: ID!) {\r\n title\r\n } \r\n}`\r\n\r\nrunning the same codegen command fails with the following error.\r\n\r\n`Generating query files with 'swift' target\r\n → No operations or fragments found to generate code for.\r\nError: No operations or fragments found to generate code for.\r\n at write (~/Downloads/ios-app/Pods/Apollo/scripts/apollo/lib/commands/client/codegen.js:65:39)\r\n at Task.task (~/Downloads/ios-app/Pods/Apollo/scripts/apollo/lib/commands/client/codegen.js:90:46)`\r\n\r\nIt seems that the script is not able to find a declaration of ID. Hoping that someone can point me in the right direction, thanks","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I'm not sure why it's saying there are no operations rather than there's an error in your declaration, but there's an error in your declaration. \r\n\r\nTo pass in a parameter, you need to declare that parameter in the query's declaration, then pass it into the query itself: \r\n\r\n```graphql\r\nquery mobileApp($id: ID!) { \r\n app(id: $id) {\r\n title\r\n }\r\n}\r\n```\r\n\r\nHope that gets you going!\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I think codegen script could be defaulting to `No Operations ...` error if it's able to come to a conclusion. \r\n\r\nAnyways, making the changes you suggested fixed the error.\r\n\r\nSuper thanks.","author":{"__typename":"User","login":"dpatel-git","id":"MDQ6VXNlcjY4NDM2NTk1","name":null}}]}},{"__typename":"Issue","title":"Fragments imported into multiple graphql queries","author":{"__typename":"User","login":"piv199","id":"MDQ6VXNlcjgyOTMxOTE=","name":"Olexii Pyvovarov"},"body":"Hi, quite new to graphql and trying to establish best practices in the project.\r\n\r\nHave found an article about fragments: https://www.apollographql.com/docs/ios/fragments/\r\n\r\nI wonder whether there is an ability to import Fragment.graphql (which defines fragment only) into another graphql file with query that uses that fragment?\r\n\r\n```\r\nFragment.graphql\r\nfragment A { }\r\n```\r\n\r\n```\r\nQuery.grapqhl\r\nquery {\r\n property {\r\n ...A\r\n }\r\n}\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Yep, as long as they're in the same module you should be able to do that!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"(you won't need to import fragment.graphql, the codegen should be able to see all fragments defined in the module)","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd Thanks! Sorry for opening the issue... I did all right but the problem was in fragment naming - it was the same as model entity thus I had segmentation fault and not found errors... Thanks for help!\r\n","author":{"__typename":"User","login":"piv199","id":"MDQ6VXNlcjgyOTMxOTE=","name":"Olexii Pyvovarov"}}]}},{"__typename":"Issue","title":"Keys with nil values are removed","author":{"__typename":"User","login":"docallag","id":"MDQ6VXNlcjM1MzIzMQ==","name":"David O'Callaghan"},"body":"Hi,\r\nI'm just wondering why keys with nil values are removed on queries/mutations? \r\n\r\nSpecifically the **withNilValuesRemoved** extension method in **GraphQLInputValue.swift**\r\n\r\nThanks,\r\nDave","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Good question! So you can see a little bit of why in [this test](https://github.com/apollographql/apollo-ios/blob/main/Tests/ApolloTests/InputValueEncodingTests.swift#L74) and [this test](https://github.com/apollographql/apollo-ios/blob/main/Tests/ApolloTests/InputValueEncodingTests.swift#L80). \r\n\r\nFor input values, passing `nil` and passing `.some(nil)` have different meanings. Passing `nil` means \"I am not providing a value here.\" Passing `.some(nil)` means \"I am providing a value, and it is explicitly nil.\" The `nil`s are filtered out, the `.some(nil)`s are not.\r\n\r\nThis has effects on the server side: If you send `null` to the server, it will overwrite whatever was already in your server-side database with `null`. If you don't send anything to the server, anything which was already there and isn't explicitly being changed will remain untouched. \r\n\r\nIn the swift Codegen stuff I'm working on there's going to be a [`GraphQLOptional`](https://github.com/apollographql/apollo-ios/blob/main/Sources/ApolloCore/GraphQLOptional.swift#L3) type that should capture this a bit more clearly than the current codegen, but unfortunately that's still a ways out (😭). \r\n\r\nDoes that make more sense? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Oh that's perfect! I can use `.some(nil)` to stop it being filtered out.\r\n\r\nThanks so much for the quick reply 🤩","author":{"__typename":"User","login":"docallag","id":"MDQ6VXNlcjM1MzIzMQ==","name":"David O'Callaghan"}}]}},{"__typename":"Issue","title":"Does every table need an \"id\" or \"","author":{"__typename":"User","login":"joshuarobs","id":"MDQ6VXNlcjUyOTQ2ODgx","name":null},"body":"","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"(closing this in favor of #1326)","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Does every table need an \"id\" or \"_id\" field for its data to be cached properly?","author":{"__typename":"User","login":"joshuarobs","id":"MDQ6VXNlcjUyOTQ2ODgx","name":null},"body":"According to Apollo Client React here: https://www.apollographql.com/docs/react/caching/cache-configuration/#generating-unique-identifiers the way data is identified and if any changes have been made is as described:\r\n\r\n````\r\nTo do so, it combines the object's __typename with its id or _id field (whichever is defined).\r\nThese two values are separated by a colon (:).\r\n````\r\n\r\nThere seems to be an option for React where a different field other than `id` can be used, especially if there is another field set as the primary key on the db.\r\n\r\nIs there a way to do this for Apollo iOS? If not, does that mean we have to make all tables in our database have some sort of `id` or `_id` field?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! This is handled rather differently on iOS at the moment. Here's [a detailed doc about our caching on iOS](https://www.apollographql.com/docs/ios/caching/). \r\n\r\nThe short answer of how to set a custom key is to take a look at the [Controlling Normalization section](https://www.apollographql.com/docs/ios/caching/#controlling-normalization), where you can find information about the `cacheKeyForObject` function you can use to set custom cache keys on iOS. \r\n\r\nDoes that answer your question? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yes it does, thanks!","author":{"__typename":"User","login":"joshuarobs","id":"MDQ6VXNlcjUyOTQ2ODgx","name":null}},{"__typename":"IssueComment","body":"@designatednerd Also, forgot to ask one more quick question: is `cacheKeyForObject` set only once throughout the whole Apollo object? That is, if we set it to `id`, does that mean every table that ever gets queried needs to have an `id` field? What about if we have most tables with a unique `id` but some tables don't have it and use other primary keys?","author":{"__typename":"User","login":"joshuarobs","id":"MDQ6VXNlcjUyOTQ2ODgx","name":null}},{"__typename":"IssueComment","body":"There is only one closure per store (set through the client), but you can do some stuff by extracting the value of `__typename` from the JSON you get in order to have it work differently for different things. \r\n\r\nYou also can just return `nil` if `id` is nil, and a default cache key based on the path of the request will be generated. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Inline GQL","author":{"__typename":"User","login":"ericlewis","id":"MDQ6VXNlcjY3NDUwMw==","name":"Eric Lewis"},"body":"This might be old hat and I know it’s not a great issue but need to write down somewhere:\r\n\r\nYou should be able to describe fragments or query’s with inline strings as opposed to colocating with graphql files. \r\n\r\nIt probs seems minor but from a DX perspective the whole co-locating things a big deal. \r\n\r\nCreating more folder structure to organize is less good than just having the query in a used component. This is probably more true of SwiftUI than anything, and I have some SwiftUI stuff to contribute if folks want it. ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! There's definitely some significant obstacles to this at the moment, particularly around how things are ingested for code generation. Right now, we only ingest from `.graphql` files rather than from any arbitrary file, and without having to worry about what is a Swift `String` that contains a GraphQL query or anything like that. \r\n\r\nThis is definitely an enhancement to consider for the long term, but I'll be honest, we've got way bigger problems to solve first. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"don't see this happening to be fair, more likely would be some kind of DSL","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"Thats' an interesting idea - I think the main issues I see with it are a) How would we ensure that queries are valid? and b) How would we generate the classes necessary for parsing the result? \r\n\r\nDefinitely going to think on that when I get back to this issue though. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Swift scripting codegen error: \"Error: Cannot find module './errors/pretty-print'\"","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"},"body":"macOS 10.15.6\r\nXcode 11.6\r\n\r\nWe're using Swift scripting for Codegen in our project. It was working fine until recently. The only change that occurred (that I can think of) is macOS and Xcode updated. I'm getting the following error:\r\n\r\n```\r\n[DEBUG - ApolloCodegenLib:CLIDownloader.swift:43] - Zip file with the CLI is already downloaded!\r\nSHASUM of downloaded file: c2b1215eb8e82ec9d777f4b1590ed0f60960a23badadd889e4d129eb08866f14\r\n[DEBUG - ApolloCodegenLib:CLIExtractor.swift:57] - Binary already extracted!\r\n[ERROR - ApolloCodegenLib:Basher.swift:62] - internal/modules/cjs/loader.js:638\r\n throw err;\r\n ^\r\n\r\nError: Cannot find module './errors/pretty-print'\r\n at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)\r\n at Function.Module._load (internal/modules/cjs/loader.js:562:25)\r\n at Module.require (internal/modules/cjs/loader.js:692:17)\r\n at require (internal/modules/cjs/helpers.js:25:18)\r\n at Object. (/Users/nateirwin/Development/trailheadlabs/outerspatial-ios/Codegen/ApolloCLI/apollo/node_modules/@oclif/errors/lib/handle.js:6:24)\r\n at Module._compile (internal/modules/cjs/loader.js:778:30)\r\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)\r\n at Module.load (internal/modules/cjs/loader.js:653:32)\r\n at tryModuleLoad (internal/modules/cjs/loader.js:593:12)\r\n at Function.Module._load (internal/modules/cjs/loader.js:585:3)\r\n\r\nProgram ended with exit code: 1\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"That's very odd, that shouldn't have changed anything in the path - I did not have any migration issues when I migrated my machine to those versions. \r\n\r\nWhat I'd suggest is deleting the extracted files from the `tar.gz` file and letting it re-extract. I have no idea what could have changed in there, but re-extracting from the zip file is a good way to make sure you've got everything. Let me know if this works.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"That worked, thanks!","author":{"__typename":"User","login":"nateirwin","id":"MDQ6VXNlcjEwNDQz","name":"Nate Irwin"}}]}},{"__typename":"Issue","title":"Apollo 0.29.0 - 0.30.0 failed to build in Travis","author":{"__typename":"User","login":"hendyevan","id":"MDQ6VXNlcjk4Mjk3Mg==","name":"Hendy Evan"},"body":"Hi, i have an issue in Travis when build my apps using apollo.\r\n\"Screen\r\nIt's said there is no module `ApolloCore`, but when i run in xcode and archive it using xcode, it went well. No issue arises when using Xcode.\r\n\r\nI tried to downgrade to version `0.28.0` and it works well in Travis. No error occured.\r\nIs there any configuration for Travis to build `Apollo` pod?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! I'm not sure what your build looks like in Travis, but the issue is around a macro that's used by CocoaPods. CocoaPods pulls every sub-spec into a single big library, so we had to add [this macro](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/Bundle%2BHelpers.swift#L2) to tell the compiler not to try to import the `ApolloCore` module when using CocoaPods. It sounds like that macro is getting properly populated when you build/archive locally. \r\n\r\nWhat's the command you're using to build on Travis? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"This is command from my Travis :\r\n\r\n```\r\nlanguage: swift\r\nosx_image: xcode11.5\r\nxcode_project: Project.xcworkspace\r\n\r\ncache:\r\n - bundler\r\n - cocoapods\r\n\r\nbefore_install:\r\n - gem install bundler\r\n - bundle install\r\n - pod install\r\n\r\njobs:\r\n allow_failures:\r\n - env: code-coverage\r\n include:\r\n - stage: deploy\r\n before_script: curl -sL firebase.tools | upgrade=true bash\r\n script: bundle exec fastlane deploy\r\n after_success: bundle exec fastlane archive\r\n```\r\n\r\nAnd for my fastlane I'm using `Gym` :\r\n```\r\nprivate_lane :ios_build do |options|\r\n scheme = options[:scheme]\r\n export_method = options[:export_method]\r\n output_name = options[:output_name]\r\n key_name = options[:development]\r\n\r\n gym(\r\n workspace: \"Project.xcworkspace\",\r\n scheme: scheme,\r\n configuration: scheme,\r\n silent: true,\r\n clean: true,\r\n suppress_xcode_output: false,\r\n export_method: export_method,\r\n output_name: output_name,\r\n xcargs: \"ARCHIVE=YES\",\r\n skip_profile_detection: true,\r\n codesigning_identity: key_name,\r\n analyze_build_time: true\r\n )\r\n end\r\n```","author":{"__typename":"User","login":"hendyevan","id":"MDQ6VXNlcjk4Mjk3Mg==","name":"Hendy Evan"}},{"__typename":"IssueComment","body":"I would maybe look at adding `COCOAPODS=YES` to your `xcargs` via `gym` if nothing else works - i would also check that the configuration that you're passing in to `gym` has that variable set. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I've add `COCOAPOD=YES` to `gym` and it's still fail to build in Travis.\r\n```\r\ngym(\r\n workspace: \"Project.xcworkspace\",\r\n scheme: scheme,\r\n configuration: scheme,\r\n silent: true,\r\n clean: true,\r\n suppress_xcode_output: false,\r\n export_method: export_method,\r\n output_name: output_name,\r\n xcargs: \"ARCHIVE=YES COCOAPODS=YES\",\r\n skip_profile_detection: true,\r\n codesigning_identity: key_name,\r\n analyze_build_time: true\r\n )\r\n```\r\n\r\n","author":{"__typename":"User","login":"hendyevan","id":"MDQ6VXNlcjk4Mjk3Mg==","name":"Hendy Evan"}},{"__typename":"IssueComment","body":"IIRC it needs a comma and not a space - what about looking at the configuration you're using - does that have `COCOAPODS=YES` (or 1) set up? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Already add comma in gym `xcargs: \"ARCHIVE=YES, COCOAPODS=YES\"` and in my configuration there is already an argument `COCOAPODS=1`. But it's still give me the same error in travis.\r\n\"Screen\r\n","author":{"__typename":"User","login":"hendyevan","id":"MDQ6VXNlcjk4Mjk3Mg==","name":"Hendy Evan"}},{"__typename":"IssueComment","body":"It looks like in the Release scheme there's a space before `COCOAPODS=1` - what happens if you delete that space?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi, we already add several condition in `xcargs` regarding this issue using `COCOAPODS=0`, `COCOAPODS=1` and `COCOAPODS=YES`. but still no luck. any clue @designatednerd ?","author":{"__typename":"User","login":"budioktaviyan","id":"MDQ6VXNlcjIwMzE0OTM=","name":"Budi Oktaviyan"}},{"__typename":"IssueComment","body":"> It looks like in the Release scheme there's a space before `COCOAPODS=1` - what happens if you delete that space?\r\n\r\nThat's not a space, maybe because it's have another config in first line so it's appear like a space.\r\n\"Screen\r\nAnyway for travis build, we use schema `alpha & beta`. And still no luck ","author":{"__typename":"User","login":"hendyevan","id":"MDQ6VXNlcjk4Mjk3Mg==","name":"Hendy Evan"}},{"__typename":"IssueComment","body":"Hmmm...I wonder if there's an issue because `$(inherited)` is in there twice. \r\n\r\nHonestly, I'm not sure what to tell you - it's clear that the `#if !COCOAPODS` compile gate isn't working on Travis, but I'm really not sure why. \r\n\r\nIf you run the fastlane script locally, do you see the same errors? That could start to point you in the right direction. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@budioktaviyan @hendyevan Were y'all ever able to figure out what was going on here, or at least get the fastlane script to run locally? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi @designatednerd , I ever run it locally using `fastlane` and got same issue. So basically, we use `gym` action on fastlane to bundle our app. Apart from that, we also trying to build + archive using xcode, and it works!\r\n\r\nIDK why, is it a `fastlane` problem or something else ?","author":{"__typename":"User","login":"budioktaviyan","id":"MDQ6VXNlcjIwMzE0OTM=","name":"Budi Oktaviyan"}},{"__typename":"IssueComment","body":"That indicates there's likely some kind of configuration issue that's being hit by fastlane - the good news is it's a lot easier to debug that when it can be reproduced locally. I would try using some of the tips from [Fastlane's troubleshooting guide](https://docs.fastlane.tools/codesigning/troubleshooting/), particularly the use of the `--verbose` flag that might give you a better indicator of what's going wrong. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@hendyevan Were you able to get the verbose output and see what might be happening? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi @designatednerd, so the issue actually come from fastlane ? What did you expect from `verbose` build ? did you have any clue ?","author":{"__typename":"User","login":"budioktaviyan","id":"MDQ6VXNlcjIwMzE0OTM=","name":"Budi Oktaviyan"}},{"__typename":"IssueComment","body":"Hi, sorry, I was on vacation last week!\r\n\r\nIt seems like Fastlane is using a build configuration that isn't picking up the `COCOAPODS` setting, I was hoping that the `verbose` build would give you more information about what configuration you're using and what settings are set in that configuration. That might help you figure out more info about what you need to pass into Fastlane to get it to use a build configuration that _does_ use the `COCOAPODS` setting. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Were you ever able to figure out what was happening? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi @designatednerd , sorry for slow response. We are still in the middle of project and the deadline is very tight. We will inform you later as soon as possible after we try it in local and using `verbose` as you suggest.","author":{"__typename":"User","login":"hendyevan","id":"MDQ6VXNlcjk4Mjk3Mg==","name":"Hendy Evan"}},{"__typename":"IssueComment","body":"Hi @designatednerd,\r\n\r\nSorry for late response. So, we're just running like this ?\r\n```bundle exec fastlane lane --verbose```\r\n\r\nisn't it ?","author":{"__typename":"User","login":"budioktaviyan","id":"MDQ6VXNlcjIwMzE0OTM=","name":"Budi Oktaviyan"}},{"__typename":"IssueComment","body":"I believe so - there's instructions in the troubleshooting guide I linked earlier that are going to be more accurate than anything I can give you. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hey all - I'm going to close this out since I haven't heard back in a few weeks. My best recommendation would be to get things building locally with Fastlane since you can get feedback much more easily than you can from Travis itself. I've generally found in the past that once something is building locally with Fastlane, it's much more likely to succeed on any CI platform if you're building using fastlane on that platform. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Adjusting the reconnection behaviour of `WebSocketTransport`","author":{"__typename":"User","login":"ketenshi","id":"MDQ6VXNlcjY4MDY2OTc=","name":"Eugene Kwong"},"body":"Hello!\r\n\r\nI have a similar setup to https://github.com/apollographql/apollo-ios/pull/1224 but with the caveat of requiring the user to login again in some cases. With an invalid `connectingPayload` the server closes the connection immediately, and `WebSocketTransport` will keep retrying. The `connectingPayload` can be updated with the new authentication token after the user logs in again.\r\n\r\nI would like to add in the ability to either prevent `WebSocketTransport` from reconnecting or be able to pause the websocket. \r\n\r\nIf we go the route of adjusting the reconnection behaviour I was thinking of adding something similar to `HTTPNetworkTransportRetryDelegate` but that kind of goes against the idea of passing `reconnect` as part of the initialization. So maybe having a getter/setter might be best.\r\n\r\nHope that I can get some guidance/feedback on this. Thanks!","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Does `closeConnection` on `WebSocketTransport` do what you need it to? That explicitly sets `reconnect.value` to false. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'd like to keep existing `subscriptions` so unfortunately `closeConnection` isn't viable.","author":{"__typename":"User","login":"ketenshi","id":"MDQ6VXNlcjY4MDY2OTc=","name":"Eugene Kwong"}},{"__typename":"IssueComment","body":"So you're thinking more like this: \r\n\r\n```swift\r\n public func pauseWebSocketConnection() {\r\n self.reconnect.value = false\r\n self.websocket.disconnect()\r\n }\r\n \r\n public func resumeWebSocketConnection(autoReconnect: Bool = true) {\r\n self.reconnect.value = autoReconnect\r\n self.websocket.connect()\r\n }\r\n```\r\n\r\nI think that could work with a sufficient documentation warning that if you call `pause` you have to manually call `resume`. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yes that's essentially what I want. Thanks for the suggestion, I'll have something in the next few days.","author":{"__typename":"User","login":"ketenshi","id":"MDQ6VXNlcjY4MDY2OTc=","name":"Eugene Kwong"}},{"__typename":"IssueComment","body":"Eh, if that's all you need i'll just do it and throw in a test 😇","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Ok, thank you so much!","author":{"__typename":"User","login":"ketenshi","id":"MDQ6VXNlcjY4MDY2OTc=","name":"Eugene Kwong"}},{"__typename":"IssueComment","body":"> 好的,非常感谢你!\r\n\r\n你好 我想问下 如果 在 APP 进入后台时,手动断开长连接. APP 重新唤起时连接长连接呢","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null}},{"__typename":"IssueComment","body":"This has shipped with `0.31.0`. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Apollo Codegen generates different Operation IDs than Apollo Server","author":{"__typename":"User","login":"Nickersoft","id":"MDQ6VXNlcjIxMDQxMjk=","name":"Tyler Nickerson"},"body":"Hey all,\r\n\r\nTonight I noticed that the operation ID Apollo Codegen creates when generating Swift code for your schema is slightly different than what the Apollo Server expects, causing APQs to fail and throw a `provided sha does not match query` error. \r\n\r\nBasically the SHA that Apollo Codegen creates adds line breaks between each GraphQL operation before it calculates the SHA of the string (seen [here](https://github.com/apollographql/apollo-tooling/blob/8e78c50a21c17a071f7b6890de446b4582e8d04a/packages/apollo-codegen-core/src/compiler/visitors/generateOperationId.ts#L26)). However, when Apollo iOS sends queries to the server, it does so without any line breaks using Swift's `.appending()` method. Then when the server calculates the SHA, due to the lack of line breaks, the operation ID is different and the error is thrown. Strangely enough, however, I noticed the StarWars API actually [manually adds line breaks](https://github.com/apollographql/apollo-ios/blob/06c357b7e98fb7abcddc02ca8aeb96cc8475d263/Sources/StarWarsAPI/API.swift#L1051) in its generated code, which mine doesn't. \r\n\r\nI believe I'm using the latest version of Apollo Codegen and Apollo iOS. I'm happy to patch a fix – it's just a matter of what needs to be changed. I'm afraid touching `apollo-tooling` would affect more repos that might depend on it, so I thought it'd be safer to open an issue here and propose adding the line breaks to the generated Swift.\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Closing, as it looks like the `apollo-tooling` upstream does add a line break during Swift Codegen, but the CLI on my system may be out of date. Will reopen if cannot find a resolution.","author":{"__typename":"User","login":"Nickersoft","id":"MDQ6VXNlcjIxMDQxMjk=","name":"Tyler Nickerson"}},{"__typename":"IssueComment","body":"@Nickersoft I would strongly recommend using the version the SDK downloads - it's set up to make sure you don't have to fight with node and mess with \"which version of the CLI works with which version of the SDK?\". You can check out the most recent version of our [installation docs](https://www.apollographql.com/docs/ios/installation/) or our new [Swift scripting docs](https://www.apollographql.com/docs/ios/swift-scripting/) to see how to set this up. \r\n\r\nI'd also recommend using version `0.29.x` of the iOS SDK - this includes some fixes that ensure the hash that you get from your iOS operation matches what's generated by the CLI, even with Fragments.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd Hey, thanks for the comment despite me opening an issue a little prematurely haha – I didn't realize the Apollo version set in the Codegen `Package.swift` affects the version of the CLI it downloads, and sure enough, I was on 0.28.x when the newline fix was pushed on 0.30.x. Updating it to download the new CLI fixed the problem :) ","author":{"__typename":"User","login":"Nickersoft","id":"MDQ6VXNlcjIxMDQxMjk=","name":"Tyler Nickerson"}},{"__typename":"IssueComment","body":"Yeah you bet - thought it would be helpful for anyone who stumbles across this via google :P","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Cache: Transaction write object results in no change.","author":{"__typename":"User","login":"pggawlowski","id":"MDQ6VXNlcjY0OTY2OTU2","name":null},"body":"```\r\n do {\r\n var response = try transaction.readObject(ofType: Package.self, withKey: packageId)\r\n response.status = entry.status\r\n \r\n try transaction.write(object: response, withKey: packageId) \r\n let confirmChange = try transaction.readObject(ofType: Package.self, withKey: packageId)\r\n print(confirmChange)\r\n } catch {\r\n print(error)\r\n }\r\n\r\n```\r\n\r\nI digged down until ApolloStore -> `func mergePromise(records: RecordSet)`.\r\nResult is giving me succes `fulfill(cacheKey)` with cacheKey \"123.status\" which is correct packageId and correct field I was trying to manipulate. \r\n\r\nHowever confirmChange object has unchanged status. My `cacheKeyForObject` for both store and client are set. \r\nIs it sth I am doing wrong or writeObject is not working the way I think?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"The issue is that the transactions aren't guaranteed to be synchronous, so `transaction.write` may not have finished before `transaction.read` is called. \r\n\r\nYou'd need to use [`withinWriteTransaction`](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/ApolloStore.swift#L149) in order to validate the change. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Actual problem was: invalid cacheKeys. Sorry for wasting Tour time.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"No worries - thanks for following up with what actually happened! I'm gonna go ahead and close this issue out. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"长连接手动断开和重连","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null},"body":"你好\r\n如何在 APP 进入后台时,手动断开长连接,从新打卡 APP 时再重新连接长连接?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Via Google Translate since I don't speak Chinese: \r\n\r\n> Hello there\r\n> How to manually disconnect the long connection when the APP enters the background, and then reconnect the long connection when the APP is newly clocked in?\r\n\r\nAre you asking about subscriptions or some other kind of long connection? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"你好.订阅消息. WebSocketTransport\r\n\"WeChat67a3558698ad0ab1125ec3110a335a58\"\r\n如果使用方法.我想在 APP 进入后台时,断开.在 APP重新打开的时候重新连接?\r\n初学者请多见谅!\r\n","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null}},{"__typename":"IssueComment","body":"> Hello. Subscribe to news. WebSocketTransport\r\n\r\n[Here's Apple's documentation on handling lifecycle changes](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle) - The short answer is that you will probably want to call `closeConnection` on the `webSocketTransport` in your App Delegate's `applicationWillResignActive` method and restart the susbcription in `applicationDidBecomeActive`. \r\n\r\nNote that names are different in the Scene delegate if you're using that, but I don't think you are since you're using a singleton rather than per-scene instances of `Network`. \r\n\r\nLet me know if that helps!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"是的,这个地方使用的是单例.多个订阅消息在这里接受,然后进行分发处理.\r\n需要在 UIApplicationWillResignActiveNotification 时,断开订阅连接\r\n UIApplicationDidBecomeActiveNotification 重新连接订阅\r\n\r\n是通过 self.webSocketTransport.closeConnection() 断开订阅么","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null}},{"__typename":"IssueComment","body":"你好.我通过 调用 self.webSocketTransport.closeConnection() ,已经可以断开连接了. 在 UIApplicationDidBecomeActiveNotification 的时候怎么重新建立连接呢?\r\n![image](https://user-images.githubusercontent.com/10558372/89000672-86b02780-d32a-11ea-8df8-59fee24addf6.png)\r\n","author":{"__typename":"User","login":"tanchendong1992","id":"MDQ6VXNlcjEwNTU4Mzcy","name":null}},{"__typename":"IssueComment","body":"Google translated: \r\n\r\n> Hello. I can disconnect by calling self.webSocketTransport.closeConnection(). How to re-establish the connection when UIApplicationDidBecomeActiveNotification?\r\n\r\nAh, because `addSubscribe` won't work if the web socket isn't connected, and right now there's not a way to tell the websocket to reconnect non-automatically. \r\n\r\nThe good news is #1335 will add the ability to reconnect more easily. Until then you'll probably need to hack it by using either `updateHeaderValues` or `updateConnectingPayload` to force a reconnection. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"#1335 is merged to `main` if you want to use it immediately, it'll come out probably sometime later this week in an official release. I'm going to close this out. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"RFC: Networking Updates","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"},"body":"This is the technical outline of a proposal to make major changes to our primary networking interface from the current `HTTPNetworkTransport` to a `RequestChainNetworkTransport` which uses a chain of interceptor objects to set up and process the results of network requests.\r\n\r\nNote that this is going to be a **🎉 Spectacularly 🎉** breaking change - while very surface level APIs will remain basically the same, if you're doing anything remotely advanced, this will necessitate some changes, but the idea is to break it now so we don't have to break it way worse later.\r\n\r\nI would **REALLY** love feedback on this before I start working towards making this the default option. You can see the code changes in-place in [this PR](https://github.com/apollographql/apollo-ios/pull/1341). I will be updating this RFC with feedback as it is received. \r\n\r\n## Why The Change?\r\n\r\n`HTTPNetworkTransport` allows you to hook into various delegates to accomplish various things. There are several limitations to this approach: \r\n\r\n- Users can only do things that are specifically supported by delegates.\r\n- Asynchronous use of delegates without callbacks is basically impossible.\r\n- Any time we want to add a new feature, we need to add a new delegate method and handle it, creating additional complexity.\r\n- There is no flexibility in terms of order of operations, particularly around whether data should be returned to the UI before being written to the cache.\r\n\r\nThe other major issue driving this update is that the current networking stack is *deeply* tied to the current cache architecture. This isn't ideal for many reasons, the biggest of which is that the cache likely to change in relation to the [Swift Codegen Rewrite](https://github.com/apollographql/apollo-ios/issues/939). \r\n\r\n## What is proposed? \r\n\r\nThe proposed new architecture uses the Interceptor pattern to create a customizable request chain. This means users can hook into the system at any point during the request creation or data processing process. \r\n\r\nThis also means that the pieces which will need to be swapped out for the Swift Codegen Rewrite are more clearly defined, and less tied to the actual parsing operation. \r\n\r\nFinally, this also opens the opportunity for different patterns than we already support, such as writing to the cache *after* returning data to the UI instead of before, or creating an array of interceptors which hit the network first, then hit the cache if nothing was returned. \r\n\r\n### New Protocols\r\n\r\n- **`FlexibleDecoder`**: This is mostly going to be helpful for the `Codable` implementation down the line, but this will allow anything conforming to `Decoder` to be used to decode data.\r\n- **`Parseable`**: This is a wrapper that allows us to continue to support non-`Codable` parsing alongside `Codable` parsing, while keeping us able to constrain and construct things generically. A default implementation for `Codable` will be provided.\r\n- **`ApolloInterceptor`**: This is an interface which allows you to add an asynchronous handler to perform any necessary work, such as fetching credentials and reading or writing from the cache, asynchronously. \r\n \r\n ```swift\r\n public protocol ApolloInterceptor: class {\r\n \r\n /// Called when this interceptor should do its work.\r\n ///\r\n /// - Parameters:\r\n /// - chain: The chain the interceptor is a part of.\r\n /// - request: The request, as far as it has been constructed\r\n /// - response: [optional] The response, if received\r\n /// - completion: The completion block to fire when data needs to be returned to the UI.\r\n func interceptAsync(\r\n chain: RequestChain,\r\n request: HTTPRequest,\r\n response: HTTPResponse?,\r\n completion: @escaping (Result, Error>) -> Void)\r\n }\r\n ```\r\n \r\n Default implementations of `ApolloInterceptor` for both Legacy (ie, non Swift Codegen) networking and Swift Codegen networking will be provided.\r\n- **`InterceptorProvider`** This protocol will be used to quickly create a new array of interceptors for a given request:\r\n\r\n ```swift\r\n public protocol InterceptorProvider {\r\n \r\n /// Creates a new array of interceptors when called\r\n ///\r\n /// - Parameter operation: The operation to provide interceptors for\r\n func interceptors(for operation: Operation) -> [ApolloInterceptor]\r\n }\r\n ```\r\n This design allows for both flexibility (you can return different interceptors for different types of requests, for instance) and isolation (each request will have its own unique set of interceptors, reducing the possibility of different requests stomping on each other). \r\n \r\n Two default interceptor providers are set up: \r\n - **`LegacyInterceptorProvider`** will provide interceptors mimicking the current stack \r\n - **`CodableInterceptorProvider`** will provide interceptors for the forthcoming Swift Codegen Rewrite's network stack. \r\n- **`ApolloErrorInterceptor`** will allow you to have additional checks whenever an error is about to be returned. This will be optional to implement, and no default implementation is provided.\r\n\r\n ```swift\r\n /// Asynchronously handles the receipt of an error at any point in the chain.\r\n ///\r\n /// - Parameters:\r\n /// - error: The received error\r\n /// - chain: The chain the error was received on\r\n /// - request: The request, as far as it was constructed\r\n /// - response: [optional] The response, if received\r\n /// - completion: The completion closure to fire when the operation has completed. Note that if you call `retry` on the chain, you will not want to call the completion block in this method.\r\n func handleErrorAsync(\r\n error: Error,\r\n chain: RequestChain,\r\n request: HTTPRequest,\r\n response: HTTPResponse?,\r\n completion: @escaping (Result, Error>) -> Void)\r\n ```\r\n \r\n### New Classes\r\n\r\n- **`HTTPRequest`** This object will hold all the information related to a request before it hits the network, with the `toURLRequest()` method creating an actual `URLRequest` based on all the information in the request. This is subclass-able (and will mostly be using subclasses). \r\n\r\n ```swift\r\n open class HTTPRequest {\r\n\r\n open var graphQLEndpoint: URL\r\n open var operation: Operation\r\n open var contentType: String\r\n open var additionalHeaders: [String: String]\r\n open var clientName: String? = nil\r\n open var clientVersion: String? = nil\r\n open var retryCount: Int = 0\r\n public let cachePolicy: CachePolicy\r\n\r\n public init(graphQLEndpoint: URL,\r\n operation: Operation,\r\n contentType: String,\r\n additionalHeaders: [String: String],\r\n cachePolicy: CachePolicy = .default)\r\n \r\n open func toURLRequest() throws -> URLRequest\r\n\r\n open func addHeader(name: String, value: String)\r\n }\r\n ```\r\n \r\n - **`JSONRequest`** subclass of `HTTPRequest` will handle creating requests with JSON, which will be the vast majority of requests with operations. This is where handling of auto-persisted queries is also layered in: \r\n\r\n ```swift\r\n public class JSONRequest: HTTPRequest {\r\n \r\n public let requestCreator: RequestCreator\r\n \r\n public let autoPersistQueries: Bool\r\n public let useGETForQueries: Bool\r\n public let useGETForPersistedQueryRetry: Bool\r\n public var isPersistedQueryRetry = false\r\n \r\n public let serializationFormat = JSONSerializationFormat.self\r\n\r\n public init(operation: Operation,\r\n graphQLEndpoint: URL,\r\n additionalHeaders: [String: String] = [:],\r\n cachePolicy: CachePolicy = .default,\r\n autoPersistQueries: Bool = false,\r\n useGETForQueries: Bool = false,\r\n useGETForPersistedQueryRetry: Bool = false,\r\n requestCreator: RequestCreator = ApolloRequestCreator())\r\n }\r\n ```\r\n \r\n - **`UploadRequest`** subclass of `HTTPRequest` will handle multipart file uploads:\r\n\r\n ```swift\r\n public class UploadRequest: HTTPRequest {\r\n \r\n public let requestCreator: RequestCreator\r\n public let files: [GraphQLFile]\r\n public let manualBoundary: String? \r\n public let serializationFormat = JSONSerializationFormat.self\r\n \r\n public init(graphQLEndpoint: URL,\r\n operation: Operation,\r\n additionalHeaders: [String: String] = [:],\r\n files: [GraphQLFile],\r\n manualBoundary: String? = nil,\r\n requestCreator: RequestCreator = ApolloRequestCreator()) \r\n }\r\n ```\r\n\r\n- **`HTTPResponse`** will represent the objects returned and/or parsed from the server:\r\n\r\n ```swift\r\n /// Designated initializer\r\n ///\r\n /// - Parameters:\r\n /// - response: The `HTTPURLResponse` received from the server.\r\n /// - rawData: The raw, unparsed data received from the server.\r\n /// - parsedResponse: [optional] The response parsed into the `ParsedValue` type. Will be nil if not yet parsed, or if parsing failed.\r\n public class HTTPResponse {\r\n public var httpResponse: HTTPURLResponse\r\n public var rawData: Data\r\n public var parsedResponse: GraphQLResult?\r\n }\r\n ```\r\n\r\n- **‌`RequestChain`** will handle the interaction with the network for a single operation. \r\n\r\n ```swift\r\n public class RequestChain: Cancellable {\r\n\r\n /// Creates a chain with the given interceptor array\r\n public init(interceptors: [ApolloInterceptor])\r\n \r\n /// Kicks off the request from the beginning of the interceptor array.\r\n ///\r\n /// - Parameters:\r\n /// - request: The request to send.\r\n /// - completion: The completion closure to call when the request has completed.\r\n public func kickoff(\r\n request: HTTPRequest, \r\n completion: @escaping (Result) -> Void)\r\n \r\n /// Proceeds to the next interceptor in the array.\r\n /// \r\n /// - Parameters:\r\n /// - request: The in-progress request object\r\n /// - response: [optional] The in-progress response object, if received yet\r\n /// - completion: The completion closure to call when data has been processed and should be returned to the UI.\r\n public func proceedAsync(\r\n request: HTTPRequest, \r\n response: HTTPResponse?,\r\n completion: @escaping (Result) -> Void)\r\n \r\n /// Cancels the entire chain of interceptors.\r\n public func cancel()\r\n \r\n /// Restarts the request starting from the first inteceptor.\r\n ///\r\n /// - Parameters:\r\n /// - request: The request to retry\r\n /// - completion: The completion closure to call when the request has completed.\r\n public func retry(\r\n request: HTTPRequest,\r\n completion: @escaping (Result) -> Void)\r\n }\r\n ```\r\n- **`RequestChainNetworkTransport`** provides an implementation of `NetworkTransport` which uses an `InterceptorProvider` to create a request chain for each request. \r\n ```swift\r\n public class RequestChainNetworkTransport: NetworkTransport {\r\n \r\n public init(interceptorProvider: InterceptorProvider,\r\n endpointURL: URL,\r\n additionalHeaders: [String: String] = [:],\r\n autoPersistQueries: Bool = false,\r\n cachePolicy: CachePolicy = .default,\r\n requestCreator: RequestCreator = ApolloRequestCreator(),\r\n useGETForQueries: Bool = false,\r\n useGETForPersistedQueryRetry: Bool = false)\r\n }\r\n ```\r\n\r\n### Changes to existing Protocols and Classes\r\n\r\n- **`ApolloStore`** will no longer require a `GraphQLQuery` explicitly for fetching data from the store. It will instead return an error if the `GraphQLOperationType` is not `.query`. This change is necessary to avoid going down an enormous rabbit hole with generics since `GraphQLOperation` has an associated type. \r\n- The **`NetworkTransport`** protocol will get a new method to be implemented: \r\n\r\n ```swift\r\n func sendForResult(operation: Operation,\r\n completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable\r\n ```\r\n \r\n This will avoid the double-wrapping of `GraphQLResponse` around the `GraphQLResult` so that only the `GraphQLResult` is actually returned. The `send` method will eventually be deprecated and removed. \r\n- **`ApolloClient`** will get a new `sendForResult` method which calls into the `sendForResult` method added to `NetworkTransport`.\r\n\r\n## How will this work in practice? \r\n\r\nInstantiating a new legacy client manually will look like this: \r\n\r\n```swift\r\nlazy var legacyClient: ApolloClient = {\r\n let url = URL(string: \"http://localhost:8080/graphql\")!\r\n \r\n let store = ApolloStore(cache: InMemoryNormalizedCache())\r\n let provider = LegacyInterceptorProvider(store: store)\r\n let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: url)\r\n \r\n return ApolloClient(networkTransport: transport)\r\n}()\r\n```\r\n\r\nIdeally I'll be able to transparently swap out the existing `HTTPNetworkTransport` for this so that this would be the under-the-hood setup on `ApolloClient`, but this may involve a transition period. \r\n\r\nCalls to the client will look like this: \r\n\r\n```swift\r\nlegacyClient.fetchForResult(query: HeroNameQuery()) { result in\r\n switch result {\r\n case .success(let graphQLResult):\r\n print(graphQLResult.data?.hero?.name ?? \"Name not found\")\r\n case .failure(let error):\r\n print(\"Unexpected error: \\(error)\")\r\n }\r\n}\r\n```\r\n\r\nNote that this is VERY similar to how they look on the surface at the moment, which is intentional. \r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Overall this looks great. I only have 2 small questions: \r\n- Do you think it is possible to add an `ErrorType: Error` generic type to the signature of `handleErrorAsync` in the `ApolloErrorInterceptor`? I would love to be able to return typed errors, and this generic parameter could simply default to `Error` itself if not specified.\r\n- Do you have any plan to add an official `ApolloCombine` module?","author":{"__typename":"User","login":"TizianoCoroneo","id":"MDQ6VXNlcjE1MzQwMzgy","name":"TizianoCoroneo"}},{"__typename":"IssueComment","body":"1. I'll have to mess around with this and see how it works - my recollection is that it would cause much more complex typing issues, but I'll see what we can do. \r\n2. Eventually, but it's going to be after all the codegen rewrites. There is a [community Combine package](https://github.com/joel-perry/ApolloCombine) if you're looking for something immediately","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> Instantiating a **new legacy** client\r\n\r\nHeh, this was kinda funny to me.\r\n\r\n---\r\n\r\n> `public let requestCreator: RequestCreator`\r\n\r\nShould the request creator live on _all_ requests? Said another way, what's the rationale behind only allowing `JSONRequests` to have this property?\r\n\r\n> Do you think it is possible to add an `ErrorType: Error` generic type to the signature of` handleErrorAsync`\r\n\r\n+1 to this, but definitely not critical for the context of this RFC. I feel like typed errors could be it's own whole RFC/PR too!\r\n\r\n\r\n> **ApolloStore will no longer require a GraphQLQuery explicitly for fetching data from the store**. It will instead return an error if the GraphQLOperationType is not .query. This change is necessary to avoid going down an enormous rabbit hole with generics since GraphQLOperation has an associated type.\r\n\r\nI'm a little bit fuzzy on what this change is. If not a `GraphQLQuery`, what will the input for data fetching from the store be? Can you clarify for me?\r\n\r\n---\r\n\r\nAll told, this seems solid! One of our big use cases in the GitHub app for the current delegate implementation of this is to logout on HTTP 401 status codes, so it seems like that should make this a little simpler (just need an interceptor to throw an error when those responses come back).\r\n\r\nHoller if you want some feedback directly on https://github.com/apollographql/apollo-ios/pull/1341 as well!","author":{"__typename":"User","login":"eliperkins","id":"MDQ6VXNlcjEwNTE0NTM=","name":"Eli Perkins"}},{"__typename":"IssueComment","body":">> Instantiating a new legacy client\r\n\r\n> Heh, this was kinda funny to me.\r\n\r\nHa, that's what I get for working on this doc for so long, I completely glossed that over 🙃\r\n\r\n>> public let requestCreator: RequestCreator\r\n\r\n> Should the request creator live on all requests? Said another way, what's the rationale behind only allowing JSONRequests to have this property?\r\n\r\nMy thought that was only `HTTPRequest` subclasses that actually need to use it should have access to it - `JSONRequest` and a forthcoming `UploadRequest` would be the places I'm thinking. At this point both of those subclasses would need it, but I don't know that it makes sense to tie that to the base class at this time. Would be interesting to hear your thoughts on that.\r\n\r\n>> ApolloStore will no longer require a GraphQLQuery explicitly for fetching data from the store. It will instead return an error if the GraphQLOperationType is not .query. This change is necessary to avoid going down an enormous rabbit hole with generics since GraphQLOperation has an associated type.\r\n\r\n> I'm a little bit fuzzy on what this change is. If not a GraphQLQuery, what will the input for data fetching from the store be? Can you clarify for me?\r\n\r\nBasically, we have the `GraphQLOperation` protocol, with an associated type of `Data`, and its three sub-protocols, `GraphQLQuery`, `GraphQLMutation`, and `GraphQLSubscription`. Previously, we were limiting what operations could read from the cache to `GraphQLQuery`, since in theory that's the only place getting something from the cache would matter. \r\n\r\n`HTTPRequest` only requires a specification of `GraphQLOperation`, but when making a call into the cache, we can't use the `Blah is GraphQLQuery` method of figuring out whether a `GraphQLOperation` is a query because of the `associatedType` on `GraphQLOperation`. \r\n\r\nI tried about 15 different workarounds for this and this is the only one that wasn't monstrously over-complicated - everything else involved some mild-to-completely bizarre type erasure strategies. I'm not totally against those, but I think in this case the benefits of going that way were vastly outweighed just changing the gating of this a bit.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"and if you have specific feedback on #1341 I'd love to hear it - just be aware that there's definitely a lot that's WIP (thus the TODOs)","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"OK, I've done some poking around on the request for a typed error parameter, and I don't think it's going to be doable at the interceptor level.\r\n\r\nWhen I tried to add this in, any existing `Error` I tried to return would cause a \"Cannot convert value\" build failure: \r\n\"Screen\r\n\"Screen\r\n\r\nIt'd make the interceptors a lot harder to keep independent if they all had to have exactly the same type of error. It also wouldn't be possible for me to have default implementations return errors without having `TypedError` conform to some other protocol that allows me to return an underlying arbitrary error. Ultimately, I think that adds too much complexity for general use cases.\r\n\r\nI think if you want to write your own typed wrapper that takes whatever's returned and feeds it into something with an `underlying` error that's easier to switch on, that could work. But I think requiring everything have to be the same type at a protocol level is going to lead to a hell of a lot more confusion than it solves. \r\n\r\nWould love to hear feedback on this finding.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"One of the things that's nice about the `ApolloLink` abstraction used for the web version of Apollo Client is that the link chain is more like a linked list, rather than an array, with each link deciding how to forward the request on to the rest of the chain (and how to process the response), without needing an overarching `RequestChain` to manage the list of links.\r\n\r\nConcretely, this kind of approach would probably mean the `InterceptorProvider` would return a single `ApolloInterceptor` (analogous to `ApolloLink`), representing the head of the linked list, rather than a `[ApolloInterceptor]` array. The last interceptor in the chain (the tail of the list) would be responsible for performing the actual HTTP request, in most cases—but not always!\r\n\r\nSometimes you want to terminate the chain with something that makes an HTTP request, but other times the terminal link might provide its own data (for example, mock data during tests). Sometimes you might want to split a request between multiple downstream links, or choose among several servers that can handle different kinds of requests (or load-balance the same type of request between multiple servers, entirely on the client). It's hard to represent branching structures like that as an array, because it's no longer really a list, but a dynamic tree. But if each interceptor gets to make its own decisions about how it passes requests to the rest of the chain (and how it handles the responses), the branching can be hidden as an implementation detail, with each interceptor abstracting over everything downstream from it.\r\n\r\nI don't know enough Swift to anticipate specific ways in which this approach might be tricky, but it seems like it should be possible to give the interceptor chain more of a recursive, potentially tree-like structure. That's worked pretty well on the web, in the sense that I haven't had to worry very much about the `ApolloLink` system, even as I've changed large portions of the rest of the library.\r\n\r\nFor reference, here's an overview of `ApolloLink` concepts that I've found useful in the past: https://www.apollographql.com/docs/link/overview/","author":{"__typename":"User","login":"benjamn","id":"MDQ6VXNlcjU3NTA=","name":"Ben Newman"}},{"__typename":"IssueComment","body":"I think one huge, huge difference is that things like cancellation, retry, and thread management can be handled through javascript's `Observable` reactive system. \r\n\r\nThat just isn't doable without either using Combine (which would require dropping everything below iOS 12, and is unfortunately a non-starter with a number of our larger users) or adding some kind of Reactive library as a dependency (which I am loathe to do because of the *massive* number of dependency conflicts it could introduce). \r\n\r\nHowever, I think you're right that splitting out methods for request setup vs response handling is a good idea - this could at least help reduce the number of things that need to be optional on `HTTPResponse`. \r\n\r\nWill futz with this tomorrow. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd I'm glad you brought that up!\r\n\r\nWhile I agree that `Observable`s are an easier pill to swallow in JavaScript, and they do figure prominently in the `ApolloLink` API, I specifically do not think it's necessary to replicate their behavior here.\r\n\r\nI should also mention that `Observable` is not implemented natively in JS, so you still need some sort of library, and (if I'm being honest) the API doesn't fully deliver on any of those benefits you mentioned, so I think it's fair to say the acceptance of `Observable` in JS (compared to the resistance to Combine in iOS) is a matter of culture/taste/evangelism.\r\n\r\nOn the topic of cancellation, one approach that does work is to pass some sort of context object explicitly down through the chain (and back up), so that each link/interceptor can check whether the request has been cancelled at points where aborting would be safe. `Observable`s don't provide any useful notion of context, even if you wanted it, but you can design a pipeline/interceptor/chain system like this to provide a strongly typed context object everywhere it's needed, I believe.\r\n\r\nOn the topic of retrying, the [`RetryLink`](https://github.com/apollographql/apollo-client/blob/master/src/link/retry/retryLink.ts) subclass of `ApolloLink` has been successful in part because the retry logic can be hidden behind the same abstraction that any other `ApolloLink` provides. From the perspective of links earlier in the chain, a request that succeeded after several retries looks exactly like one that succeeded on the first try, except that it might have taken a bit longer. If retrying was something you could implement in a perfectly generic way for all interceptors, it might make sense to hoist it to a higher layer of the system (maybe into `RequestChain`), but in practice retrying tends to be sensitive to application concerns (different logic for different queries, even), so I think it makes sense to push it down into a part of the system that can be customized by application developers.\r\n\r\nI think we can agree it's important for interceptors to be able to perform any kind of async work as an implementation detail, which requires a uniformly asynchronous API. Both `Observable` and Combine provide that kind of API, but they are both probably overkill, or at the very least they would need to earn their way into a system like this. I believe you that Combine is not worth it for iOS, but then again I'm not sure `Observable` is totally defensible for JS applications, either.","author":{"__typename":"User","login":"benjamn","id":"MDQ6VXNlcjU3NTA=","name":"Ben Newman"}},{"__typename":"IssueComment","body":"> When I tried to add this in, any existing `Error` I tried to return would cause a \"Cannot convert value\" build failure:\r\n\r\nfrom this error it looks like you changed the signature of `handleErrorAsync` to:\r\n```swift\r\nfunc handleErrorAsync(\r\n error: TypedError,\r\n chain: RequestChain,\r\n request: HTTPRequest,\r\n response: HTTPResponse,\r\n completion: @escaping (Result) -> Void)\r\n```\r\n\r\nwhile I was thinking something like: \r\n```swift\r\nfunc handleErrorAsync(\r\n error: Error, // keep this one untyped so that you can pass anything you need\r\n chain: RequestChain,\r\n request: HTTPRequest,\r\n response: HTTPResponse,\r\n completion: @escaping (Result) -> Void) // but allow users to wrap the internal errors in their own custom types\r\n```\r\nso that you can give a default implementation that does not wrap the error type: \r\n```swift \r\nextension ApolloErrorInterceptor where TypedError == Error {\r\n// default interceptor with a untyped completionHandler\r\n```\r\n\r\nsorry I wasn't clear with the previous message. Thank you for fiddling with this!\r\n\r\n> +1 to this, but definitely not critical for the context of this RFC. I feel like typed errors could be it's own whole RFC/PR too!\r\n\r\n@designatednerd would you prefer to move this conversation in a separate issue?","author":{"__typename":"User","login":"TizianoCoroneo","id":"MDQ6VXNlcjE1MzQwMzgy","name":"TizianoCoroneo"}},{"__typename":"IssueComment","body":"@TizianoCoroneo Yeah if I left it with `Error` as the incoming error, I got that same `Cannot convert value` problem in the method in question - I'll take a look at your suggestion later today though","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@benjamn I think one thing that's helpful context to understand is that the basis for this architecture is the [`ApolloInterceptor` type in Android](https://github.com/apollographql/apollo-android/tree/master/apollo-runtime/src/main/java/com/apollographql/apollo/interceptor). This itself is based on [`OkHttp` library's `Interceptor` type](https://square.github.io/okhttp/interceptors/) that's used very widely throughout the Android ecosystem for networking.\r\n\r\nIn `OkHttp`, there's a chain that takes an array of interceptors. Each interceptor in the array needs to call `proceed` before it can keep going, and then each one calls `intercept` to handle the result. There's a few issues with that architecture as-is (mostly around things being implicitly asynchronous instead of explicitly asynchronous), which are generally dealt with by `ApolloInterceptor`'s changes to the architecture.\r\n\r\nStill futzing around, but I thought that'd be useful context.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@TizianoCoroneo I've pushed some stuff to a branch ominously named `nope/typed-errors` if you want to take a look - basically, what you're looking for is not possible without associated types which sends this wholllllllllle mess down a huge rabbit hole. This is a huge piece of why the generic constraint is on the function rather than set up as an `associatedType` in the first place. If you see a better way please definitely feel free to open a PR to that branch!\r\n\r\nAll: I did make some improvements that make it easier to reason about what data's coming back through (basically: Got rid of the need for `Parseable` and moved to `GraphQLResult` as the type being returned in the completion closure), I'll update the RFC tomorrow or Monday to match the updated implementation details. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I tried to play around with it, and I confirm that the ominous name of the branch is accurate. I found no way to avoid having the `TypedError` bubble up to the `RequestChain`, and from there going everywhere else.\r\nThanks for trying this anyway 😄 ","author":{"__typename":"User","login":"TizianoCoroneo","id":"MDQ6VXNlcjE1MzQwMzgy","name":"TizianoCoroneo"}},{"__typename":"IssueComment","body":"Still looking at some of the stuff @benjamn and I were talking about, but I've updated the issue to match what's in the code at the moment.\r\n\r\nTL;DR - I was able to simplify by constraining to `Operation.Data` on `GraphQLOperation` instead of to the more generic `Parseable`. In the end, the result of a GraphQL operation is actually what we handle, so making it even more generic didn't really anything (and in fact made it harder to real with errors that are within `GraphQLResult`, which is part of what a lot of folks want to be able to do. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"More updates:\r\n- Moved `HTTPResponse` to being optional on the interceptor and related methods rather than having its properties be optional. This makes it way clearer whether a response has been received from the network or not. \r\n- Moved error declaration within each individual interceptor for clarity\r\n\r\n@benjamn: While I think the linked-list idea is more flexible, I don't know the additional flexibility it provides gets you much more than what we have in \"This interceptor can be async and take as long as it pleases to do stuff, so you can fire off a bunch of additional network requests and wait for them to call `proceed` if you feel like it.\" \r\n\r\nI think the overwhelming majority of interceptors are not going to do that, and I think the simplicity, especially from a retry standpoint, of \"Here's a list of interceptors in the order they should be executed, GO!\" is a lot better fit for the way this is used on iOS than a linked list would be. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"More updates are up - I don't think any fundamentally change anything already in here, but I do have a couple questions: \r\n\r\n1. Is there anyone using the `context: UnsafeMutableRawPointer?` on the various send/fetch methods for `ApolloClient` _in a way that could not be replaced by this change_? I took it out for now but I figured It's worth asking.\r\n2. I'm extremely tempted to rip out the current `HTTPNetworkTransport` that `RequestChainNetworkTransport` is replacing altogether, largely because I would need to keep a whole bunch of knotted code in `ApolloClient` around that facilitates caching longer than I'd like to. However, I'd like to hear y'all's thoughts about ripping the band-aid in a single release (with a migration guide) vs. doing a bridge release that still has `HTTPNetworkTransport` and its associated ick with a bunch of deprecation warnings. \r\n\r\n For what it's worth I've updated all the tests that aren't specifically _for_ the `HTTPNetworkTransport` to use either a `RequestChainNetworkTransport`, or a `MockNetworkTransport` which inherits from it, and everything is back to passing. I don't think that fully captures the extent to which this would create work for developers using the more advanced delegate features, but I do think for people using less advanced features it shows that everything *should* work the same. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> 1. Is there anyone using the `context: UnsafeMutableRawPointer?` on the various send/fetch methods for ApolloClient in a way that could not be replaced by this change? I took it out for now but I figured It's worth asking.\r\n\r\nNot using it here 🤷‍♂️ feels like a pretty cumbersome API to use effectively right now, so removing it seems alright, as long as we don't think others are using it.\r\n\r\n> I'm extremely tempted to rip out the current ` that RequestChainNetworkTransport is replacing altogether, largely because I would need to keep a whole bunch of knotted code in ApolloClient around that facilitates caching longer than I'd like to. However, I'd like to hear y'all's thoughts about ripping the band-aid in a single release (with a migration guide) vs. doing a bridge release that still has HTTPNetworkTransport and its associated ick with a bunch of deprecation warnings.\r\n\r\nI think it's alright to remove this in favor of `RequestChainNetworkTransport`. Is there a way to deprecate it, and replace it's impl with `RequestChainNetworkTransport`? If it feels like more overhead to maintain, API-wise, I think it's fine to force consumers over to use `RequestChainNetworkTransport` instead, since it solves the same problems that supplying a custom `HTTPNetworkTransport` was doing.","author":{"__typename":"User","login":"eliperkins","id":"MDQ6VXNlcjEwNTE0NTM=","name":"Eli Perkins"}},{"__typename":"IssueComment","body":"> feels like a pretty cumbersome API to use effectively right now,\r\n\r\nWholeheartedly agreed, I want to come up with something way better (and that does not involve the word `Unsafe`)\r\n\r\n> replace it's impl with`RequestChainNetworkTransport`\r\n\r\nI don't think it's a great idea because there's a bunch of stuff with delegates that would be a bit of a hot mess to handle. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'm going to close out this RFC as I'm getting ready to beta off of #1341 - I just updated the [client initialization documentation](https://deploy-preview-1341--apollo-ios-docs.netlify.app/docs/ios/initialization/), which hopefully will give a good idea of how this should all be working.\r\n\r\nIn terms of differences from what's outlined in the RFC, at this time the main difference is that I moved retry counting off the `HTTPRequest` itself and onto the `MaxRetryInterceptor`. \r\n\r\nFurther comments should be left on #1341 - thank you all for the feedback!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"getting \"The network connection was lost\" sometimes, while Calling API's","author":{"__typename":"User","login":"guru-mtech","id":"MDQ6VXNlcjY0NjU4ODQw","name":null},"body":"I cannot get the grapgql responces sometimes and getting following messages in console. Though My Internet connection completely normal and and speed is about 10MBps, I am getting follwing error sometimes!!\r\n\r\n\r\n2020-08-02 01:07:00.435742+0530 Dwell[16526:884485] Task <080DA3DA-F4E7-4F5C-9DE3-D2B77A55F81B>.<8> HTTP load failed, 159275/0 bytes (error code: -1005 [4:-4])\r\n2020-08-02 01:07:00.461811+0530 Dwell[16526:884303] Task <080DA3DA-F4E7-4F5C-9DE3-D2B77A55F81B>.<8> finished with error [-1005] Error Domain=NSURLErrorDomain Code=-1005 \"The network connection was lost.\" UserInfo={_kCFStreamErrorCodeKey=-4, NSUnderlyingError=0x6000014c4300 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 \"(null)\" UserInfo={NSErrorPeerAddressKey={length = 16, capacity = 16, bytes = 0x10021f9b12da60e20000000000000000}, _kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <080DA3DA-F4E7-4F5C-9DE3-D2B77A55F81B>.<8>, _NSURLErrorRelatedURLSessionTaskErrorKey=(\r\n \"LocalDataTask <080DA3DA-F4E7-4F5C-9DE3-D2B77A55F81B>.<8>\"\r\n), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=https://localhost:8091/graphql, NSErrorFailingURLKey=https://localhost:8091/graphql, _kCFStreamErrorDomainKey=4}\r\nThe operation couldn’t be completed. (Apollo.URLSessionClient.URLSessionClientError error 2.)\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! That error is coming from Apple's URL loading system, not from Apollo. I've got no idea why that would be happening with `localhost` - that shouldn't even be going out of your local network. \r\n\r\nI don't _think_ it's `http` vs `https` since that would theoretically be a different error, but it might be worth giving it a shot since most of the time `localhost` doesn't have SSL set up. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Since I haven't heard anything back here in a couple weeks, I'm going to close this issue out. @guru-mtech if you're still having problems, feel free to reopen. Anyone else having similar problems, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Error \"Variable \"$id\" is never used\" not fail build process","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"},"body":"when generate API.swift with graphql file that has unuse variables.\r\nan error `Variable \"xxx\" is never used in operation \"xxx\"` is log but build process is success and run an app normally\r\n```\r\nquery Repo($id: ID!) {\r\n currentuser {\r\n id\r\n }\r\n}\r\n\r\n```\r\n\r\n\r\nbut on other error, the build process will fail \r\n\r\nEx. generate API.swift with below graphql result an error \r\n\r\n`error: Cannot query field \"something\" on type \"Query\". Did you mean \"setting\"?` \r\n\r\nand build process is fail\r\n```\r\nquery Repo {\r\n currentuser {\r\n id\r\n }\r\n something\r\n}\r\n```\r\n\r\nPS: Apollo version 0.27.1","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I would first recommend updating to a more recent version of the SDK - IIRC this was a bug in the underlying CLI that has since been addressed. If that doesn't help, let me know. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"update to Apollo 0.30.0 doesn't help. ","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"```\r\nVariable \"$id\" is never used in operation \"Repo\".\r\n\r\nCommand PhaseScriptExecution emitted errors but did not return a nonzero exit code to indicate failure\r\n```\r\n\r\n\r\nError from log when build with\r\n\r\n```\r\nquery Repo($id: ID!) {\r\n currentuser {\r\n id\r\n }\r\n}\r\n```","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"OK - are you using the shell script or the Swift Scripting method to run your codegen? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'm not sure about that.\r\n\r\nI add a run script phase on Build Phase that has script below with shell = sh \r\n```\r\nPATH=$PATH:/usr/local/opt/node@8/bin\r\nSCRIPT_PATH=\"${PODS_ROOT}/Apollo/scripts\"\r\n\r\nif [ -z \"${XCS_BOT_NAME}\" ]; then\r\n\r\ncd \"${SRCROOT}/${TARGET_NAME}\"\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./GraphQL/**/*.graphql --localSchemaFile=\"GraphQL/Generated/schema.json\" GraphQL/Generated/API.swift --customScalarsPrefix=GraphQL\r\nfi\r\n\r\n```","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"Yep that's the shell script method. Can you confirm that in your schema `currentuser` requires a non-optional `id`, meaning an `ID!`? If it only requires an `ID` (without the exclamation point) then that might be the source of the issue. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"`currentuser ` does not require any variables.`$id: ID!` is just unuse variable that i forgot to remove. it can change to any variable Ex. `Repo($abcd: String!)` or ` Repo($test: Int!)`\r\n\r\nif RepoQuery never called or called with given variable Ex. `RepoQuery(abcd: \"a\")` it'll build success with error that mention before but will throw an `Variable $abcd is never used in operation \"Repo\"` from the server","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"> `currentuser` does not require any variable\r\n\r\nI'm almost positive this is why it's not exiting, then. When the error is more of a \"Hey, you forgot to remove this, but there are no real consequences to not using this\" rather than a \"Nope, this is not a valid query\", we don't want to fail the entire build. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I understand that it's not a fatal error for an entire app. but if the query is sent to graphql server it'll always fail due to graphql default validation rule(if I understand it correctly). \r\nSo, I think it's not different from invalid query because the query always fails if sends to server","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"Hm...what server are you using? I think that might be a server implementation detail, but I could be wrong. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"`apollo-server-express` from https://github.com/apollographql/apollo-server/tree/main/packages/apollo-server-express\r\n","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"`GraphQL operation is only valid if all variables defined by an operation are used `\r\nfrom graphql-js [line](https://github.com/graphql/graphql-js/blob/80471134f1152c69da2cc27518a127991cc801b9/src/validation/rules/NoUnusedVariablesRule.d.ts#L7\r\n)\r\n\r\nI'm not sure that the server can choose to enable/disable this rule but I think it enable by default.","author":{"__typename":"User","login":"Mangese","id":"MDQ6VXNlcjIxNTEyNTI4","name":"Mangese"}},{"__typename":"IssueComment","body":"Ahhh got it. OK, will talk to some tooling folks on this.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"(FYI that team is super backed up, so it may take some time)","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"So our tooling folks are working on a new Rust-based parsing and validation of schema + queries, it will have to land with that. \r\n\r\nI believe the reason it's not in there right now is because it would cause errors when people were using it in watch mode (mostly useful for JS) and it got disabled for that. However, I'm going to be working to make sure there's at least a mode that can be selected in new Rust stuff to bomb out on errors like this. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Crashlytics reported: \"Crashed: com.apollographql.DataLoader\"","author":{"__typename":"User","login":"Kharauzov","id":"MDQ6VXNlcjE4MjQzNTI1","name":"Serhii Kharauzov"},"body":"Hi 👋, We have a version of iOS Apollo SDK: 0.27.0\r\n\r\nWe've got many crashes:\r\n\r\nURLSessionClient.swift line 85\r\nURLSessionClient.sendRequest(_:rawTaskCompletionHandler:completion:)\r\n\r\nCrashed: com.apollographql.DataLoader\r\nEXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000000\r\n\r\nWill be thankful for any suggestion or help 🙏🏼\r\n\r\nIt happened for different iOS versions and different devices.\r\nHere is a stack trace:\r\n```\r\nApollo\r\nURLSessionClient.swift - Line 85\r\nURLSessionClient.sendRequest(_:rawTaskCompletionHandler:completion:) + 85\r\n2\r\nApollo\r\nHTTPNetworkTransport.swift - Line 159\r\nHTTPNetworkTransport.send(operation:isPersistedQueryRetry:files:completionHandler:) + 159\r\n3\r\nApollo\r\nApolloClient.swift - Line 70\r\nApolloClient.send(operation:shouldPublishResultToStore:context:resultHandler:) + 70\r\n4\r\nApollo\r\nApolloClient.swift - Line 287\r\nFetchQueryOperation.fetchFromNetwork() + 287\r\n5\r\nApollo\r\nApolloClient.swift - Line 282\r\nclosure #1 in FetchQueryOperation.start() + 282\r\n6\r\nApollo\r\nApolloStore.swift - Line 193\r\nclosure #2 in ApolloStore.load(query:resultHandler:) + 193\r\n7\r\nApollo\r\nPromise.swift - Line 142\r\nclosure #1 in closure #1 in Promise.catch(_:) + 142\r\n8\r\nApollo\r\n - Line 4351240464\r\npartial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351240464\r\n9\r\nApollo\r\n - Line 4351234200\r\nclosure #1 in Promise.resolve(_:) + 4351234200\r\n10\r\nApollo\r\n - Line 4351232104\r\nPromise.resolve(_:) + 4351232104\r\n11\r\nApollo\r\nPromise.swift - Line 213\r\nPromise.reject(_:) + 213\r\n12\r\nApollo\r\nPromise.swift - Line 122\r\nclosure #1 in closure #1 in Promise.andThen(_:) + 122\r\n13\r\nApollo\r\n - Line 4351240464\r\npartial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351240464\r\n14\r\nApollo\r\n - Line 4351234200\r\nclosure #1 in Promise.resolve(_:) + 4351234200\r\n15\r\nApollo\r\n - Line 4351232104\r\nPromise.resolve(_:) + 4351232104\r\n16\r\nApollo\r\nPromise.swift - Line 213\r\nPromise.reject(_:) + 213\r\n17\r\nApollo\r\nPromise.swift - Line 165\r\nclosure #1 in closure #1 in Promise.map(_:) + 165\r\n18\r\nApollo\r\npartial apply for closure #1 in closure #1 in Promise.map(_:) + 4351241932\r\n19\r\nApollo\r\n - Line 4351240464\r\npartial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351240464\r\n20\r\nApollo\r\n - Line 4351234200\r\nclosure #1 in Promise.resolve(_:) + 4351234200\r\n21\r\nApollo\r\n - Line 4351232104\r\nPromise.resolve(_:) + 4351232104\r\n22\r\nApollo\r\nPromise.swift - Line 213\r\nPromise.reject(_:) + 213\r\n23\r\nApollo\r\nPromise.swift - Line 142\r\nclosure #1 in closure #1 in Promise.catch(_:) + 142\r\n24\r\nApollo\r\n - Line 4351240464\r\npartial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351240464\r\n25\r\nApollo\r\n - Line 4351234200\r\nclosure #1 in Promise.resolve(_:) + 4351234200\r\n26\r\nApollo\r\n - Line 4351232104\r\nPromise.resolve(_:) + 4351232104\r\n27\r\nApollo\r\nPromise.swift - Line 213\r\nPromise.reject(_:) + 213\r\n28\r\nApollo\r\nPromise.swift - Line 122\r\nclosure #1 in closure #1 in Promise.andThen(_:) + 122\r\n29\r\nApollo\r\n - Line 4351240464\r\npartial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351240464\r\n30\r\nApollo\r\n - Line 4351234200\r\nclosure #1 in Promise.resolve(_:) + 4351234200\r\n31\r\nApollo\r\n - Line 4351232104\r\nPromise.resolve(_:) + 4351232104\r\n32\r\nApollo\r\nPromise.swift - Line 213\r\nPromise.reject(_:) + 213\r\n33\r\nApollo\r\nPromise.swift - Line 142\r\nclosure #1 in closure #1 in Promise.catch(_:) + 142\r\n34\r\nApollo\r\nPromise.swift - Line 238\r\nclosure #1 in Promise.whenResolved(_:) + 238\r\n35\r\nApollo\r\nPromise.swift - Line 4351205536\r\nPromise.whenResolved(_:) + 4351205536\r\n36\r\nApollo\r\nPromise.swift - Line 136\r\npartial apply for closure #1 in Promise.catch(_:) + 136\r\n37\r\nApollo\r\nPromise.swift - Line 68\r\nPromise.init(_:) + 68\r\n38\r\nApollo\r\nPromise.swift - Line 135\r\nclosure #1 in closure #1 in Promise.flatMap(_:) + 135\r\n39\r\nApollo\r\npartial apply for closure #1 in closure #1 in Promise.map(_:) + 4351241932\r\n40\r\nApollo\r\n - Line 4351240464\r\npartial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351240464\r\n41\r\nApollo\r\nspecialized closure #1 in Promise.resolve(_:) + 4351233008\r\n42\r\nApollo\r\nspecialized Promise.fulfill(_:) + 4350994784\r\n43\r\nApollo\r\n - Line 4350998216\r\npartial apply for specialized Promise.fulfill(_:) + 4350998216\r\n44\r\nApollo\r\nPromise.swift - Line 163\r\nspecialized closure #1 in closure #1 in Promise.map(_:) + 163\r\n45\r\nApollo\r\npartial apply for specialized closure #1 in closure #1 in Promise.map(_:) + 4351244372\r\n46\r\nApollo\r\n - Line 4351244132\r\npartial apply for specialized thunk for @escaping @callee_guaranteed (@in_guaranteed Result) -> () + 4351244132\r\n47\r\nApollo\r\n - Line 4351232400\r\nspecialized closure #1 in Promise.resolve(_:) + 4351232400\r\n48\r\nApollo\r\nPromise.swift - Line 4350994980\r\nspecialized Promise.fulfill(_:) + 4350994980\r\n49\r\nApollo\r\n - Line 4351012708\r\npartial apply for specialized thunk for @escaping @callee_guaranteed (@in_guaranteed B) -> () + 4351012708\r\n50\r\nApollo\r\nDataLoader.swift - Line 53\r\nspecialized closure #3 in closure #1 in DataLoader.dispatch() + 53\r\n51\r\nApollo\r\n - Line 4351012380\r\npartial apply for specialized thunk for @escaping @callee_guaranteed (@guaranteed [B]) -> (@error @owned Error) + 4351012380\r\n52\r\nApollo\r\nPromise.swift - Line 122\r\nspecialized closure #1 in Promise.andThen(_:) + 122\r\n53\r\nApollo\r\nDataLoader.swift - Line 4351009748\r\nspecialized closure #1 in DataLoader.dispatch() + 4351009748\r\n54\r\nApollo\r\n - Line 4350967396\r\nthunk for @escaping @callee_guaranteed () -> () + 4350967396\r\n```\r\n\r\n\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hello, this was addressed in [0.27.1](https://github.com/apollographql/apollo-ios/blob/main/CHANGELOG.md#v0271), I recommend updating your client. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd , hello👋 Roger that. We've already updated to the latest version 0.30.0. \r\nWe'll see soon if it solves the issue.\r\nThanks.","author":{"__typename":"User","login":"Kharauzov","id":"MDQ6VXNlcjE4MjQzNTI1","name":"Serhii Kharauzov"}},{"__typename":"IssueComment","body":"OK great - I'm going to close this since it was a known issue with 0.27.0. If you're still seeing problems with this on 0.30.0, please open a new issue and we'll figure it out. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Getting \"The request timed out.\" sometimes while calling query and mutation.","author":{"__typename":"User","login":"DiwakarThapa","id":"MDQ6VXNlcjI5OTE3Nzk5","name":"diwakar thapa"},"body":"Hello!!! \r\nSometimes when I open the app I cannot get the **response of the first query** it requests rather I get the following **timeout error message** on Xcode debug console. I tried every possible solution found on StackOverflow but could find any effective solution and also could not figure out why **\"The request timed out.\"** has occurred in the first place. Our Android team is also experiencing similar issues. On the **server-side**, the timeout interval is **65 seconds**. so, I set request timeout interval **65 seconds** but it didn't work. \r\n\r\n**Console Error**\r\n```\r\nError Domain=NSURLErrorDomain Code=-1001 \"The request timed out.\" UserInfo={_kCFStreamErrorCodeKey=-2103, NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <1874F8BE-FA0F-45E1-8A51-96F290D85883>.<2>, NSURLErrorRelatedURLSessionTaskErrorKey=(\r\n \"LocalDataTask <1874F8BE-FA0F-45E1-8A51-96F290D85883>.<2>\"\r\n), NSLocalizedDescription=The request timed out., NSErrorFailingURLStringKey=https://example.graphql, NSErrorFailingURLKey=https://example.graphql, _kCFStreamErrorDomainKey=4}\r\n```\r\n**Is this apollo-ios terminating the request itself or server-side error?** ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"This is an error from Apple's URL loading system, the timeout is happening there. Are you saying that the timeout is happening before the 65 seconds that you set it to? Or just that it's still happening? The fact that your Android app is also having a similar problem points pretty squarely at your server.\r\n\r\nAlso am I correct in assuming that the url string here `https://example.graphql` is a placeholder for your real URL? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd `https://example.graphql` is a placeholder for our real URL? timeout is happening at 65 seconds.","author":{"__typename":"User","login":"DiwakarThapa","id":"MDQ6VXNlcjI5OTE3Nzk5","name":"diwakar thapa"}},{"__typename":"IssueComment","body":"Yeah that sounds like the request timeout is working as expected and the issue is that the request is, in fact, timing out, and that the issue is most likely going to be on your server side. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"thank you @designatednerd ","author":{"__typename":"User","login":"DiwakarThapa","id":"MDQ6VXNlcjI5OTE3Nzk5","name":"diwakar thapa"}},{"__typename":"IssueComment","body":"@designatednerd I forget to mention one thing, on **graphql playground** if we request the same query or mutation multiple times the response arrives without \"The request timed out. \" error but on the app side sometimes \"The request timed out. \" error appears. why is that?","author":{"__typename":"User","login":"DiwakarThapa","id":"MDQ6VXNlcjI5OTE3Nzk5","name":"diwakar thapa"}},{"__typename":"IssueComment","body":"GraphQL playground generally runs on your the same server as your endpoint, so in theory it's just making local calls. It's also possible that there's some kind of credential that is available through the web that's not going through to mobile. I wish I could narrow it down for you but unfortunately there are about a zillion things that could go wrong here. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@DiwakarThapa did you find a solution for your Problem? In our application, we have the same behaviour. Sometimes we run into a timeout, but the GraphQL Playground is always working.","author":{"__typename":"User","login":"DaTebe","id":"MDQ6VXNlcjEyOTY3MzA1","name":"DaTebe"}}]}},{"__typename":"Issue","title":"extensions property on GraphQLResult","author":{"__typename":"User","login":"paulkite","id":"MDQ6VXNlcjQwOTMwMDc=","name":"Paul Kite"},"body":"Hello! Curious if there are any plans to implement the `extensions` hash map support on `GraphQLResult`. I see the Android implementation has this and would love to be able to have the same ability to use this as well.\r\n\r\nThanks!","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"This [is implemented on `GraphQLError`](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/GraphQLError.swift#L33) on our end. Are you using it in a non-error capacity? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yes. Our team sends non-error information through `extensions`.","author":{"__typename":"User","login":"paulkite","id":"MDQ6VXNlcjQwOTMwMDc=","name":"Paul Kite"}},{"__typename":"IssueComment","body":"OK - looking at [the spec](https://spec.graphql.org/June2018/#sec-Response-Format) it does appear `extensions` is allowed at the root of the response. \r\n\r\nI'm somewhat swamped at the moment - if you want to make a PR you're more than welcome to (just make sure to add tests!) but I'll try to get to it as I can if not. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thank you so much for the response!","author":{"__typename":"User","login":"paulkite","id":"MDQ6VXNlcjQwOTMwMDc=","name":"Paul Kite"}},{"__typename":"IssueComment","body":"@designatednerd Just curious, what's the usual turnaround on PRs from the community to getting into a release?","author":{"__typename":"User","login":"paulkite","id":"MDQ6VXNlcjQwOTMwMDc=","name":"Paul Kite"}},{"__typename":"IssueComment","body":"Usually fairly quick if they're small. It'd almost certainly be faster than waiting for me to have bandwidth 😛 ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"This shipped as part of 0.32.0!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"GraphQLQueryWatcher - fetch and watch flow.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null},"body":"Let's discuss watchers, cache and their flow.\r\n\r\nCold start of application - no cache at all. \r\n**Here are my debug logs:**\r\n```\r\nisReachable true //Reachability change\r\nUser: nil //No user logged in \r\napollo.watch(query: SyncManagerQuery(), cachePolicy: .returnCacheDataDontFetch) \r\nWatch SyncManagerQuery // We are interested ONLY in cached data.\r\nWatch SyncManagerQuery error //Error cache is empty. It's ok\r\nMissing value //Error description - missing value. Because cache is empty. \r\n\r\n```\r\n\r\nHere everything seems to be fine. We are starting application for the first time. Cache is empty. Query watcher is being triggered and is returning error because of lack of data in cache.\r\n\r\nNow let's move forward and log in.\r\n\r\n```\r\nOptional() //Now we've got user\r\nfetch. apollo.fetch(query: SyncManagerQuery(), cachePolicy: .fetchIgnoringCacheData) \r\nFetch Sync FETCH //Ignoring cache data is still creating cache am I right?\r\nSync Fetch success //Fetch is successful \r\nBUT NOTHING IS HAPPENING :(\r\n```\r\n\r\n**Question 1:** Why watcher is not reacting? It is being stored in a parent object. \r\n`private var syncWatcher: GraphQLQueryWatcher?`\r\nand is initialized before fetch trigger.\r\n\r\nOk let's start over again. Close the application and start again with already existing cache. \r\n\r\n```\r\nisReachable true //We've got internet\r\nOptional() //We've got user\r\nFetch Sync FETCH //Above conditions are triggering FETCH\r\nWatch SyncManagerQuery //Hmm watch is also starting? Not that scary ok, it is just executing for the first time?\r\nWatch SyncManagerQuery success //Success - because we already have cache so it's ok\r\nSync Fetch success //In the meantime FETCH just finished\r\nWatch SyncManagerQuery // **1*** So it is triggering watch. Not sure why.\r\nWatch SyncManagerQuery error //Error :(The operation couldn’t be completed. (Apollo.URLSessionClient.URLSessionClientError error 2.) **2**\r\nWatch SyncManagerQuery // But hey it is trying once again \r\nWatch SyncManagerQuery success // And this time we've got a success.\r\n```\r\n\r\n**Question 2:** - Fetch result had no changes at all. It was exactly the same. Is watcher reacting to just cache update or is it verifying actual changes?\r\n**Question 3:** - Why it fails? And the retry is normal behavior after failure or is it a side effect of sth else?\r\n\r\n\r\nOk let's start over again. Exactly same conditions. We already have cache.\r\n```\r\n\r\nisReachable true //We've got internet\r\nOptional() //We've got user\r\nFetch Sync FETCH //Starting fetch\r\nWatch SyncManagerQuery \r\nWatch SyncManagerQuery success //Watching cache successful\r\nSync Fetch success //Fetching data successful, cache is being refreshed\r\nWatch SyncManagerQuery //And this is probably triggering watch \r\nWatch SyncManagerQuery success //Watch is successful\r\nWatch SyncManagerQuery //**1** But what is happening? Why it is triggering once again?\r\nWatch SyncManagerQuery success\r\n\r\n```\r\n**Question 4:** - why my watch query seems to be triggering twice after fetch? ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! I renumbered your questions so it would be clearer which one i'm responding to once I get more information here. Some things that would be helpful to understand: \r\n\r\n- Are you using the SQLite cache or the in-memory cache? \r\n- In the second code block (just before question 1), you are still running the watcher which was started in the first code block, and that's what you're expecting to get hit when you've added \"But nothing is happening\", correct?\r\n- After Question 1, you say \"close the application and start again\" - do you mean that you just exit the application then go back into it, or that you force-quit the application? \r\n- For the 3rd and 4th sets of logs, are you specifying a cache policy or using the default `.returnCacheDataElseFetch`? \r\n- Where in the application lifecycle are you setting up your watcher? Is it possible that the watcher could be getting set up multiple times? \r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"1. SQLite cache\r\n2. That is the same app session. So yeah watcher is still up and running.\r\n3. Reset the application. New session. SQLite cache already exists. Just wanted to check how watcher is going to act with existing cache and initializing once again.\r\n4. Watch is always using returnCacheDataDontFetch, fetch is alwasy using fetchIgnoringCacheData\r\n5. Not possible in that case. My AppDelegate is starting the whole FlowControlAgent which is Singleton here.\r\n\r\nAll problems seems to be similar to \"cold start\" problem described here \r\nhttps://github.com/apollographql/apollo-ios/issues/99 \r\n","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"Yeah, this from @martijnwalraven in #99 definitely seems to explain why your first watcher isn't called:\r\n\r\n> Because your watch uses `.returnCacheDataDontFetch`, and the cache is initially empty, it will never get a valid response in that case.\r\n\r\nIs there a chance you could send me a small repro project? I should at least be able to try to figure out why the `watch` is getting called twice, but it'd be pretty hard to do without something to debug. You can email it to ellen at apollographql dot com. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'll do my best to prepare some sample however now I'm out of time. Hopefully will send you sth around weekend. \r\nRight now, well, I can live with double watcher :) ","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"@pgawlowski Were you ever able to get a sample together? If not, do you mind if we close this issue out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hey @designatednerd \r\n\r\nSorry for not providing my sample code. It's still on my personal ToDo however I am totally sucked into other work. Let's close this issue right now. Hope I will provide some sample that will be helpful to validate this issue in some time - maybe during my vacations :) \r\n\r\nThanks for everything!","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}}]}},{"__typename":"Issue","title":"Cache and queries, unable to fetch record by ID.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null},"body":"So let's start with sth like this. Fetch and cache using SQLite normalized cache.\r\n```\r\nquery Sync {\r\n\tviewer {\r\n\t\tthings {\r\n\t\t\tnodes {\r\n\t\t\t\tid\r\n }\r\n }\r\n }\r\n}\r\n\r\n```\r\nHere is our cacheKeyForObject\r\n\r\n ```\r\n client.cacheKeyForObject = { (object) in\r\n if\r\n let id = object[\"id\"] as? String,\r\n let type = object[\"__typename\"] as? String {\r\n return [id, type]\r\n }\r\n // No id or typename, don't do caching\r\n return nil\r\n } \r\n\r\n```\r\nI also tried the basic one \r\n`client.cacheKeyForObject = { $0[\"id\"] }`\r\n\r\nWe've got (or at least out backend claims that we've got) unique ID's.\r\nNext I want to perform query with cachePolicy: `.returnCacheDataDontFetch`.\r\n\r\n```\r\nquery ThingActionConnection($thingId: ID!) {\r\n thing: node(id: $thingId) {\r\n ...on Thing {\r\n id\r\n }\r\n }\r\n} \r\n```\r\n\r\nResult is `GraphQLResultError(path: thing, underlying: Apollo.JSONDecodingError.missingValue)`\r\nThe more I dig down into apollo and caching the less I know how exactly this supposed to work. \r\n\r\nNetwork call is giving us correct results. What is more I checked local sqliteDB and there is a results with this particular `$thingId`. \r\n\r\nAndroid developer is getting results with ease. On our side, JSONDecodingError. \r\nI am nearly 100% sure that the problem is with cacheKeyForObject or ios apollo is unable to handle nodes here?\r\n\r\n@edit\r\nSame goes for \r\n```\r\n\r\nquery ThingActionTest($thingId: ID!) {\r\n viewer {\r\n thing(id: $thingId) {\r\n id\r\n }\r\n }\r\n}\r\n\r\n```\r\n\r\n@edit 2:\r\n\r\nInteresting fact is - direct cache access with same id works totally fine.\r\n\r\n```\r\n apolloClient.store.withinReadTransaction({ transaction in\r\n do {\r\n let variables = [\"isReady\": false]\r\n let data = try transaction.readObject(ofType: ThingAction.self, withKey: actionId, variables: variables)\r\n print(data)\r\n } catch {\r\n print(error.localizedDescription)\r\n }\r\n })\r\n```\r\nThis is only giving me more confusion about query execution on cache.\r\n\r\nI also noticed that direct cache access using query is giving me some confusing error.\r\n`Error at path \"thing)\": missingValue`\r\nWhy it is printing ')' character there? \r\n@edit ok it's just a typo in GraphqlExecutor.swift line 36.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"> The more I dig down into apollo and caching the less I know how exactly this supposed to work.\r\n\r\nWelcome to my last year, my friend 🙃. And also to why I'm planning to simplify a bunch of stuff in the Cache as part of phases 2-3 of the swift codegen rewrite if it's at all possible.\r\n\r\nI can tell you for sure that iOS and Android have no cache compatibility guarantees right now, and that I *think* the issue is that you're using a fragment on a node, and that you don't have the `id` on the node itself - that means that the node won't have an ID, and it won't go into the cache. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I finally figured it out. The problem was missing variables. \r\n\r\nHowever what I noticed is that sometimes when I am asking for data one by one I am getting\r\n`GraphQLResultError(path: lock.id, underlying: Apollo.JSONDecodingError.missingValue)` without any particular reason. Because starting exactly the same `withinReadTransaction` few seconds later is giving me correct response.\r\n","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"Is it giving you that error maybe because the data has not yet been populated? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Data is populated. \r\nI am executing exactly the same load and it can give a results like:\r\n\"I've got data.\"\r\n\"I've got data.\"\r\n\"I've got data.\"\r\nGraphQLResultError(path: lock.id, underlying: Apollo.JSONDecodingError.missingValue)\r\nGraphQLResultError(path: lock.id, underlying: Apollo.JSONDecodingError.missingValue)\r\n\"I've got data.\"\r\n\r\nNo fetching or repopulating cache in between.\r\nUser is offline and no cache manupulations are happening. I just wondered if there is a chance of some sort data access race here?\r\n\r\nI digged down ino the sql file and found that when I am getting this error the reference ID of one object is missing and right after getting data back there is a new one, different than previous (before missing value) one.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}},{"__typename":"IssueComment","body":"There is definitely a possibility of a data race, there are some known issues with threading in the cache at the moment.\r\n\r\nI'd really need to see your exact code to figure out what's going on with your references - the reference ID should be stable, but any number of things could be happening here to mess that up. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@pgawlowski Were you ever able to resolve this issue? Anything I can do to help here or do you mind if I close this out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hey @designatednerd \r\nActually yes. The main problem was old cache + messed id's. \r\nThank you for your help.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null}}]}},{"__typename":"Issue","title":"How to download schema.json with apollo client for an endpoint with url params and multi headers?","author":{"__typename":"User","login":"XiaoxiaYao","id":"MDQ6VXNlcjIyODk5MDk2","name":"MichaelYao"},"body":"Hi,\r\n\r\nI am trying to download a schema.json file from an endpoint. However, I don't know how to config the the url params and multi headers? Please check the pic below:\r\n![image](https://user-images.githubusercontent.com/22899096/89851786-e5de2980-dbbf-11ea-9a36-1c3499af4dc2.png)\r\nI am able to use graphql in graphiql. But don't know how to config in terminal. I tried:\r\n`apollo client:download-schema --endpoint=https://xxxxxxxxxxx/graphql/ --header='xxxxx-API-Key:xxxx;xxxxx-k:xxxxxx' --data='co=US'`\r\nHowever still no luck. Can anyone help me with this? I did not any doc about this ...so I am here. I don't know how to specify co=US and how to separate the headers with ,(comma) or ; (semi comma) Thank you in advance. Thanks.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! Each header must be passed in separately like so: `--header=\"Header-Key: Header Value\" --header=\"Header-Key-2: Header Value 2\"`\r\n\r\nThere is also a way to set this up using the [Swift Scripting lib](https://www.apollographql.com/docs/ios/swift-scripting) using the [`ApolloSchemaDownloader`](https://www.apollographql.com/docs/ios/swift-scripting/#downloading-a-schema). ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> Hi! Each header must be passed in separately like so: `--header=\"Header-Key: Header Value\" --header=\"Header-Key-2: Header Value 2\"`\r\n> \r\n> There is also a way to set this up using the [Swift Scripting lib](https://www.apollographql.com/docs/ios/swift-scripting) using the [`ApolloSchemaDownloader`](https://www.apollographql.com/docs/ios/swift-scripting/#downloading-a-schema).\r\n\r\nThank you. Sorry, one more thing. Do you know how to deal with url params? co=US? How should I set it?","author":{"__typename":"User","login":"XiaoxiaYao","id":"MDQ6VXNlcjIyODk5MDk2","name":"MichaelYao"}},{"__typename":"IssueComment","body":"URL params should just be the same as a normal URL - `https://example.com?paramName=paramValue¶m2name=param2Value`","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Cool. I will have a try. Thank you @designatednerd. Have a nice day!","author":{"__typename":"User","login":"XiaoxiaYao","id":"MDQ6VXNlcjIyODk5MDk2","name":"MichaelYao"}},{"__typename":"IssueComment","body":"@XiaoxiaYao Mind if we close this issue out then? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'm gonna close this out - @XiaoxiaYao if you have further problems please reopen. Anyone else experiencing similar problems, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Changing converting logic for custom objects","author":{"__typename":"User","login":"Shiaulis","id":"MDQ6VXNlcjEzNjAxNzQ4","name":"Andrius Shiaulis"},"body":"Hey awesome Apollo team. I have a question related to custom scalar objects.\r\nWe are moving towards using GraphQL and I'm trying to adapt it for our requests. The problem occurs whenever I'm trying to convert custom objects from our response.\r\nOur backend is using `JSON` type for legacy information. Codegen is trying to convert it to a string:\r\n![image](https://user-images.githubusercontent.com/13601748/90020057-f8d42500-dcb7-11ea-8132-dc3b28699b36.png)\r\n\r\nIs there any way to specify that we don't want that object to be converted to a string?\r\nFor now I know only one solution: pass `--passthroughCustomScalars` key, but the downside of this approach is that I need to create global typealias or type for with `JSON` name for the whole project. Is there any way to not convert the object at all so it can convert ANY type or some more specific name like `ApolloJSON` so in that case name would be more specific?\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Okay I found codegen Readme file :) At least I can make prefix for custom scalars by passing it with codegen option:\r\n```\r\n--customScalarsPrefix=\"Apollo\"\r\n```","author":{"__typename":"User","login":"Shiaulis","id":"MDQ6VXNlcjEzNjAxNzQ4","name":"Andrius Shiaulis"}},{"__typename":"IssueComment","body":"Yep, there's also a `namespace` option that wraps all your stuff in a big `enum` to namespace it. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"HTTPNetworkTransport's URLSessionClient possible [ lost calls / memory leak ]","author":{"__typename":"User","login":"EggYoke","id":"MDQ6VXNlcjY5NjM3NTc4","name":null},"body":"Hi team!\r\nFirst of all, thanks for an awesome framework that makes the lives of so many of us that much easier 😄\r\n\r\nWe have run into a [lost calls / memory leak] issue.\r\nWe believe it is closely linked to issue https://github.com/apollographql/apollo-ios/issues/1292.\r\n\r\n### SETUP\r\nDependency manager: SPM\r\nApollo-iOS version: 0.30.0\r\nSetup: Instanced (not a Singleton)\r\n\r\nAlso we provide a `URLSessionClient` that runs on a background callbackQueue to the `HTTPNetworkTransport`:\r\n```\r\nURLSessionClient(\r\n sessionConfiguration: URLSessionConfiguration.background(withIdentifier: \"background\"),\r\n callbackQueue: .some(operation)\r\n)\r\n```\r\n\r\n### INTENDED OUTCOME\r\nWe expect that the calls of all instanced ApolloClients return successfully.\r\nWe also expect that ApolloClients that are not retained in our code get deallocated from the system memory.\r\n\r\n### ACTUAL OUTCOME\r\nWe first noticed that for some reason, new instances of `ApolloClient` (those created after the first instance is not retained in our code anymore) never return from their calls This has made us notice that the created `URLSessionClient`s, `HTTPNetworkTransport`s and `ApolloClient`s are never deallocated properly causing a memory leak.\r\n\r\n### REPRODUCTION STEPS\r\n1 - Make a call with the setup described above.\r\n2 - Remove the retained instance of the ApolloClient.\r\n3 - Create a new ApolloClient and make a new call.\r\n4 - Call does not come back / memory leak occurs.\r\n5 - Repeat from step 2 to create a new unwanted retained instance of `URLSessionClient`, `HTTPNetworkTransport` and `ApolloClient`.\r\n\r\n### OUR CONCLUSIONS\r\nThis part should be taken with a grain of salt as we are not Apollo experts. That said, it is the only conclusion that survived our tests. Having found this https://stackoverflow.com/questions/62612056/why-dispatchqueue-global-still-alive-after-deinit on StackOverflow, we think that the problem stems from the queue keeping alive the instance of the `URLSession` created in `URLSessionClient` in some fashion.\r\n\r\nThis causes multiple retains climbing up the dependence graph of:\r\n- URLSession\r\n- URLSessionClient\r\n- HTTPNetworkTransport\r\n- ApolloClient\r\n- Objects in our code that calls ApolloClient ...\r\n\r\n### OUR SOLUTION\r\nAdding the following to `HTTPNetworkTransport` fixes both our issues:\r\n```\r\ndeinit {\r\n self.client.session.invalidateAndCancel()\r\n}\r\n```\r\n\r\nWe understand that this is most probably not the solution you will want to implement but it might help as a starting point to formulate something that will not jeopardize others that use your framework.\r\n\r\n### OUR INVESTIGATION\r\nIt should be said that we took the liberty to try this as there was code in the `URLSessionClient` for `deinit` that clears all tasks. We surmised that clearing the tasks in that situation did not cause a problem for calls in progress, meaning that clients of the framework should not expect the calls to complete if they stop holding their instance of `ApolloClient`.\r\n\r\nBut we noticed that the `deinit` in the `URLSessionClient` was never called even when its parent `HTTPNetworkTransport` `deinit` was called. We then noticed that the `HTTPNetworkTransport` was never deallocated even though its `deinit` was called.\r\n\r\nThat made us realize that something further down the line was probably holding things recursively. Implementing our solution, everything gets deallocated and for some reason, further ApolloClients return their calls successfully.\r\n\r\n### CONCLUSION\r\nAdvice on how to go forward from here would be greatly appreciated.\r\nThanks in advance for your help. We stand ready to answer any of your questions should you have some.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! Thanks for the extremely detailed report. Very, very odd that `deinit` would get called without the `HTTPNetworkTransport` actually being deallocated - usually the telltale sign of a memory leak is that `deinit` never gets called at all. \r\n\r\nIs this only happening with background sessions, or is it also happening with normal sessions? Or are you using a background configuration for all sessions? \r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi again!\r\n\r\nTo answer your question, we are using a background configuration for all sessions. As for normal sessions, we do see some memory leaks but they do not impede calls. Maybe the following will be useful.\r\n\r\nWe tried many configurations, mainly:\r\n- not using a URLSessionClient\r\n- using a URLSessionClient with a `.background` configuration and a callbackQueue `.main`\r\n- using a URLSessionClient with a `.background` configuration and a callbackQueue `.some`\r\n\r\nOnly the configuration of `.background` with a callbackQueue `.some` is suitable for us. Otherwise, some computations happen on the main thread when Apollo decodes our objects which brings the application to a crawl. (This is probably due to a specific situation in our code).\r\n\r\n### OUR TESTS\r\nHere are our results with those configurations in both instance setup and singleton setup. The main things we got out of it are that with an instance setup:\r\n- Calls do not come back if we provide a URLSessionClient\r\n- We always see URLSessionClients being kept in memory. In instruments, some are identified as leaks, some are not.\r\n\r\nWe hope this is clear and it did not confuse you to what's happening. As always, we are here if you need more info 😃.\r\n\r\nNo URLSessionClient\r\n---\r\n\r\n#### Instance\r\n✅ Calls come back\r\n✅ Does not retain objects holding ApolloClient instance in our code\r\n🛑 Retain orphaned UrlSessionClients and shows a leak in instruments\r\n\r\n#### Singleton\r\n✅ Calls come back\r\n✅ Does not retain objects holding ApolloClient instance in our code\r\n✅ Does not retain orphaned UrlSessionClients\r\n\r\n\r\nURLSessionClient with callback queue .main\r\n---\r\n\r\n#### Instance\r\n🛑 Calls do not come back\r\n🛑 Retains objects holding ApolloClient instance in our code\r\n🛑 Retains orphaned UrlSessionClients but does not show a leak in instruments\r\n\r\n#### Singleton\r\n✅ Calls come back\r\n✅ Does not retain objects holding ApolloClient instance in our code\r\n✅ Does not retain orphaned UrlSessionClients\r\n\r\n\r\nURLSessionClient with callback queue .some\r\n---\r\n\r\n#### Instance\r\n🛑 Calls do not come back\r\n🛑 Retains objects holding ApolloClient instance in our code\r\n🛑 Retains orphaned UrlSessionClients but does not show a leak in instruments\r\n\r\n#### Singleton\r\n✅ Calls come back\r\n✅ Does not retain objects holding ApolloClient instance in our code\r\n✅ Does not retain orphaned UrlSessionClients","author":{"__typename":"User","login":"EggYoke","id":"MDQ6VXNlcjY5NjM3NTc4","name":null}},{"__typename":"IssueComment","body":"I'm going to take a look deeper at this on Monday but one thing to be aware of is that there is no such thing as \"No `URLSessionClient` - a default one will be created for you if you're using `HTTPNetworkTransport`. It uses `.main` as its default queue, so I'm not sure what would be different between that and passing in your own. \r\n\r\nAdditionally: How are you setting up the instances? Is it possible that ARC is clobbering them because they are not properly retained somewhere and one of the assorted `weak self` calls winds up being nil? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks!\r\n\r\nFor the `URLSessionClient`, we figured that one was created on the Apollo framework side if not provided. Seeing the disparity in behaviour, we thought of sending you our observations on that as well. Maybe the difference between providing ours compared to the one by default is that we always put a `URLSessionConfiguration.background` instead of the `.default` one provided by Apollo.\r\n\r\nAs for how we retain instances, if you are talking about the `URLSessionClient`, we create it and give it to the `HTTPNetworkTransport`. It is all done in the same method and we do not retain either the `URLSessionClient` or the `HTTPNetworkTransport`. If you are talking about the `ApolloClient`, we tested swapping the `ApolloClient` for a mock that implements the same methods. We see no retain on our side.","author":{"__typename":"User","login":"EggYoke","id":"MDQ6VXNlcjY5NjM3NTc4","name":null}},{"__typename":"IssueComment","body":"So where do you retain the `ApolloClient` which you've handed the `HTTPNetworkTransport` to? Basically, I have a suspicion that the whole stack is getting hammered by ARC before the call returns if the instance is not being held onto somewhere. That would explain why in the `Instance` case listed above calls don't come back.\r\n\r\nAgain, if you have some sample code to share, that would be most helpful.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"The `ApolloClient` is retained by a **repo** object. When the object is instantiated it is injected with a new `ApolloClient` instance and uses it to make its calls.\r\n\r\nThe first time a user navigates to where a call is needed, we create a repo and start a call, it comes back correctly. The second time a user navigates to where a call is needed, we create a new repo and start a call, it never comes back. We keep those instances alive until they are not needed anymore or the user navigates away. In any case, when we create the second `ApolloClient` instance, nothing returns from the call even if held for over 10 minutes.\r\n\r\nI was able to confirm that calls not coming back happens if we provide a `URLSessionConfiguration` that is `.background`.\r\n\r\nAlso, sorry about the late notice but in debug environment, if we provide a `URLSessionConfiguration` that is `.background`, we often hit line 225 of the `URLSessionClient`:\r\n`assertionFailure(\"No data found for task \\(dataTask.taskIdentifier), cannot append received data\")`\r\n","author":{"__typename":"User","login":"EggYoke","id":"MDQ6VXNlcjY5NjM3NTc4","name":null}},{"__typename":"IssueComment","body":"I was able to replicate easily with the iOSTutorial project. What is the easiest way to send you that project amended to reproduce?","author":{"__typename":"User","login":"EggYoke","id":"MDQ6VXNlcjY5NjM3NTc4","name":null}},{"__typename":"IssueComment","body":"Email! ellen at apollographql dot com. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@EggYoke The sample you sent was very helpful, thank you. The underlying problem was a retain cycle as outlined in #1366. \r\n\r\nThe secondary problem is that you're attempting to create multiple background sessions with the same identifier at the same time, which the system won't let you do. I found that after the changes in #1366 were applied, I was able to get things to work with a background session by just using `UUID().uuidString` as the identifier, as this prevents any collisions in session name. \r\n\r\nHonestly, I wouldn't really recommend using background sessions for everything as it's kind of overkill, but if you need to for reasons I'm missing, that should at least unblock you.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"This has shipped with `0.31.0` - if you're still having issues with that version, please open a new issue and we'll try to figure it out. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thank you very much for the fast response.\r\nOur calls come back successfully and none of our objects are retained anymore.\r\nThis fixed all our issues, awesome job! 👍 ","author":{"__typename":"User","login":"EggYoke","id":"MDQ6VXNlcjY5NjM3NTc4","name":null}}]}},{"__typename":"Issue","title":"Cannot load underlying module for 'Apollo' for unit test target","author":{"__typename":"User","login":"dpatel-git","id":"MDQ6VXNlcjY4NDM2NTk1","name":null},"body":"Hello folks,\r\n\r\nI have following setup.\r\n\r\nXcode 11.3.1 (also tried on 11.6 without success)\r\nApollo 0.29.1\r\nCocoapods 1.9.2\r\n\r\nI am able to compile and run my application, but get the following error when I try to compile the unit test target\r\n\r\n```:0: error: cannot load underlying module for 'Apollo'```\r\n\r\nHere is how I have declared the app and test targets in podfile\r\n\r\n```\r\ntarget 'MyApp' do\r\n pod 'Apollo', Apollo\r\n target 'MyAppTests' do\r\n pod 'OHHTTPStubs', OHHTTPStubs\r\n end\r\nend\r\n```\r\nI have set `MyApp` as host application for the test target\r\n\r\nAny help is appreciated, thanks\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"It looks like your `MyAppTests` is missing an `inherit! :search_paths`. See the 2nd example [in the Podfile docs](https://guides.cocoapods.org/using/the-podfile.html). ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks, that fixed the issue.","author":{"__typename":"User","login":"dpatel-git","id":"MDQ6VXNlcjY4NDM2NTk1","name":null}}]}},{"__typename":"Issue","title":"GraphQLQueryWatcher doesn't update its dependent keys","author":{"__typename":"User","login":"teodorpenkov","id":"MDQ6VXNlcjU2MjIyODg=","name":"Teodor Penkov"},"body":"With the `0.23.0` release Apollo changed the way it stores keys in the `QueryWatcher` https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/GraphQLQueryWatcher.swift#L73-L83\r\n\r\nThe problem with this is that the watcher doesn't update its `dependentKeys` like it should. There is a commit that does that but I couldn't follow why it was changed:\r\nhttps://github.com/apollographql/apollo-ios/commit/2b07e69e71a0621795b7089fda84c0ca744ba202\r\n\r\nThe problem that we are experiencing is that we are updating a query in the store with `ReadWriteTransaction` and in the previous versions the updated query captured the newly dependent keys, therefore when a change occured it was propagated to the result handler and now it's not.\r\n\r\nWhat's the reason behind this change and how can we workaround this? Was there a problem with the previous implementation in 0.22.0 https://github.com/apollographql/apollo-ios/blob/0.22.0/Sources/Apollo/GraphQLQueryWatcher.swift#L66-L68","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi, the commit you referenced was part of #1156 which went out with `0.28.0`, not `0.23.0`. You can see a detailed explanation of the bug in #1155. \r\n\r\nWhat version are you actually on right now? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"hey @designatednerd thanks for reaching out.\r\n\r\nI'm using `0.28.0` but I think the problem that I experience is on every version after `0.23.0`.\r\n\r\nOur use case is pagination using the Apollo cache.\r\nWe are doing one `main` query followed by 0 or more `fetch more` queries (based on page info and scroll events) each `fetch more` query updates the main one with its nodes and page info. We've been using this method for a while and it worked pretty well, the reason for that is that the \"main\" query was updating its dependent keys (the nodes from the fetch more queries) and after the commits I mentioned it stopped working.\r\n\r\nMutation values gets to the store correctly but after `didChangeKeys` gets called this results in a watcher's result handler being called with the old values rather than the updated values from the mutation.\r\n\r\nI will run through the commits and PR's that you mentioned and will try to figure out what the problem with the previous behavior was.","author":{"__typename":"User","login":"teodorpenkov","id":"MDQ6VXNlcjU2MjIyODg=","name":"Teodor Penkov"}},{"__typename":"IssueComment","body":"So I know some stuff changed around `0.22.0` that was the motivation for these changes that went out with `0.28.0`, but otherwise I'm not really seeing anything that changed. If you have any suggestions or a PR, I'm more than happy to try them out!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'd either suggest reverting to `0.22.0`'s implementation https://github.com/apollographql/apollo-ios/blob/0.22.0/Sources/Apollo/GraphQLQueryWatcher.swift#L66-L68\r\n\r\nor adding `self.dependentKeys = graphQLresult.dependentKeys` before this line https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/GraphQLQueryWatcher.swift#L79\r\n\r\nIf you don't see problem with that I'm happy to open a PR.","author":{"__typename":"User","login":"teodorpenkov","id":"MDQ6VXNlcjU2MjIyODg=","name":"Teodor Penkov"}},{"__typename":"IssueComment","body":"@designatednerd thanks for the links that you shared. I've checked them and I found the root cause of the problem.\r\n\r\n\"Screen\r\n\r\nI'm pretty sure that if we bring back those lines it wouldn't break anything.","author":{"__typename":"User","login":"teodorpenkov","id":"MDQ6VXNlcjU2MjIyODg=","name":"Teodor Penkov"}},{"__typename":"IssueComment","body":"Hi! Sorry, I was on vacation last week. \r\n\r\nI read [your explanation](https://github.com/apollographql/apollo-ios/pull/1156#discussion_r476476875) here and I think I get it. I'll take a look at this today or tomorrow and see what I can figure out. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Primary Maintainer Out Of Office August 23-30","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"},"body":"I will be taking a break in a place that (not coincidentally) has terrible internet connectivity the week of August 24th. \r\n\r\nKeep opening issues and PRs while I'm out, but please be aware that they will not be addressed until August 31st or thereafter. Thank you for your patience!","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I'm back! ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Ambiguous for type lookup in this context error","author":{"__typename":"User","login":"Shiaulis","id":"MDQ6VXNlcjEzNjAxNzQ4","name":"Andrius Shiaulis"},"body":"Hey hey! Another question from my side :) \r\nIn our backend response contains 2 data fields `userCompanies` and `userCompany` that share type. \r\n![image](https://user-images.githubusercontent.com/13601748/90987179-b81abc80-e591-11ea-9e96-ded615f5630e.png)\r\nThe problem is that code generation creates 2 totally equal structures:\r\n![image](https://user-images.githubusercontent.com/13601748/90987269-573fb400-e592-11ea-8292-1a365a37b737.png)\r\n\r\nIn documentation explorer in GraphiQL I don't see any issues:\r\n![image](https://user-images.githubusercontent.com/13601748/90987304-9837c880-e592-11ea-9f5f-af004aa50ca8.png)\r\n\r\nSo should I still look for a fix on backend side? Is there any way to explain that these data fields share type?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Im getting the exact same problem.\r\n\r\n```swift\r\npublic struct Author: GraphQLSelectionSet {\r\n public static let possibleTypes: [String] = [\"Staff\", \"Customer\"]\r\npublic struct Author: GraphQLSelectionSet {\r\n public static let possibleTypes: [String] = [\"ArticleAuthor\"]\r\n```","author":{"__typename":"User","login":"kylebrowning","id":"MDQ6VXNlcjExMzAyMw==","name":"Kyle Browning"}},{"__typename":"IssueComment","body":"Yeah - this is where the depluralization for type names we're using in the typescript codegen kind of falls apart. The workaround is to use field aliases:\r\n\r\n```graphql\r\nquery MyQuery {\r\n user {\r\n id\r\n userCompany: company // <-- alias\r\n userCompanies\r\n }\r\n}\r\n```\r\n\r\nThis way what's called `userCompany` on your server will be called `company` locally, making the type for that property `Company` and the type for `userCompanies` will be `UserCompany`. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd, thanks for the clarification 👍 ","author":{"__typename":"User","login":"Shiaulis","id":"MDQ6VXNlcjEzNjAxNzQ4","name":"Andrius Shiaulis"}},{"__typename":"IssueComment","body":"@Shiaulis did that work? If so, can we close this out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Worked for us. ","author":{"__typename":"User","login":"kylebrowning","id":"MDQ6VXNlcjExMzAyMw==","name":"Kyle Browning"}},{"__typename":"IssueComment","body":"Thanks, let's close it","author":{"__typename":"User","login":"Shiaulis","id":"MDQ6VXNlcjEzNjAxNzQ4","name":"Andrius Shiaulis"}}]}},{"__typename":"Issue","title":"Error: Unable to read file › schema.json. ENOENT: no such file or directory, open 'schema.json'","author":{"__typename":"User","login":"fatma95","id":"MDQ6VXNlcjEyMTc1NDE3","name":"Fatma Mohamed"},"body":"I followed all the correct steps in the document, schema.json and graphql files are on the right places however I always get this error and build fails please help.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! So I'll need a bit more information to help diagnose this. Can you answer a few questions: \r\n\r\n- Have you confirmed that `schema.json` is downloaded and exists where you think it is on your filesystem? \r\n- Are you using the Swift Scripting wrapper or the shell script? \r\n- Can you paste a link to the set of instructions you are following? \r\n\r\nThank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi! I haven't heard back on this issue in over a week so I'm going to close it out - @fatma95 please reopen if you still need help, anyone else with a similar problem, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"No data found for task x, cannot append received data","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"},"body":"One of our tests hitting assert in `URLSessionClient.swift:230` in on CI after updating to latest version (0.31.0).\r\nIt's not networking stack test so don't think we doing anything specific to hit that assert. Looking at code that would indicate some kind race condition...","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Weird! Is it possible it's something leaking over from an older test? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"can't see anything relevant, also it don't happen every run","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"```swift\r\npublic func invalidate() {\r\n self.clearAllTasks()\r\n self.session?.invalidateAndCancel()\r\n self.session = nil\r\n }\r\n```\r\n\r\nshouldn't `self.session?.invalidateAndCancel()` be before `self.clearAllTasks()`? Will try change and see if our tests passes more reliably ","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"Hi! Yeah flipping the cleanup order likely wouldn't help since some tasks are still in-flight, I suspect I need to actually cancel all the in-flight tasks. Thanks for the heads up on this!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Haha damn it, looks like there's a key piece of info about `invalidateAndCancel` that's only in the docs docs and not in the headerdoc: \r\n\r\n\"Screen\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Shipped with version `0.32.1`!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi @designatednerd,\r\n\r\nI am encountering this issue in `0.33.0`, looking at #1383 I'm not quite certain it addressed the root issue given the shared `URLSession` isn't being used in `URLSessionClient`? I have a fairly reproducible case where this `invalidate` logic is getting hit but I'm still encountering this assertion error afterwards, confirmed with some debugging its definitely the same instance floating around. \r\n\r\nThat all said, it does seem that the issue is resolved by calling `invalidateAndCancel` prior to calling the `clear` block (as is currently done in the else branch). I've tested this quite a bit and have been unable to trigger the assertion failure anymore. I'll go ahead and open a PR for you to take a look, hopefully it helps!","author":{"__typename":"User","login":"philfi","id":"MDQ6VXNlcjM5NTY0NjE1","name":null}},{"__typename":"IssueComment","body":"Can confirm that it's not solved in 0.33.0. Just got assert while running tests on iOS12\r\n\r\n\"Screenshot\r\n","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"still happening in 0.36.0 (iOS12 simulator)","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}}]}},{"__typename":"Issue","title":"Crash at runtime when upgrading to 0.31.0 on URLSessionClient.swift, line 95","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"},"body":"Hey guys,\r\n\r\nSo I have an app that works perfectly with 0.30.0 but when upgrading to 0.31.0 I get a crash soon after the app launches:\r\n\r\n```\r\nFatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file /Users/XXX/Library/Developer/Xcode/DerivedData/XXX-bzyicfzsqzelixabxktyzmboxbaj/SourcePackages/checkouts/apollo-ios/Sources/Apollo/URLSessionClient.swift, line 95\r\n```\r\n\r\nThe issue is one this line :\r\n\r\n```\r\nlet task = self.session.dataTask(with: request)\r\n```\r\n\r\nhere `session` is nil.\r\n\r\nLet me know if you need anything else as I can reproduce the crash 100% of the time. Many thanks","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! That's awfully weird, since the session is instantiated in the initializer. Can you share the code you're using to create your client, as well as where in the app lifecycle that's happening? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Something that occurred to me is that in `0.31.0` we added a mechanism to make sure the `URLSession` is properly terminated so as not to create a retain cycle - you can probably throw a breakpoint in [here](https://github.com/apollographql/apollo-ios/blob/d95b4463f78a15fba7e3de2017817a391e9714f0/Sources/Apollo/URLSessionClient.swift#L63) to see if that's getting hit before you get to whatever's creating the data task.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hey @designatednerd !\r\n\r\nFirst, thank you very much for answering so quickly, appreciate it :)\r\n\r\nI think your guess of adding a breakpoint into the `invalidate` method of `URLSessionClient` was a good idea. It turns out that when our app starts, we are initializing an `HTTPNetworkTransport` to use into a `SplitNetworkTransport` without any authentication, and when we authenticate (a few seconds after the app starts) we replace that `HTTPNetworkTransport` with a new one, simply by dereferencing the old one and keeping a pointer on a new `SplitNetworkTransport` that contains this new client.\r\n\r\nI think that what may happen is that the first client may have started some work in background, and when it gets destroyed this work hasn't finished, leading to this crash as the `session` is already nil. Could that be possible? ","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"That's possible - I've added some code in #1383 that should cancel any inflight operations on a `URLSessionClient` when `invalidate()` gets called, but I'm not sure if it'll address this crash since it's happening before the task is even added, which means `invalidate` has probably been called on a different thread.\r\n\r\nDefinitely sounds like a race condition is happening here - out of curiosity why are you fully replacing the client rather than using one of the delegate methods to handle authentication?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd Just tested, still crashing.\r\n\r\nI'm not 100% sure why we are replacing the client as I'm not the one who wrote that code, but as far as I understand it's because we are using `SplitNetworkTransport` and we are recreating the websocket so we need to also recreate the http client.","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"From here, I see a couple of workaround options: \r\n\r\n- Hanging on to the instance of `HTTPNetworkTransport` and using that when you have to recreate the web socket rather than creating a fully new transport\r\n- Taking a look at recent changes to the web socket transport, particularly around disconnecting and reconnecting, and seeing if any of those will prevent you from having to recreate. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I took the first option which works, so ok for me now but I guess you still have a race condition somewhere. Thank you very much for your help","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"Yeah for sure - I'm going to have to dig deeper into this but a lot of things are changing with the updated networking stack, so I'd like to get that out before digging back into this.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@benoitletondor We've just shipped something that will allow you to delay starting the websocket after initialization, which in theory should allow you to not have to replace the `SplitNetworkClient`. Do you mind pulling `0.36.0` and letting me know if that gets you to where you need to be? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hey @designatednerd ,\r\n\r\nThank you for your help on that. Indeed, it would work for my use case as we can avoid starting the websocket until we have a proper authentication. As I said last time I already followed your advice of keeping the `HTTPNetworkTransport` instance so it's not really needed anymore on my side.\r\n\r\nThanks","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"@benoitletondor Do you mind if I close out this issue then? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Be my guest ;) ","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}}]}},{"__typename":"Issue","title":"ApolloCodegen.run does not throw error when validation of GraphQL query document fails","author":{"__typename":"User","login":"michaelxbarrett","id":"MDQ6VXNlcjMzODIyNjEz","name":null},"body":"From the tutorial:\r\n```\r\ndo {\r\n // Actually attempt to generate code.\r\n try ApolloCodegen.run(from: targetRootURL,\r\n with: cliFolderURL,\r\n options: codegenOptions)\r\n} catch {\r\n // This makes the error message in Xcode a lot more legible.\r\n exit(1)\r\n}\r\n```\r\n\r\nWhen there is an error in the query, the message `Validation of GraphQL query document failed` is logged and outputted to the console with a stacktrace, but no error is thrown in this case.\r\n\r\n\r\nStack trace:\r\n```\r\nValidation of GraphQL query document failed\r\n at Object.validateQueryDocument (Codegen/ApolloCLI/apollo/node_modules/apollo-language-server/lib/errors/validation.js:35:38)\r\n at Object.generate [as default] (Codegen/ApolloCLI/apollo/lib/generate.js:23:18)\r\n at write (Codegen/ApolloCLI/apollo/lib/commands/client/codegen.js:84:54)\r\n at Task.task (Codegen/ApolloCLI/apollo/lib/commands/client/codegen.js:104:46)\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"To clarify: Do you mean that the `exit(1)` is not called because no error is thrown from `run` itself, or that `exit(1)` does not constitute throwing an error? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Also, what version of the SDK are you using? I think there was an issue a couple versions back with our JS CLI where it wouldn't throw errors properly on failure, which should be resolved now.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@michaelxbarrett Were you able to address this by updating? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Since I haven't heard back in 3 weeks, I'm going to close this out. @michaelxbarrett Please reopen if you're still experiencing problems. Anyone else with similar problems, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Query watcher not being called when cache is updated on an element of a collection that is added after calling watch","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"},"body":"Hi everyone,\r\n\r\nI've been trying a lot of things on that one and wasn't able to find a way to fix my problem. So in my app I'm having a list of conversations, so I'm creating a `watch` on a query that returns the list of conversations, this is something like that:\r\n\r\n```\r\nuser {\r\n uuid\r\n firstName\r\n lastName\r\n conversations {\r\n uuid\r\n unreadMessagesCount\r\n }\r\n}\r\n```\r\n\r\n> In the app we use the `uuid` key to handle cache, so we make sure to always pass `uuid` in our queries to automatically handle cache update.\r\n\r\nSo the role of the watcher I'm talking about is both to update existing conversations and also be able to catch when a new conversation is created (it can happen and not be initiated by the user, we then trigger an event from the backend that is listen from a subscription in the app). When this event happens it returns something like that\r\n\r\n```\r\nevent {\r\n newConversation {\r\n conversation {\r\n uuid\r\n unreadMessagesCount\r\n // This is the part that adds the new conversation to the existing ones of the users in the cache\r\n user {\r\n uuid\r\n conversations {\r\n uuid\r\n unreadMessagesCount\r\n }\r\n } \r\n }\r\n }\r\n}\r\n```\r\n\r\nIt works great, meaning that when this event happens, the watcher is being called with the newly created conversation, but the issue is that any new cache update for that specific conversation doesn't trigger the watcher again.\r\n\r\nAfter investigating a bit, I realised that the cache is being updated because if I'm adding 3 new messages into the new conversation (setting the `unreadMessagesCount` to 3), the watcher doesn't get called but then if I add 1 new message into an old one, the watcher is being called with both the new message on the old conversation and the 3 new on the new one. \r\n\r\nSo it really seems like `watch` is not being called again for changes on an item that wasn't in a collection when the `watch` was initially made. I've also take a look at https://github.com/apollographql/apollo-ios/issues/281 and making a `fetch` on the same query again after the event doesn't fix the issue.\r\n\r\nLet me know if I'm not clear on something as the whole thing is a bit complicated to explain.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! Can you take a look at v0.32.0 - I fixed something in query watchers in terms of updating dependent keys that I *think* should help with this. If it doesn't, let me know. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hey @designatednerd \r\n\r\nSure, if #1377 is resolved too I will be able to test that tomorrow. If that's not the case I guess I won't be able","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"Hey @designatednerd \r\n\r\nI tested and I can confirm 0.32.0 fixes the issue, thank you very much for your help.","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"Reopening this one as the bug seems to be back with 0.34.0 :/ Let me know if you need help on my side","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"@designatednerd I haven't tested 0.33.0 so I'm not sure when the regression happened","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"That's odd, because the test added is passing - I actually spent quite a bit of time making it pass. 🙃 Do you mind opening a new issue with a link to this one since it's in a different version? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Sure","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}}]}},{"__typename":"Issue","title":"Availability of framework with Xcode 12 and iOS version 8","author":{"__typename":"User","login":"novinfard","id":"MDQ6VXNlcjYxMTYwNw==","name":"Soheil Novinfard"},"body":"Is it possible to use the framework with Xcode 12 and iOS version 8? Currently it asks me to upgrade to iOS version 9 with Xcode 12","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"iOS 9 is our minimum supported version regardless of Xcode version. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@novinfard Any further questions or do you mind if I close this issue out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Crash while checking graphQLResult with 0.32 and 0.32.1","author":{"__typename":"User","login":"jsm174","id":"MDQ6VXNlcjExOTcxMzc=","name":"Jason Millard"},"body":"Hello. Yesterday I upgraded to 0.32 and immediately started getting crashes anytime one of our services is checking a `graphQLResult`:\r\n\r\n```\r\ncase let .success(graphQLResult):\r\n```\r\n\r\nI downgraded to 0.31 and it started working again. I saw that 0.32.1 was released and figured I'd give it a try, but I'm seeing the same behavior.\r\n\r\nI know this isn't much to go on, but:\r\n\r\n![Screen Shot 2020-09-11 at 9 36 16 AM](https://user-images.githubusercontent.com/1197137/92932578-14476280-f413-11ea-9b8a-02df220cfcfd.png)\r\n\r\n(FWIW, that first preflight is just refreshing oauth tokens if necessary)\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"So, I apologize but I think it is working after all. \r\n\r\nI think maybe after I did a pod update, it never actually rebuilt apollo.\r\n\r\nI will close this. ","author":{"__typename":"User","login":"jsm174","id":"MDQ6VXNlcjExOTcxMzc=","name":"Jason Millard"}},{"__typename":"IssueComment","body":"No worries, that can definitely happen. Thanks for the update!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"codegen produces Swift code that doesn't compile","author":{"__typename":"User","login":"rlimberger","id":"MDQ6VXNlcjQ4NDEyNDI=","name":"Rene Limberger"},"body":"My scheme defines a GQL query named ```shipmentETAs``` and a type ```shipmentETA```. Codegen generates Swift code which incorrectly changes parts of the query and type name to lowercase. As a result, the Swift code generated by codegen doesn't compile.\r\n\r\nSchema:\r\n```\r\n {\r\n \"name\": \"shipmentETAs\",\r\n \"description\": \"\",\r\n \"args\": [\r\n {\r\n \"name\": \"params\",\r\n \"description\": \"\",\r\n \"type\": {\r\n \"kind\": \"NON_NULL\",\r\n \"name\": null,\r\n \"ofType\": {\r\n \"kind\": \"INPUT_OBJECT\",\r\n \"name\": \"QueryShipmentETAParams\",\r\n \"ofType\": null\r\n }\r\n },\r\n \"defaultValue\": null\r\n }\r\n ],\r\n \"type\": {\r\n \"kind\": \"NON_NULL\",\r\n \"name\": null,\r\n \"ofType\": {\r\n \"kind\": \"LIST\",\r\n \"name\": null,\r\n \"ofType\": {\r\n \"kind\": \"OBJECT\",\r\n \"name\": \"ShipmentETA\",\r\n \"ofType\": null\r\n }\r\n }\r\n },\r\n \"isDeprecated\": false,\r\n \"deprecationReason\": null\r\n }\r\n```\r\n\r\nResulting Swift code:\r\n```\r\n public var shipmentEtAs: [ShipmentEta?] {\r\n get {\r\n return (resultMap[\"shipmentETAs\"] as! [ResultMap?]).map { (value: ResultMap?) -> ShipmentEtA? in value.flatMap { (value: ResultMap) -> ShipmentEtA in ShipmentEtA(unsafeResultMap: value) } }\r\n }\r\n set {\r\n resultMap.updateValue(newValue.map { (value: ShipmentEtA?) -> ResultMap? in value.flatMap { (value: ShipmentEtA) -> ResultMap in value.resultMap } }, forKey: \"shipmentETAs\")\r\n }\r\n }\r\n\r\npublic struct ShipmentEta: GraphQLSelectionSet {\r\n...\r\n```\r\n\r\nCompiler error:\r\n`Cannot find type 'ShipmentEtA' in scope`\r\n\r\nSwift 5.3\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Urgh, this is one of the things I'm working on getting rid of with Swift Codegen - this is all handled under the hood in the Typescript codegen in a way that's really, really opaque. Unfortunately for now the only real way to work around it is to alias the name of the field to not have multiple uppercase characters in a row. \r\n\r\nI don't know your schema but here's a general stab at what I think an updated query would look like: \r\n\r\n```query\r\nquery ShipmentArrives($id: ID!) {\r\n shipment(id: $id) {\r\n id\r\n shipmentETA: shipmentEstimate\r\n }\r\n}\r\n```\r\n\r\nLet me know if that works!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks so much @designatednerd ! The alias worked! \r\n```\r\nquery ShipmentEstimates($siteId: ID!) {\r\n shipmentEstimates: shipmentETAs(params: {siteId: $siteId}) {\r\n ...\r\n }\r\n}\r\n```","author":{"__typename":"User","login":"rlimberger","id":"MDQ6VXNlcjQ4NDEyNDI=","name":"Rene Limberger"}},{"__typename":"IssueComment","body":"Woot! Mind if we close this out - I'm already tracking the casing stuff in other tickets. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Fix Apple Silicon on Xcode 12 GM","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"},"body":"Related to #1280. In testing for the Xcode 12 GM everything's working swimmingly via my Intel mac but the DTK is throwing fits that I can't seem to solve at the moment, mostly related to `unable to load standard library` issues. ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"OK well it turns out I am both less dumb than I originally thought for not being able to get this to work, _and_ dumber than I thought for not realizing I shouldn't download the GM on the DTK. \r\n\r\nThe Apple Silicon stuff was not included with the GM since that ships to the public, and AS stuff should still be using the beta track (still Xcode 12b6 for now, probably a 12.1 beta sometime soon). \r\n\r\nClosing this out since everything still works on the most recent version of Xcode to support Apple Silicon, 12.0b6. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Apollo 0.33.0 + Xcode 11.7. Use of unknown directive '#filePath'.","author":{"__typename":"User","login":"Hazeaze","id":"MDQ6VXNlcjgzNTE4NzQ=","name":null},"body":"Hi.\r\nI use SPM for the third-party libraries, updated Apollo from 0.32.1 to 0.33.0, and on the app build, I faced with the problem in the `FileFinder.swift`, where received an error `Use of unknown directive '#filePath'`.\r\n\r\n![image](https://user-images.githubusercontent.com/8351874/93308812-91fcdb00-f824-11ea-9050-275be2b39282.png)\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I got the same error","author":{"__typename":"User","login":"Parilar","id":"MDQ6VXNlcjgxNTk2NDY=","name":"Lars Hallek"}},{"__typename":"IssueComment","body":"`#filePath` is new in Swift 5.3, which ships with Xcode 12. You will need to use Xcode 12 for versions `0.33.0` and higher.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'm going to close this out since this is intended behavior. Enjoy Xcode 12!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Exclude Apollo Playground from the main project file to make Carthage faster","author":{"__typename":"User","login":"manicmaniac","id":"MDQ6VXNlcjE2NzIzOTM=","name":"Ryosuke Ito"},"body":"Apollo Playground, which introduced in Apollo 0.33.0 as [a scheme in Apollo.xcoderpoj](https://github.com/apollographql/apollo-ios/blob/0.33.0/Apollo.xcodeproj/xcshareddata/xcschemes/Apollo%20Playground.xcscheme), makes Carthage build slower, and to make matters worse, building Apollo Playground fails in Xcode older than 12 (https://github.com/apollographql/apollo-ios/issues/1391).\r\n\r\nI guess most Apollo users don't want to build Apollo Playground at the time they install dependencies.\r\nHowever, Carthage doesn't provide a convenient way to exclude a specific scheme as discussed in https://github.com/Carthage/Carthage/issues/2529.\r\n\r\nSo to solve this problem, could you exclude Apollo Playground scheme from Apollo.xcodeproj and move it to another xcodeproj or another repo?\r\n\r\n```sh\r\n$ carthage bootstrap --platform iOS --no-use-binaries --cache-builds\r\n*** Checking out ApolloDeveloperKit at \"ce9fd3e1c75c074ae77632a8fe21be635219401b\"\r\n*** Checking out apollo-ios at \"0.33.0\"\r\n*** No cache found for apollo-ios, building with all downstream dependencies\r\n*** xcodebuild output can be found in /var/folders/tm/wy8sj46s6yq4rlfgsxyvd1l80000gn/T/carthage-xcodebuild.Plidos.log\r\n*** Building scheme \"Apollo\" in Apollo.xcodeproj\r\n*** Building scheme \"ApolloCore\" in Apollo.xcodeproj\r\n*** Building scheme \"Apollo Playground\" in Apollo.xcodeproj\r\nld Failed\r\n Task failed with exit code 65:\r\n /usr/bin/xcrun xcodebuild -project /Users/manicmaniac/Projects/manicmaniac/ApolloDeveloperKit/InstallTests/Carthage/Checkouts/apollo-ios/Apollo.xcodeproj -scheme Apollo\\ Playground -configuration Release -derivedDataPath /Users/manicmaniac/Library/Caches/org.carthage.CarthageKit/DerivedData/11.5_11E608c/apollo-ios/0.33.0 -sdk iphoneos ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES archive -archivePath /var/folders/tm/wy8sj46s6yq4rlfgsxyvd1l80000gn/T/apollo-ios SKIP_INSTALL=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=NO CLANG_ENABLE_CODE_COVERAGE=NO STRIP_INSTALLED_PRODUCT=NO (launched in /Users/manicmaniac/Projects/manicmaniac/ApolloDeveloperKit/InstallTests/Carthage/Checkouts/apollo-ios)\r\n\r\nThis usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/tm/wy8sj46s6yq4rlfgsxyvd1l80000gn/T/carthage-xcodebuild.Plidos.log\r\nmake: *** [carthage] Error 1\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Have you tried using the [`carthage-build-workaround` script outlined in the release notes?](https://github.com/apollographql/apollo-ios/releases/tag/0.33.0) There's some other nonsense going on with Carthage that I think may be causing the build failures rather than this scheme. \r\n\r\nAs for time reduction, the problem is that if that scheme isn't shared, the playgrounds won't build because it needs different sub-libraries than any of the other schemes. \r\n\r\nI can't for the life of me figure out why Carthage is so against excluding schemes. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> Have you tried using the carthage-build-workaround script outlined in the release notes?\r\n\r\nAh, my bad 😓 \r\nWith the workaround script and Xcode 12, I confirmed it works.\r\n\r\n```sh\r\n$ ./carthage-build-workaround.sh\r\n/tmp/static.xcconfig.hvN4SB\r\n*** Fetching apollo-ios\r\n*** Checking out apollo-ios at \"0.33.0\"\r\n*** xcodebuild output can be found in /var/folders/tm/wy8sj46s6yq4rlfgsxyvd1l80000gn/T/carthage-xcodebuild.6GUdYX.log\r\n*** Building scheme \"Apollo\" in Apollo.xcodeproj\r\n*** Building scheme \"ApolloCodegenLib\" in Apollo.xcodeproj\r\n*** Building scheme \"Apollo Playground\" in Apollo.xcodeproj\r\n*** Building scheme \"ApolloSQLite\" in Apollo.xcodeproj\r\n*** Building scheme \"ApolloCore\" in Apollo.xcodeproj\r\n*** Building scheme \"ApolloWebSocket\" in Apollo.xcodeproj\r\n```","author":{"__typename":"User","login":"manicmaniac","id":"MDQ6VXNlcjE2NzIzOTM=","name":"Ryosuke Ito"}},{"__typename":"IssueComment","body":"Cool - do you mind if we close this out with the answer as \"No\" for removing the `Apollo Playground` scheme? I understand it's inconvenient, but it's not inconvenient that often. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yes, let me close this issue and thank you very much for your support 👍 ","author":{"__typename":"User","login":"manicmaniac","id":"MDQ6VXNlcjE2NzIzOTM=","name":"Ryosuke Ito"}}]}},{"__typename":"Issue","title":"Looking for recommendation for Pagination + Watching flow","author":{"__typename":"User","login":"bharath2020","id":"MDQ6VXNlcjkwMzUzNg==","name":null},"body":"_(Have this question [posted ](https://spectrum.chat/apollo/apollo-ios/looking-for-recommendation-to-perform-pagination-watch-in-ios-and-android-clients~a15afb8b-21fb-49a6-a80c-dd2ef097c8ad) in Spectrum chat as well, Adding here for better reach. Apologize for noise.)_\r\n\r\n# Problem\r\n\r\nWe have done some experiments in adopting pagination and encountered a few issues. I am looking for a recommendation on how to extract paginated results that do achieve two of my main goals. For the context, we have a mobile application that has screens that show paginated content that allows infinite vertical scrolling.\r\n\r\n1. Perform pagination in a responsible manner without any lag on the UI\r\n2. Ability to watch any changes to the items retrieved across all pages\r\n\r\nFor example, assume the following schema\r\n\r\n```\r\ntype PageResult {\r\n cursor: String\r\n hasMore: Bool\r\n items: [String]\r\n}\r\nquery {\r\n getItems(cursor: String): PageResult\r\n}\r\n```\r\n\r\nHere are the approaches we tried:\r\n\r\n## Approach 1: Follow the suggestion as per the [Apollo iOS tutorial blog](https://www.apollographql.com/docs/ios/tutorial/tutorial-pagination/)\r\n\r\n1. Load the first page with no cursor with cache policy that writes data back to the cache\r\n2. Load the second page with the cursor and follow the same for the next pages with cache policy that writes data back to the cache\r\n\r\n### Issues with Approach 1\r\n\r\n#### 1. Zombie records:\r\n\r\nFollowing the query path approach to generate cache key, the First page will be written under cache key \"QUERY\\_ROOT.getPage-cursor\", while subsequent pages will hold the items under the cache key \"QUERY\\_ROOT.getItems-cursor-page2cursor\", \"QUERY\\_ROOT.getItems-cursor-page3cursor\", and so on..\r\n\r\nIn our case, The page cursors are generated run time and only valid until the first page is refreshed again to get a new cursor. Following this approach, We notice that all the pages that were previously fetched will never be deleted after re-fetching the first page and hence get accumulated as the user fetches more pages and re-fetches leading to larger cache size over time. Not to mention the more number of records, the higher the read time.\r\n\r\n#### 2. Cannot watch updates to items from the second page onwards:\r\n\r\nWe want to set up a GraphQLQueryWatcher on the paginated query, such that any changes to the items, including items from all the pages retrieved so far. However, Looking at the implementation of the GraphQLQueryWatcher, it appears that with this approach, Watcher will notify only for the items returned from the first page since dependent keys for the watcher includes only keys from the first page.\r\n\r\n## Approach 2: Manually merge data from subsequent pages into the first page\r\n\r\nIn order to solve the Approach #1 Issue #2, We took inspiration from [Apollo react Pagination](https://www.apollographql.com/docs/react/data/pagination/#cursor-based) which does the following:\r\n\r\n1. Load the first page with no cursor with cache policy that writes data back to the cache\r\n2. Load the second page, and so on, with `fetchIgnoringCacheCompletely` cache policy and manually write the data into the First-page query.\r\n\r\n### Issues with Approach 2\r\n\r\n#### 1. Writes are slow\r\n\r\nAs we can notice in Step #2, we merge the previous page with data pulled from the next page and re-write the entire data back. As we fetch more pages, the write latency increases.\r\n\r\n#### 2 Latency of reading the first page exponentially increases\r\n\r\nSince we merge data from all pages into the first page, reading the first page exponentially increases based on the number of items present in the cache. This is more evident with queries that have an increasing number of attributes that are non-scalar data types in the query as the batch loader does round trip to the database for each attribute. With our sample of data, the read time for a query with medium complex schema has clocked 10 seconds to read 150 items on an iPhone XS device.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hey @bharath2020 - just a heads up that I'm bogged down at the moment but this is a *very* good question that I need to work on a better answer to (and that we should have a *way* better answer to overall for mobile), and I think messing around with the tutorial is probably a good place to start with it. And you are very correct that 10 seconds to read 150 items is 🤮. \r\n\r\nIn terms of what you can try while I'm digging out from under what I'm dealing with now, there's the `cacheKeyForObject` closure that you can use to generate a custom cache key. For most items you should be able to cache by ID, and that should avoid having to rewrite all the data if it's not necessary. \r\n\r\nI'm going to leave this open for the community to respond more - I know this has been done well, but my knowledge of details isn't there because I'm focused on other parts of the SDK at the moment. \r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks, @designatednerd for the response.\r\n\r\n> For most items you should be able to cache by ID, and that should avoid having to rewrite all the data if it's not necessary.\r\n\r\nInteresting. In approach #2, Given that I am appending items from `morePage` back to `firstPage` and issuing a re-write of data for the first-page query, I am curious how would the store understand to not overwrite data referencing items in the first page? In other words, I understand `cacheKeyForObject` would reduce the number of records written to the database, but even with normalized cache, there would be unnecessary overwrites (in this case the items in the first page) that would add to the write latency. Please correct me If I am wrong.\r\n\r\nP.S. I have cacheKeyForObject enabled in my sample, and timings were taken after. The only part where I would not be able to generate a cache key is for the `PageResult` type, as `cacheKeyForObject` does not expose the variables (or field arguments) used to generate the type, in this case, it is the `cursor` provided for `getItems(cursor:)` query.","author":{"__typename":"User","login":"bharath2020","id":"MDQ6VXNlcjkwMzUzNg==","name":null}},{"__typename":"IssueComment","body":"Again, my knowledge of the cache is not as deep as it should be, but my understanding is you'd be rewriting the references with IDs rather than the entire object and its entire tree of changes. This almost certainly has some unnecessary work, but it would likely constitute a lot *less* unnecessary work than without the `cacheKeyForObject`. \r\n\r\nAnd again, this is not working as well as we want it to. We have some changes to the cache slated for [phases 2 and 3 of the ongoing Swift codegen rewrite](https://github.com/apollographql/apollo-ios/issues/939), and making things less annoying for pagination is one of the major things I want to do within that work. \r\n\r\nWish I had a better answer for you. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Got it. I played a little bit with batch reading objects from the database. I will give it a try to see if we can do the batch updates within a transaction. Right now, each roundtrip to the SQLite database is in its own transaction and I am guessing that is causing the reads to slow down. I have in the past read a huge number of items from SQLite and latency was fine.\r\n\r\nI will see if it makes any difference in the same and post it back.","author":{"__typename":"User","login":"bharath2020","id":"MDQ6VXNlcjkwMzUzNg==","name":null}},{"__typename":"IssueComment","body":"OK - do you mind if we close out this issue? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Ok","author":{"__typename":"User","login":"bharath2020","id":"MDQ6VXNlcjkwMzUzNg==","name":null}}]}},{"__typename":"Issue","title":"It expected a JSON schema introspection result, but got an HTML response instead.","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null},"body":"Hello,\r\n\r\nI am trying to run a script first time but i am receiving below error. \r\n\r\n**Unexpected token < in JSON at position 0\r\n Error: Apollo tried to introspect a running GraphQL service at \r\n http://10.10.10.10/graphql\r\n It expected a JSON schema introspection result, but got an HTML response \r\n instead.\r\n You may need to add headers to your request or adjust your endpoint url.**\r\n\r\nHere is my Script\r\n\r\n # Type a script or drag a script file from your workspace to insert its path.\r\n # Go to the build root and search up the chain to find the Derived Data Path where the source packages are checked out.\r\n DERIVED_DATA_CANDIDATE=\"${BUILD_ROOT}\"\r\n\r\n while ! [ -d \"${DERIVED_DATA_CANDIDATE}/SourcePackages\" ]; do\r\n if [ \"${DERIVED_DATA_CANDIDATE}\" = / ]; then\r\n echo >&2 \"error: Unable to locate SourcePackages directory from BUILD_ROOT: '${BUILD_ROOT}'\"\r\n exit 1\r\n fi\r\n\r\n DERIVED_DATA_CANDIDATE=\"$(dirname \"${DERIVED_DATA_CANDIDATE}\")\"\r\n done\r\n\r\n # Grab a reference to the directory where scripts are checked out\r\n SCRIPT_PATH=\"${DERIVED_DATA_CANDIDATE}/SourcePackages/checkouts/apollo-ios/scripts\"\r\n\r\n if [ -z \"${SCRIPT_PATH}\" ]; then\r\n echo >&2 \"error: Couldn't find the CLI script in your checked out SPM packages; make sure to add the framework to your project.\"\r\n exit 1\r\n fi\r\n\r\n #cd \"${SRCROOT}/${TARGET_NAME}\"\r\n #\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=\"schema.json\" API.swift\r\n\r\n SCRIPT_PATH=\"${PODS_ROOT}/Apollo/scripts\"\r\n cd \"${SRCROOT}/${TARGET_NAME}\"\r\n \"${SCRIPT_PATH}\"/run-bundled-codegen.sh schema:download --endpoint=http:///graphql schema.json\r\n\r\nXCode Version : 11.3.1\r\nApollo : 0.24.1\r\nInstalled Apollo pod.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi, it looks like the endpoint hasn't had the `` placeholder replaced yet - the `http:///graphql` in your error message makes it look like that's just being stripped out entirely by the CLI. \r\n\r\nUnrelated to your immediate issue, I would strongly recommend running `schema:download` before running `codegen:generate` since codegen uses the result of downloading the schema. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"As of now i am trying to download schema.json from CLI with the following command.\r\n\r\n`apollo schema:download --endpoint=http:///graphql schema.json\r\n`\r\n\r\nBut still i am getting the same error. I didnt get placeholder (in your comment, can you please clarify)\r\n\r\nI have updated my question where i written down a dummy server url","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}},{"__typename":"IssueComment","body":"Hey I am able to download schema.json file from other public graphql url.\r\n\r\nBut now i am facing another error. I am using POD for apollo now.\r\n\r\nRun Script : \r\n\r\n`SCRIPT_PATH=\"${PODS_ROOT}/Apollo/scripts\"\r\ncd \"${SRCROOT}/${TARGET_NAME}\"\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=\"schema.json\" API.swift\r\n`\r\n\r\nError :\r\n\r\nLoading Apollo Project [started]\r\nLoading Apollo Project [completed]\r\nGenerating query files [started]\r\nGenerating query files with 'swift' target [title changed]\r\nGenerating query files with 'swift' target [failed]\r\n→ Apollo does not support anonymous operations\r\n GraphQLError: Apollo does not support anonymous operations\r\nCommand PhaseScriptExecution failed with a nonzero exit code\r\n\r\n\r\nIf its not legal then can i raise new issue with this error and close this one","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}},{"__typename":"IssueComment","body":"You need to make sure you give your query a name - otherwise the codegen won't know what name to give the class containing the query. \r\n\r\nSo it has to look like this: \r\n\r\n```graphql\r\nFetchUser($id: ID!) {\r\n user(id: $id) {\r\n name\r\n [etc]\r\n }\r\n}\r\n```\r\n\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks.. this works.","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}},{"__typename":"IssueComment","body":"Hello, \r\n\r\nI am receiving this error right now.\r\n\r\nERROR : Received error response: Field \"country\" argument \"code\" of type \"ID!\" is required, but it was not provided.\r\n\r\nGraphQL : https://countries.trevorblades.com/graphql\r\n\r\nQuery : \r\n\r\n query AllCountry {\r\n country {\r\n name\r\n }\r\n }\r\n\r\niOS Swift Code : \r\n\r\n NetworkClient.sharedInstance().apollo.fetch(query: AllCountryQuery()) { result in\r\n \r\n switch result {\r\n case .success(let GraphQLResult) :\r\n print(GraphQLResult.data?.country as Any)\r\n \r\n \r\n \r\n case .failure(let error) :\r\n print(\"ERROR :\", error.localizedDescription)\r\n }\r\n }\r\n","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}},{"__typename":"IssueComment","body":"I think the error is telling you exactly what the problem is: `Field \"country\" argument \"code\" of type \"ID!\" is required, but it was not provided.` You need to make sure you're passing in a country code for this query.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Fixed. Thanks","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}}]}},{"__typename":"Issue","title":"Swift Package Manager + Xcode 12.0: Target 'arm64-apple-ios-simulator' missing","author":{"__typename":"User","login":"jzeisweiss","id":"MDQ6VXNlcjQyNjEyNTg=","name":"Jimmy Zeisweiss"},"body":"Hello,\r\n\r\nI can no longer use \"Preview\" for SwiftUI or build to a simulator due to the following error.:\r\n\r\n```\r\nerror: could not find module 'Apollo' for target 'arm64-apple-ios-simulator'; found: x86_64-apple-ios-simulator, x86_64\r\nimport Apollo\r\n```\r\n**Xcode Version**: 12.0 (12A7209)\r\n**Apollo Version**: 33.0\r\n\r\n_Note: I am having no problem building to a device._","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"@jzeisweiss Hi, what package manager are you using? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd - Hey Ellen, I am using Swift Package Manager.","author":{"__typename":"User","login":"jzeisweiss","id":"MDQ6VXNlcjQyNjEyNTg=","name":"Jimmy Zeisweiss"}},{"__typename":"IssueComment","body":"Are you using it on the Developer Transition Kit (I ask since it's looking for the `arm64-apple-ios-simulator` slice)? They took all the Apple Silicon stuff out of 12.0 and put it back in the 12.2 beta, so you'd need to use that if you are. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I am not using the Silicon ARM-Based prototype Mac from the Developer Transition Kit. I am using a 2018 Mac Mini and a 2018 MacBook Pro. However, I did find a workaround. I went in and changed the project settings to:\r\n\"Build Settings\" > \"Build Active Architecture Only\" > Set to \"YES\". This fixed my issue and I can now see the SwiftUI previews as well as build to simulators. Thank you for the speedy responses!\r\n\r\n**Source**: https://stackoverflow.com/questions/56957632/could-not-find-module-for-target-x86-64-apple-ios-simulator","author":{"__typename":"User","login":"jzeisweiss","id":"MDQ6VXNlcjQyNjEyNTg=","name":"Jimmy Zeisweiss"}},{"__typename":"IssueComment","body":"Ah yeah, that'll do it for sure - thank you for sharing your fix! Do you mind if we close this issue out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Networking Beta: Convenience constructors for HTTPRequest and JSONRequest","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"},"body":"In my use case i have to append to the `URLRequest.query` before a request is actually sent and that was fairly straight forward with the old network stack using `HTTPNetworkTransportPreflightDelegate.networkTransport(_:willSend:)` \r\n\r\nWith the new network stack things have gotten a bit more complex but i was able to come up with a solution involving a custom `ApolloInterceptor` that turns a given `JSONRequest` into a custom subclass which overrides `toURLRequest()`.\r\n\r\nSo to make implementation of custom HTTPRequests more easy i suggest you to add some convenience constructors for `HTTPRequest` and `JSONRequest` that take a single argument of their own type. This would let me get rid of this bunch of constructor arguments like this:\r\n\r\n```\r\n let customRequest = CustomJSONRequest(jsonRequest)\r\n```\r\n\r\ninstead of this:\r\n``` \r\n let customRequest = CustomJSONRequest(\r\n operation: jsonRequest.operation,\r\n graphQLEndpoint: jsonRequest.graphQLEndpoint,\r\n contextIdentifier: jsonRequest.contextIdentifier,\r\n clientName: jsonRequest.additionalHeaders[\"apollographql-client-name\"] ?? \"\",\r\n clientVersion: jsonRequest.additionalHeaders[\"apollographql-client-version\"] ?? \"\",\r\n additionalHeaders: jsonRequest.additionalHeaders,\r\n cachePolicy: jsonRequest.cachePolicy,\r\n autoPersistQueries: jsonRequest.autoPersistQueries,\r\n useGETForQueries: jsonRequest.useGETForQueries,\r\n useGETForPersistedQueryRetry: jsonRequest.useGETForPersistedQueryRetry,\r\n requestCreator: jsonRequest.requestCreator\r\n )\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"The override is the correct way of doing this - I'm not quite clear why the `super init`, which has a bunch of default parameters, isn't the way you're doing this, though. Can you go into a bit more detail on that? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"When looking for a way to get my `CustomHTTPRequest` with its overriden `toURLRequest()` into place i learned about the concept of `ApolloInterceptor` in the new network stack architecture.\r\n\r\nTherefore i have implemented a custom interceptor to replace the original `HTTPRequest` instance with one of `CustomHTTPRequest` as a substitution. Basically what i'm trying to do here is to create a copy of the request _with whatever particular values its properties have_ but extend its original functionality.\r\n\r\nIf there is something i have misunderstood or a better approach to achive this i'm glad to get enlighted.","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"}},{"__typename":"IssueComment","body":"OK! I think I see what the problem is here: While the `RequestChain` can take an arbitrary subclass of `HTTPRequest`, there's no way to say \"You should use this specific subclass\" from the level of the `RequestChainNetworkTransport`, so as of right now you're having to recreate the request at the interceptor level. \r\n\r\nIt sounds like the issue is that there needs to be a way to specify the request type that's customizable at that level, so that you can actually use the custom type you've created. \r\n\r\nDoes that sound accurate? I'm gonna poke at some ideas on this. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Indeed, if subclassing `HTTPRequest` is the intended way to go, a more simple way to place that type into the processing is greatly appreciated.","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"}},{"__typename":"IssueComment","body":"@knox Please see #1405 . You may have opened a trapdoor to a bigger change but it's a good one 😄 ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Wow i didn't mean to ask for moving mountains but opening `RequestChainNetworkTransport` and `constructRequest(for:cachePolicy:contextIdentifier:)` seems to perfectly fit my needs.","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"}},{"__typename":"IssueComment","body":"Haha, this worked as designed: You pointed out that I hadn't provided an access point to something, so I added it. Then by adding it I realized something else that was annoying me could change. 😇","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"With 0.34.0-rc.2 i was able to implement a clean and simple solution to my use case.","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"}}]}},{"__typename":"Issue","title":"Download Schema.json but server has CSRF Token protection","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null},"body":"Hello,\r\n\r\nI want to download a schema.json file but our server is protected with CSRF Token so which command i need to use to download a schema file and how can i send --header with CSRF token (From where i can get CSRF token means from our server guy or is apollo-client give/generate for downloading schema & passing in --header) ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! Please check out the instructions for [doing this in Bash](https://www.apollographql.com/docs/ios/downloading-schema/) and/or [doing this with the Swift Scripting tools](https://www.apollographql.com/docs/ios/swift-scripting/#downloading-a-schema). Do those docs answer your questions? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi! Since this is pretty clearly documented and I haven't heard anything back in a week, I'm going to close this out - @tapannathvani if you're still having problems please reopen. Anyone else having similar problems, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"is apollo provide internet check class?","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null},"body":"I am trying to check internet connection in my project.. and looking in apollo-ios library also like if you guys providing any reachability type class so without adding any other library or framework i can use your class to check connection\r\n\r\nIf yes then please provide documentation link and if not then please let me know how can i achieve this? and can i check internet connectivity in HTTPNetworkTransportPreflightDelegate (will send) method or in should send method? ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"We do not provide an internet check class, nor do we have plans to do so. \r\n\r\nIf you're using iOS 12 and above, the recommend way of doing things is [using `NWPathMonitor`](https://medium.com/@rwbutler/nwpathmonitor-the-new-reachability-de101a5a8835). If you're storing the most recent result from `NWPathMonitor` the preflight delegate would be a reasonable place to check it. \r\n\r\nPlease note that the Preflight delegate will be going away with `0.34.0` - you can check out the updated networking beta in #1386, and the PR has links to updated documentation. It would probably be fairly easy to add an interceptor that does that network check in the new networking stack. \r\n\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Can we know when can we have 0.34.0?","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}},{"__typename":"IssueComment","body":"Release candidate 2 is available now, gonna let it bake over the weekend and put it out monday night (US-Central time) if I don't hear any major showstoppers.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks for the quick response.","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}}]}},{"__typename":"Issue","title":"No such file or directory: run-bundled-codegen.sh","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null},"body":"I imported via cocoa pods the Apollo, actually it installed 0.30. \r\n\r\nI added exactly the same script as here:\r\nhttps://www.apollographql.com/docs/ios/installation/#troubleshooting \r\nschema.json is under project folder, under the target folder name.\r\nBut I keep receiving:\r\n![image](https://user-images.githubusercontent.com/6308120/94440933-75588f80-01a2-11eb-8095-c1d6862880b1.png)\r\nActually there is no data on SourcePackages folder about Apollo scripts.\r\n\r\nCould you help me?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi, it looks like you're using the Swift Package Manager run script rather than the CocoaPods run script [outlined in this step of the setup instructions](https://www.apollographql.com/docs/ios/installation/#adding-a-code-generation-build-step), because the CocoaPods script should be looking in `Pods/apollo-ios/scripts` rather than doing the weird dance of diving through derived data that the SPM script has to do.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"OMG!!! True. Wee can close the ticket!!!! ","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null}}]}},{"__typename":"Issue","title":"How to inject HTTP headers before fetching a query","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null},"body":"Do you know a mechanism to do that?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"This is covered in the [Advanced Client Creation](https://www.apollographql.com/docs/ios/initialization/) section of our docs. \r\n\r\nFair warning that this will be changing significantly very soon with the release of what's now in RC for #1386 (which I'm hoping to release tonight). The PR has a link to the updated docs for advanced client creation as well. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Error not parsed","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null},"body":"Hi,\r\n\r\nI have a GraphQL which is returning the following:\r\n![image](https://user-images.githubusercontent.com/6308120/94543867-da67c000-024a-11eb-803f-e76731c18064.png)\r\nBut the generated code is not parsing the error, but just giving data:\r\n![image](https://user-images.githubusercontent.com/6308120/94543972-fa977f00-024a-11eb-8689-7fa93a3d05f9.png)\r\nCould you help to identify how to get the errors?\r\n\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Weird - that does look like properly formatted JSON for the error - can you confirm what version of the SDK, Xcode, and Swift you're using here? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"SDK 0.33.0\r\nXcode 11.5 \r\nSwift 5","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null}},{"__typename":"IssueComment","body":"I've got no idea why that's not parsing the error - I put a test together and this is passing (different `\"data\"` key name since I'm using a local type for this test): \r\n\r\n```swift\r\nfunc testGH1415() throws {\r\n let json = \"\"\"\r\n{\r\n \"data\": {\r\n \"hero\": null\r\n },\r\n \"errors\": [\r\n {\r\n \"message\": \"Exception while fetching data (lastViewedProducts) : Customer not logged in\",\r\n \"locations\": [\r\n {\r\n \"line\": 2,\r\n \"column\": 3\r\n }\r\n ],\r\n \"path\": [\r\n \"lastViewedProducts\"\r\n ],\r\n \"extensions\": {}\r\n }\r\n ]\r\n}\r\n\"\"\"\r\n let data = try XCTUnwrap(json.data(using: .utf8),\r\n \"Couldn't create json data\")\r\n \r\n let deserialized = try JSONSerializationFormat.deserialize(data: data)\r\n let jsonObject = try XCTUnwrap(deserialized as? JSONObject)\r\n let response = GraphQLResponse(operation: HeroNameQuery(), body: jsonObject)\r\n \r\n let result = try response.parseResultFast()\r\n XCTAssertNil(result.data)\r\n XCTAssertNotNil(result.errors)\r\n \r\n let error = try XCTUnwrap(result.errors?.first)\r\n XCTAssertEqual(error.message, \"Exception while fetching data (lastViewedProducts) : Customer not logged in\")\r\n XCTAssertEqual(error.locations, [\r\n GraphQLError.Location(line: 2, column: 3),\r\n ])\r\n XCTAssertNotNil(error.extensions)\r\n}\r\n```","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Overwrite whole cache after fetch.","author":{"__typename":"User","login":"pgawlowski","id":"MDQ6VXNlcjk4NDUwMjQ=","name":null},"body":"Hello again.\r\n\r\nMy application is trying to archive offline first mode.\r\nWe are using BigQuery to fetch all the data required for app to be usable and focus on offline cache mutations with custom made syc feature. \r\n\r\nThe problem is that after synchronization we are trying to refresh whole cache data. Some of our tasks can fail, most will be successful.\r\nTo avoid too much noise with cache handling, right after syc we are refetching BigQuery once again. \r\nAnd here is our problem. Mutations we performed in offline mode are still present, no matter the fact of success of failure during sync it is because backend is creating it's own unique ID's here and we are just generating UUID as a placeholder. The source of truth is server. So in case of BigQuery fetch I would like to totally teardown current cache and recreate it with BigQuery result.\r\n\r\nCalling clearCache before BigQuery seems to be a little bit risky. I mean there is a risk of loosing data if sth goes wrong with BigQuery.\r\n\r\nAny ideas how to handle?\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Oof, that's a tough one. This is part of why sync is so hard (and frankly why I have zero interest in handling it on our end). \r\n\r\nThe first thing that jumps to mind is making a second instance of whatever cache you're using, swapping in a store with that cache, and then putting the old one back if things fail. I won't say that won't be a giant pain, but off the top of my head that's at least something that will keep the old data in case your `BigQuery` fails. \r\n\r\nLike I said though, sync is really hard. I don't think there's going to be a simple, straightforward solution to this problem. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@pgawlowski Anything else I can help with here or do you mind if I close this out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Since I haven't heard back in a week, I'm going to close this out. @pgawlowski feel free to reopen if you have more questions - anyone else with similar problems, please open a separate issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Question about ApolloInterceptor","author":{"__typename":"User","login":"dchohfi","id":"MDQ6VXNlcjUwODYzNg==","name":"Diego Chohfi"},"body":"Hey, amazing rewrite of the http architecture, good naming and nice usage of open/close principles.\r\n\r\nJust one stuff, I'm not sure how many times the `interceptAsync` method gets called, as it receives both request and an option response, I think this will be called twice, I'm correct?\r\n\r\nIf this is correct, talking about an interceptor that adds authentication token to the request, might be better to check if we don't have the response yet? Should I only add the token if the response is nil?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Each interceptor is called once - they're called in sequence based on the order of the array passed in from the `InterceptorProvider`. So if you want to put a token in, you can probably just add the token adding interceptor to the beginning of that array. \r\n\r\nYou can see an example of this in the [updated tutorial here](https://www.apollographql.com/docs/ios/tutorial/tutorial-mutations/#add-authentication-handling).","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"So the interceptor isn't called before each request and after each response?","author":{"__typename":"User","login":"dchohfi","id":"MDQ6VXNlcjUwODYzNg==","name":"Diego Chohfi"}},{"__typename":"IssueComment","body":"Thank your for your response! Now I get it, sorry about that.","author":{"__typename":"User","login":"dchohfi","id":"MDQ6VXNlcjUwODYzNg==","name":"Diego Chohfi"}}]}},{"__typename":"Issue","title":"JSONRequest losing headers when useGETForQueries is true","author":{"__typename":"User","login":"dchohfi","id":"MDQ6VXNlcjUwODYzNg==","name":"Diego Chohfi"},"body":"## Bug report\r\n\r\nAfter migrating my project to the new version, I'm not able to use a service that has authentication via header.\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.0\r\n- Xcode version: 12.0.1\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nCreate an interceptor that adds a header to the request, the NetworkTransporter must have `useGETForQueries=true`.\r\n\r\n## Further details\r\n\r\nWhen the method `toURLRequest` gets called, the request gets recreated and all headers are lost, including the defaults added by apollo. After digging into the code, I found that the library is instantiating a new `URLRequest` instead of just changing the URL.\r\n\r\nhttps://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/JSONRequest.swift#L101","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I would love to send a PR to fix it, just want to confirm first if this is what is happening.","author":{"__typename":"User","login":"dchohfi","id":"MDQ6VXNlcjUwODYzNg==","name":"Diego Chohfi"}}]}},{"__typename":"Issue","title":"Massive API.swift file ","author":{"__typename":"User","login":"RomanTysiachnik","id":"MDQ6VXNlcjMxNjUyMjY1","name":"Roman Tysiachnik"},"body":"## Feature request\r\n\r\nGenerate each query, mutation, fragment and scalar type in a separate file.\r\n\r\n## Motivation\r\n\r\nWe use Apollo in production on a pretty large project.\r\nRight now our generated `API.swift` file is almost 10 Mb and it has 255,000+ lines of code.\r\nAfter we create a new query/mutation, the file may be overwritten completely, that it is impossible to understand anything in git. \r\nMoreover, Xcode freezes for about a minute when we try to open that single file.\r\n\r\n| Code | Git mess |\r\n| :--: | :--: | \r\n| \"Screen | \"Screen |\r\n\r\n\r\n## Proposed solution\r\n\r\nAs far as all requests and types are public classes, it shouldn't be hard to put each of them in a separate file.\r\nAll those files can also be sorted in folders to make it much easier to navigate through the API.\r\nAPI ->\r\n--Scalars ->\r\n----Upload.swift\r\n--Fragments ->\r\n----UserFragment.swift\r\n--Queries ->\r\n----UserQuery.swift ->\r\n--Mutations ->\r\n----CreateUserMutation.swift\r\n\r\n#### Benefits\r\n\r\n- Each request/type in a separate file and it is easy to navigate among them;\r\n- No freezes when you accidentally open an API file and it freezes Xcode for minutes.\r\n- Only new updates of the API in source control. \r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"If you provide a folder path instead of a file path to the generate command, it will do exactly this: a separate file for everything.","author":{"__typename":"User","login":"TizianoCoroneo","id":"MDQ6VXNlcjE1MzQwMzgy","name":"TizianoCoroneo"}},{"__typename":"IssueComment","body":"@TizianoCoroneo \r\n\r\nCould you share an example, please? ","author":{"__typename":"User","login":"RomanTysiachnik","id":"MDQ6VXNlcjMxNjUyMjY1","name":"Roman Tysiachnik"}},{"__typename":"IssueComment","body":"This is the script as is in [the docs](https://www.apollographql.com/docs/ios/installation/):\r\n```bash\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=\"schema.json\" API.swift\r\n```\r\n\r\nIf you make a folder named `API` just next to your `API.swift` file, and then remove the `.swift` extension from the last argument of the script, it should work:\r\n```bash\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=\"schema.json\" API/\r\n```","author":{"__typename":"User","login":"TizianoCoroneo","id":"MDQ6VXNlcjE1MzQwMzgy","name":"TizianoCoroneo"}},{"__typename":"IssueComment","body":"I'm using Swift scripting to generate API from this [doc](https://www.apollographql.com/docs/ios/swift-scripting/):\r\n```swift\r\nApolloCodegen.run(\r\n from: queriesURL,\r\n with: apolloCLIURL,\r\n options: Options.codegen\r\n )\r\n```\r\n\r\nAnd I couldn't find a way to get rid of that massive file.","author":{"__typename":"User","login":"RomanTysiachnik","id":"MDQ6VXNlcjMxNjUyMjY1","name":"Roman Tysiachnik"}},{"__typename":"IssueComment","body":"Ok. I guess I've managed how to handle that, there's another `init` that allows you to specify output format:\r\n\r\n```swift\r\nlet operationIDsURL = outputURL\r\n .appendingPathComponent(\"operationIDs.json\")\r\n\r\nlet schemaURL = outputURL\r\n .appendingPathComponent(\"schema.json\")\r\n\r\n ApolloCodegenOptions(\r\n codegenEngine: .default,\r\n operationIDsURL: operationIDsURL,\r\n outputFormat: .multipleFiles(inFolderAtURL: outputURL),\r\n urlToSchemaFile: schemaURL\r\n )\r\n```\r\n\r\nClosing the issue :) ","author":{"__typename":"User","login":"RomanTysiachnik","id":"MDQ6VXNlcjMxNjUyMjY1","name":"Roman Tysiachnik"}},{"__typename":"IssueComment","body":"So, I'm noticing we're getting massive differences in file sizes from the generated output depending on if we use the `apollo codegen:generate` command through the NPM installed CLI vs. the **SwiftCodegenLib**.\r\n\r\nLike... one of our files is almost 20mb from **SwiftCodegenLib** but 224kb from the NPM CLI.\r\n\r\nWhat could be causing such as massive difference?","author":{"__typename":"User","login":"Mordil","id":"MDQ6VXNlcjM1MDY3NzY=","name":"Nathan Harris"}},{"__typename":"IssueComment","body":"I just compared the commands, and it looks like the default `mergeInFieldsFromFragmentSpreads: true` is the source of the \"bloat\".\r\n\r\nWhat is the cost/benefit of having that set to `true`, as it is by default?","author":{"__typename":"User","login":"Mordil","id":"MDQ6VXNlcjM1MDY3NzY=","name":"Nathan Harris"}},{"__typename":"IssueComment","body":"I'm very surprised to hear it's causing that big a jump. `mergeInFieldsFromFragmentSpreads` ensures that fields in spreads (the `...BlahFragment` operator) are actually on the returned object. It basically is the difference between calling `object.propertyFromFragment` and `object.fragment.propertyFromFragment` on literally everything, which can get REAL old. \r\n\r\n@Mordil you've got my email, can you send me before/after of your API.swift so i can validate assumptions? \r\n\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"In our codebase adding the `mergeInFieldsFromFragmentSpreads` option causes 220k+ lines of code to appear, mostly:\r\n- getter/setters for each property in the fragment\r\n- memberwise initializers that are omitted if a type contains a fragment (I found this behavior quite surprising; I would prefer to always have `init`s for testing purposes)\r\n\r\n(I have to admit that we overuse fragments, and that's the main culprit.)\r\n\r\nMight be interesting to use [dynamic member lookup with keypaths](https://www.avanderlee.com/swift/dynamic-member-lookup/) to reduce code bloat, so that the enclosing type can refer dynamically to the properties of the enclosed fragment. I guess this road will be explored in the context of the new Swift Codegen though, right?","author":{"__typename":"User","login":"TizianoCoroneo","id":"MDQ6VXNlcjE1MzQwMzgy","name":"TizianoCoroneo"}},{"__typename":"IssueComment","body":"Yes. Also representing fragments as protocols means that you can have the properties straight on the object without duplication. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Query watcher not being called when cache is updated on an element by another query/subscription/mutation","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"},"body":"## Bug report\r\n\r\nQuery watcher not being called when cache is updated on an element of a collection that is added after calling watch\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.0\r\n- Xcode version: 12.0.1\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nI've been trying a lot of things on that one and wasn't able to find a way to fix my problem. So in my app I'm having a list of conversations, so I'm creating a `watch` on a query that returns the list of conversations, this is something like that:\r\n\r\n```\r\nuser {\r\n uuid\r\n firstName\r\n lastName\r\n conversations {\r\n uuid\r\n unreadMessagesCount\r\n }\r\n}\r\n```\r\n\r\n> In the app we use the `uuid` key to handle cache, so we make sure to always pass `uuid` in our queries to automatically handle cache update.\r\n\r\nSo the role of the watcher I'm talking about is both to update existing conversations and also be able to catch when a new conversation is created (it can happen and not be initiated by the user, we then trigger an event from the backend that is listen from a subscription in the app). When this event happens it returns something like that\r\n\r\n```\r\nevent {\r\n newConversation {\r\n conversation {\r\n uuid\r\n unreadMessagesCount\r\n // This is the part that adds the new conversation to the existing ones of the users in the cache\r\n user {\r\n uuid\r\n conversations {\r\n uuid\r\n unreadMessagesCount\r\n }\r\n } \r\n }\r\n }\r\n}\r\n```\r\n\r\nIt works great, meaning that when this event happens, the watcher is being called with the newly created conversation, but the issue is that any new cache update for that specific conversation doesn't trigger the watcher again.\r\n\r\nAfter investigating a bit, I realised that the cache is being updated because if I'm adding 3 new messages into the new conversation (setting the `unreadMessagesCount` to 3), the watcher doesn't get called but then if I add 1 new message into an old one, the watcher is being called with both the new message on the old conversation and the 3 new on the new one. \r\n\r\nSo it really seems like `watch` is not being called again for changes on an item that wasn't in a collection when the `watch` was initially made. I've also take a look at https://github.com/apollographql/apollo-ios/issues/281 and making a `fetch` on the same query again after the event doesn't fix the issue.\r\n\r\nLet me know if I'm not clear on something as the whole thing is a bit complicated to explain.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"To add more to this, I feel like this is not related to collections only. If you have 1 query that watches something, then another query/mutation updates this cache indirectly (not using the same query, but another query that contains the same element with the same `uuid`), it doesn't work.","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"Do you have any thoughts on why the test that was added would be passing, but what you're working with would not be working?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'm afraid no, but all I can tell is that it works with 0.32.0 and not with 0.34.0","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"Hi @designatednerd,\r\n\r\nI think I have the same problem but not on a collection. My watcher is not triggered anymore since I have updated Apollo from 0.31.0 to 0.34.1. I have a watcher in cachePolicy .returnCacheDataAndFetch on this Query.\r\n\r\n```\r\nquery GetRide($rideId: ID!) {\r\n ride(id: $rideId) {\r\n ...EndRideFragment\r\n }\r\n}\r\n```\r\n\r\nAnd I have a mutation that updates my cache and normally triggers my watcher.\r\n```\r\nmutation StopRide($input: StopActiveRideInput!) {\r\n stopActiveRide(input: $input) {\r\n ride {\r\n ...EndRideFragment\r\n }\r\n }\r\n}\r\n```\r\nSince my Apollo pod upgrade, not working anymore. My watcher is not triggered when mutation payload updates my cache.","author":{"__typename":"User","login":"Narayane","id":"MDQ6VXNlcjQ5MjEzMDg=","name":"Sébastien BALARD"}},{"__typename":"IssueComment","body":"This is also occurring for me. 0.33.0 (non beta) worked; but not 0.34.0 or 0.34.1","author":{"__typename":"User","login":"dhritzkiv","id":"MDQ6VXNlcjEzNDk4NjU=","name":"Daniel Hritzkiv"}},{"__typename":"IssueComment","body":"@dhritzkiv That makes sense, the network stack and how it interacts with the cache changed completely in 0.34.0. \r\n\r\nApologies, I've been under the weather. I'm gonna do some digging starting tomorrow to try to figure out how I broke this without breaking the tests 🙃","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"No rush from me! I was able to roll back to 0.33.0 no problem","author":{"__typename":"User","login":"dhritzkiv","id":"MDQ6VXNlcjEzNDk4NjU=","name":"Daniel Hritzkiv"}},{"__typename":"IssueComment","body":"I can wait 1 week to have feedback from you @designatednerd on this issue.\r\nIf you need more time to investigate or to solve it, I could roll back to 0.33.0 to avoid blocking me in production","author":{"__typename":"User","login":"Narayane","id":"MDQ6VXNlcjQ5MjEzMDg=","name":"Sébastien BALARD"}},{"__typename":"IssueComment","body":"Same here, I rollbacked to 0.32.1 so no rush from me, and thanks for taking time investigating this!","author":{"__typename":"User","login":"benoitletondor","id":"MDQ6VXNlcjg2ODA1NA==","name":"Benoit Letondor"}},{"__typename":"IssueComment","body":"I'm trying to reproduce this issue to investigate what could be going on, but it's been hard because unfortunately our tests aren't set up to run in real life conditions, where concurrency may play a role. The existing watcher tests all continue to pass, and so do some new ones I've been adding.\r\n\r\nIt would be helpful to learn more about the way people who experience this are using the framework, and what behavior they are seeing:\r\n- How are you initializing and configuring the client, cache, store and network transport?\r\n- Are you calling methods on `ApolloClient` from the main thread or from a background thread? Do you receive results on the main queue as well, or are you passing in a custom queue?\r\n- Does the issue occur 100% of the time, or only sometimes?\r\n- Are there other operations in flight when this happens, or does it also happen with just a single watcher and a single related query or mutation?\r\n- Anything else unusual or noticeable?\r\n\r\nI know this is a long shot, but it would be even more helpful if anyone was able to share a project that reliably exhibits this issue.","author":{"__typename":"User","login":"martijnwalraven","id":"MDQ6VXNlcjU0NDg1","name":"Martijn Walraven"}},{"__typename":"IssueComment","body":"A few more thoughts after taking a closer look at this:\r\n\r\n1) It seems any operations using the `WebSocketTransport` always ignore the cache completely starting in 0.33 (I believe https://github.com/apollographql/apollo-ios/commit/444c465671c786659599a16da4b2d23d43648a74 is where this change was introduced). That means subscription results are not actually published to the store, and thus will not trigger watchers. (@benoitletondor I think that would at least explain your initial bug report).\r\n\r\n2) That doesn't yet explain why queries and mutations would also fail to trigger watchers (assuming those are not using the `WebSocketTransport`). There is a possibility for misconfiguration however, which would lead to inadvertently having multiple stores (see https://github.com/apollographql/apollo-ios/issues/1438). Could some of you be bitten by this maybe?\r\n\r\n3) Using a custom `NetworkTransport` also currently ignores the cache completely (see https://github.com/apollographql/apollo-ios/pull/1442 for an in progress PR to work around this). Any chance this could explain the behavior some of you are seeing?","author":{"__typename":"User","login":"martijnwalraven","id":"MDQ6VXNlcjU0NDg1","name":"Martijn Walraven"}},{"__typename":"IssueComment","body":"I'm not using WebSocketTransport, but 3. sound like it could be what's plaguing us! Will have some time in two weeks to poke around that","author":{"__typename":"User","login":"dhritzkiv","id":"MDQ6VXNlcjEzNDk4NjU=","name":"Daniel Hritzkiv"}},{"__typename":"IssueComment","body":"@martijnwalraven I guess 3. could be an explanation in my case, I have a custom `NetworkTransport` implementation (http request headers additions, checks on http response)\r\n\r\n`public func send(operation: Operation, completionHandler: @escaping (_ result: Result, Error>) -> Void) -> Cancellable` in 0.33\r\n\r\nbecomes\r\n\r\n`public func send(operation: Operation, cachePolicy: CachePolicy, contextIdentifier: UUID?, callbackQueue: DispatchQueue, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable where Operation : GraphQLOperation` in 0.34\r\n\r\nI need to change\r\n```\r\ndo {\r\n let body = try self.serializationFormat.deserialize(data: data) as! JSONObject\r\n let response = GraphQLResponse(operation: operation, body: body)\r\n completionHandler(.success(response))\r\n} catch { }\r\n```\r\ninto\r\n```\r\ndo {\r\n let body = try self.serializationFormat.deserialize(data: data) as! JSONObject\r\n let response = GraphQLResponse(operation: operation, body: body)\r\n let result = try response.parseResultFast()\r\n completionHandler(.success(result))\r\n} catch { }\r\n```\r\nto try to conform my code to the new signature","author":{"__typename":"User","login":"Narayane","id":"MDQ6VXNlcjQ5MjEzMDg=","name":"Sébastien BALARD"}}]}},{"__typename":"Issue","title":"Why the response is not being triggered and no interceptors are dispatched?","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null},"body":"I'm building the client like this:\r\n![image](https://user-images.githubusercontent.com/6308120/94703838-90143b00-033f-11eb-8033-3f2727a09fbe.png)\r\nThis is my Interceptor Provider:\r\n![image](https://user-images.githubusercontent.com/6308120/94703879-9c989380-033f-11eb-8fab-ea802d571565.png)\r\nAnd this is an example of the query fetch:\r\n![image](https://user-images.githubusercontent.com/6308120/94703946-aae6af80-033f-11eb-93aa-b7670cb5c41d.png)\r\nIt is never stopping at result or at any interceptor, but console is dispatching:\r\n![image](https://user-images.githubusercontent.com/6308120/94704042-c81b7e00-033f-11eb-9ca7-ad9b833251b2.png)\r\n\r\nDo you have any idea what is wrong there?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"You are not actually including anything that calls the network, it looks like. You will need to include the `NetworkFetchInterceptor`, probably between request and response logging interceptors. \r\n\r\nI don't know why the response logging interceptor would be showing a 200 response when there's nothing that came through, because the request never went out to the network.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Obsolete type GraphQLHTTPResponseError","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"},"body":"## Bug report\r\n\r\nWith the new network stack (yeah!) a few types such as `GraphQLHTTPResponseError` became obsolte but did not get removed from code base yet.\r\n\r\n## Versions\r\n\r\n- `apollo-ios` SDK version: 0.34.0\r\n\r\n## Steps to reproduce\r\n\r\n\"Find usages\" of `GraphQLHTTPResponseError`, `GraphQLHTTPRequestError` and probably others.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"`GraphQLHTTPRequestError` is still used, but good catch on the response error. \r\n\r\nPlease note that \"find usages\" isn't the be-all, end-all, especially for enum types - always worth doing a text search through the full codebase. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"The problem here for me was that by not beeing broken because of a removed class my validations got semantically broken because they where still checking for that type.\r\n\r\nOf course you're right about `GraphQLHTTPRequestError`. I've mistaken that.\r\n\r\nBut still, regarding your advise to check for \"usages\" with full text search i have to strongly disagree. In fact i heavily rely on this kind of type based analysis and navigating through code and therefore i prefer AppCode over Xcode a lot because of it outstanding capabilities in that. You should give it a try.","author":{"__typename":"User","login":"knox","id":"MDQ6VXNlcjE2NDAx","name":"Mickey"}},{"__typename":"IssueComment","body":"I agree that it's helpful, but particularly when it comes to removing stuff, I've found it better to belt-and-suspenders things by actually searching out where something is used (even in AppCode, which I have used before). ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"This has been removed with `0.35.0`. If you find other unused types, please open a new issue. Thanks!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Enhance support for custom cache key resolver logic","author":{"__typename":"User","login":"qingqingliu","id":"MDQ6VXNlcjMzMDk3NjE=","name":null},"body":"## Feature request\r\n\r\nAdd similar support of [CacheKeyResolver](https://github.com/apollographql/apollo-android/blob/main/apollo-normalized-cache-api/src/commonMain/kotlin/com/apollographql/apollo/cache/normalized/CacheKeyResolver.kt) as from Android Apollo Client library. \r\n\r\n## Motivation\r\n\r\nCurrent iOS library provides cacheKeyForObject on ApolloClient that allows you to provide custom cache key for response, but there is no way for client app to provide custom cache key for request. This feature is needed in case client wants to use a different cache key for request\r\n\r\n## Proposed solution\r\n\r\nFollow Android pattern to introduce CacheKeyResolver on ApolloClient and support custom cache key for both response and request key.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"We're going to be looking in late 2020-early 2021 at getting our mobile caching more aligned, both across iOS and android and with our web cache, and this is one of the things I'll definitely be considering. \r\n\r\nI'm definitely open to discussion if you're interested in implementing this yourself.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks @designatednerd for the follow up. I see this is being part of bigger alignment between iOS and Android, I would probably wait for an overall proposal first. Happy to contribute though once the proposal is in place\r\n\r\nAs android side does seems have more feature supports like refetch, optimistic updates and custom cache key etc, wondering whether the direction for iOS would be following Android design pattern","author":{"__typename":"User","login":"qingqingliu","id":"MDQ6VXNlcjMzMDk3NjE=","name":null}},{"__typename":"IssueComment","body":"We're going to try to line up on what's best for both - the biggest issue right now is that iOS had a long period where no development took place (while Android was chugging along well with open-source contributions) and I'm still digging my way out of that hole. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Enum generation with `INIT` case","author":{"__typename":"User","login":"bezoadam","id":"MDQ6VXNlcjI1NjEzMTI1","name":"Adam Bezak"},"body":"## Bug report\r\n\r\nHi, enum is declared like this:\r\n![Snímka obrazovky 2020-10-01 o 8 26 56](https://user-images.githubusercontent.com/25613125/94775340-ede86780-03bf-11eb-9f4e-f9cb5bc9f5a0.png)\r\n\r\nand generated code throws these errors:\r\n![Snímka obrazovky 2020-10-01 o 8 27 08](https://user-images.githubusercontent.com/25613125/94775447-18d2bb80-03c0-11eb-9fe5-b6f6d12420ef.png)\r\n\r\nIt looks like there is problem with `INIT` case when using enum.\r\n\r\n## Versions\r\n\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 12.0.1\r\n- Swift version: 5\r\n\r\n## Steps to reproduce\r\n\r\nGenerate code with `init` in enum case.\r\n\r\nIs it problem on my side or bug in apollo codegen. Any possible fixes?\r\nThanks.\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"It's the codegen - it's not properly escaping the case named `init`, which is a reserved Swift keyword. Upcoming codegen should handle this better but it's gonna be a bit - is this schema already public or is it still being evolved? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Schema is partially public but I think there is not chance that there will be some changes. Anyway if I change `.init` to ``.init`` on lines where error is triggered, it disappears. But of course on next build code is regenerated. So I think this should be fixed in codegen.","author":{"__typename":"User","login":"bezoadam","id":"MDQ6VXNlcjI1NjEzMTI1","name":"Adam Bezak"}},{"__typename":"IssueComment","body":"Yeah, absolutely - fixing the current codegen is a pain (which is why it's being rewritten) so I was trying to make sure it was necessary before diving into it. 🙃","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thank you 👍 it is not necessary for me, I think i can handle it somehow (use temporary script to rename all `.init` cases to `\".init\"`)","author":{"__typename":"User","login":"bezoadam","id":"MDQ6VXNlcjI1NjEzMTI1","name":"Adam Bezak"}},{"__typename":"IssueComment","body":"You'd need to make it\r\n\r\n```swift\r\n`.init`\r\n```\r\n\r\n rather than `\".init\"`, but if you're ok with that, I'm very OK with not diving into typsecript hell 😇. If that's cool with you, mind if we close this one out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"When adding interceptors, they don't parse properly errors","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null},"body":"SDK 0.34.0\r\n\r\nI can fetch the data, response is received:\r\n![image](https://user-images.githubusercontent.com/6308120/94791351-cac9b200-03d7-11eb-9d99-78a0bacddbcf.png)\r\nBut when handling it:\r\n![image](https://user-images.githubusercontent.com/6308120/94791434-e92fad80-03d7-11eb-934b-7777241fbad7.png)\r\nIt is entering the failure, but with a totally separate error:\r\n![image](https://user-images.githubusercontent.com/6308120/94791471-f8166000-03d7-11eb-8e70-c9a48d108e87.png)\r\nActually, that error does not contain anything related to the errors data is receiving.\r\nEven with just the Network Interceptor:\r\n![image](https://user-images.githubusercontent.com/6308120/94791498-02d0f500-03d8-11eb-8877-bc49dd33a64e.png)\r\n\r\nCould you help there?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"If I use LegacyInterceptorProvider it does work","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null}},{"__typename":"IssueComment","body":"You don't have a parsing interceptor happening here, so the data is not being parsed by the time it gets to the end of the interceptor chain. The parsing isn't done by the chain itself, it's done by the individual interceptors.\r\n\r\nIf you're creating your own interceptor provider, you have to provide _all_ the interceptors that you're planning to use, including the ones that do the parsing. A good place to start is to copy the interceptors that are in `LegacyInterceptorProvider` and then add your custom interceptors to that array wherever you want them to execute. \r\n\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Is there anything else I can help with here, or can we close this issue out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"You can close it. Many thanks!\n\nEl mar., 6 oct. 2020 a las 0:43, Ellen Shapiro ()\nescribió:\n\n> Is there anything else I can help with here, or can we close this issue\n> out?\n>\n> —\n> You are receiving this because you authored the thread.\n> Reply to this email directly, view it on GitHub\n> ,\n> or unsubscribe\n> \n> .\n>\n\n\n-- \n*Jose Ángel Zamora Cobo*\nTelecommunication Engineer\nAndroid/iOS Senior Software Engineer\n\n","author":{"__typename":"User","login":"angelu25","id":"MDQ6VXNlcjYzMDgxMjA=","name":null}}]}},{"__typename":"Issue","title":"Failed codegen when using GitHub GraphQL schema","author":{"__typename":"User","login":"mattia","id":"MDQ6VXNlcjExMTM4OA==","name":"Mattia Valzelli"},"body":"## Bug report\r\n\r\nWhile trying to use the [Swift scripting codegen tooling](https://www.apollographql.com/docs/ios/swift-scripting/) I was not able to generate the `API.swift` file given the corresponding schema file.\r\n\r\nAn error like this is generated \r\n\r\n> Field \"AcceptEnterpriseAdministratorInvitationInput.clientMutationId\" already exists in the schema. It cannot also be defined in this type extension.\r\n\r\n\r\nBut using the GraphQL verification tool available in the [same repo](https://github.com/octokit/graphql-schema) it passes. (running `npm start validate:ts`)\r\n\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 12.2 beta 2 (12B5025f)\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nSet up the project as described in the [Swift scripting guide](https://www.apollographql.com/docs/ios/swift-scripting/) and use the GitHub schema definition with the following files:\r\n - [schema.graphql](https://raw.githubusercontent.com/octokit/graphql-schema/master/schema.graphql)\r\n - [schema.json](https://raw.githubusercontent.com/octokit/graphql-schema/master/schema.json)\r\n\r\n## Further details\r\n\r\n
\r\n Example `main.swift`\r\n \r\n```swift\r\nimport ApolloCodegenLib\r\n\r\n// Grab the parent folder of this file on the filesystem\r\nlet parentFolderOfScriptFile = FileFinder.findParentFolder()\r\n\r\n// Use that to calculate the source root of both the\r\nlet sourceRootURL = parentFolderOfScriptFile\r\n .apollo.parentFolderURL() // Sources\r\n .apollo.parentFolderURL() // Codegen\r\n .apollo.parentFolderURL() // My Project\r\n\r\n// From the source root, figure out where your target\r\n// root is within your main project\r\nlet targetRootURL = sourceRootURL\r\n .apollo.childFolderURL(folderName: \"My Project\")\r\n\r\n// Set up the URL you want to use to download the project\r\nlet endpoint = URL(string: \"https://api.github.com/graphql\")!\r\n\r\n// Create an options object for downloading the schema\r\nlet schemaDownloadOptions = ApolloSchemaDownloadConfiguration(\r\n endpointURL: endpoint,\r\n headers: [\"Authorization: Bearer XXXXXXXXX\"],\r\n outputFolderURL: targetRootURL\r\n)\r\n\r\n// Calculate where you want to create the folder where the CLI will\r\n// be downloaded by the ApolloCodegenLib framework.\r\nlet cliFolderURL = sourceRootURL\r\n .apollo.childFolderURL(folderName: \"Codegen\")\r\n .apollo.childFolderURL(folderName: \"ApolloCLI\")\r\n\r\ndo {\r\n // Actually attempt to download the schema.\r\n try ApolloSchemaDownloader.run(with: cliFolderURL,\r\n options: schemaDownloadOptions)\r\n} catch {\r\n // This makes the error message in Xcode a lot more legible,\r\n // and prevents the script from continuing to try to generate\r\n // code if the schema download failed.\r\n exit(1)\r\n}\r\n\r\n// Create the default Codegen options object (assumes schema.json\r\n// is in the target root folder, all queries are in some kind\r\n// of subfolder of the target folder and will output as a\r\n// single file to API.swift in the target folder)\r\nlet codegenOptions = ApolloCodegenOptions(targetRootURL: targetRootURL)\r\n\r\ndo {\r\n // Actually attempt to generate code.\r\n try ApolloCodegen.run(from: targetRootURL,\r\n with: cliFolderURL,\r\n options: codegenOptions)\r\n} catch {\r\n // This makes the error message in Xcode a lot more legible.\r\n exit(1)\r\n}\r\n```\r\n
\r\n\r\nPlease let me know if I can help debug this. Also I am new to GraphQL, so I may be doing something wrong.\r\n\r\nThank you for this library!","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I've definitely seen this from the `.graphql` version of the GitHub schema before, but it looks from the code like you're downloading the JSON version of it. Can you please confirm that and attach a copy of the schema you're getting from GitHub so I can take a look? Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> I've definitely seen this from the `.graphql` version of the GitHub schema before, but it looks from the code like you're downloading the JSON version of it. Can you please confirm that and attach a copy of the schema you're getting from GitHub so I can take a look? Thank you!\r\n\r\nYes, of course. The schema I'm downloading is from the [octokit repo](https://github.com/octokit/graphql-schema).\r\nThe files are:\r\n - [schema.graphql](https://gist.github.com/mattia/d2cc50fdbfc1a90e58c4c35716677052)\r\n - [schema.json](https://gist.github.com/mattia/4545c6371577d3a7c7c17722bf7266f2).\r\n\r\nThank you and have a nice day!","author":{"__typename":"User","login":"mattia","id":"MDQ6VXNlcjExMTM4OA==","name":"Mattia Valzelli"}},{"__typename":"IssueComment","body":"OK looks like I had it backwards, it's the JSON that's giving the weird error and the SDL that seems to be working fine. If you update your schema download options to downloading SDL instead of the default JSON option, that should work: \r\n\r\n```swift\r\n// Create an options object for downloading the schema\r\nlet schemaDownloadOptions = ApolloSchemaDownloadConfiguration(\r\n schemaFileType: .schemaDefinitionLanguage,\r\n endpointURL: endpoint,\r\n headers: [\"Authorization: Bearer XXXXXXXXX\"],\r\n outputFolderURL: targetRootURL\r\n)\r\n```","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thanks for the reply. I've been real busy these days but I will try to come back to you in the next few days after trying your suggestion.\r\n\r\nThanks again! Have a nice day","author":{"__typename":"User","login":"mattia","id":"MDQ6VXNlcjExMTM4OA==","name":"Mattia Valzelli"}},{"__typename":"IssueComment","body":"OK cool - I'm going to close this issue out for now, please let us know if using the Schema Definition Language version of their schema doesn't work by reopening this issue. \r\n\r\nAnyone else having a similar problem, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Is it okay to git ignore API.swift?","author":{"__typename":"User","login":"prateek3255","id":"MDQ6VXNlcjIxMjc3MTc5","name":"Prateek Surana"},"body":"## Question\r\n\r\nSince API.swift is auto-generated, is it good practice to add it to `.gitignore`?\r\n\r\nWe tried adding it to `.gitignore` but whenever someone new clones the repo, the code fails to compile because of a broken reference to API.swift, and hence we have to manually pass it for the very first time.\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.32.1\r\n- Xcode version: 11.4\r\n- Swift version: 5.1","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"This is not a recommended practice - the exact problem you're having illustrates why this isn't a good idea. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Okay, thanks for the clarification","author":{"__typename":"User","login":"prateek3255","id":"MDQ6VXNlcjIxMjc3MTc5","name":"Prateek Surana"}}]}},{"__typename":"Issue","title":"Using a custom Date scalar","author":{"__typename":"User","login":"Renish-Development","id":"MDQ6VXNlcjQ3Njg0NzE5","name":"Renish_Development"},"body":"@cerupcat @jzhw0130: You should be able to pass `--passthrough-custom-scalars` to `apollo-codegen` to avoid generating a `typealias` to `String` for custom scalars. You can then add your own alias and conversion code, see [here](https://github.com/apollographql/apollo-ios/issues/23#issuecomment-261697349) for an example.\r\n\r\n_Originally posted by @martijnwalraven in https://github.com/apollographql/apollo-ios/issues/94#issuecomment-327287361_","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"How to use/implement Date type custom scalar in iOS?\r\n\r\nI'm working with GraphQL. I have successfully implement Query and Mutation in iOS app.\r\nI'm facing issue with Date Type. As per references, I have added --passthrough-custom-scalars in Run Script BUT I'm facing compilation issue.\r\n**I'm facing issue with \"--passthrough-custom-scalars\" variable. I have added below code in Run script but I'm facing an error.**\r\n\r\n```\r\nDERIVED_DATA_CANDIDATE=\"${BUILD_ROOT}\"\r\nwhile ! [ -d \"${DERIVED_DATA_CANDIDATE}/SourcePackages\" ]; do\r\nif [ \"${DERIVED_DATA_CANDIDATE}\" = / ]; then\r\necho >&2 \"error: Unable to locate SourcePackages directory from BUILD_ROOT: '${BUILD_ROOT}'\"\r\nexit 1\r\nfi\r\nDERIVED_DATA_CANDIDATE=\"$(dirname \"${DERIVED_DATA_CANDIDATE}\")\"\r\ndone\r\nSCRIPT_PATH=\"${DERIVED_DATA_CANDIDATE}/SourcePackages/checkouts/apollo-ios/scripts\"\r\nif [ -z \"${SCRIPT_PATH}\" ]; then\r\necho >&2 \"error: Couldn't find the CLI script in your checked out SPM packages; make sure to add the framework to your project.\"\r\nexit 1\r\nfi\r\ncd \"${SRCROOT}/${TARGET_NAME}\"\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./*/.graphql --localSchemaFile=\"schema.json\" API.swift\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh schema:download --endpoint=\"endpointURL\"\r\n#custom scalars\r\n**$APOLLO_FRAMEWORK_PATH/check-and-run-apollo-codegen.sh generate $(find . -name '*.graphql') --schema schema.json --output API.swift --passthrough-custom-scalars**\r\n```\r\n\r\n**Code for Define Date Scalars**\r\n```swift\r\npublic typealias DateTime = Date\r\nextension DateTime: JSONDecodable, JSONEncodable {\r\n public init(jsonValue value: JSONValue) throws {\r\n guard let string = value as? String else {\r\n throw JSONDecodingError.couldNotConvert(value: value, to: String.self)\r\n }\r\n guard let date = ISO8601DateFormatter().date(from: string) else {\r\n throw JSONDecodingError.couldNotConvert(value: value, to: Date.self)\r\n }\r\n self = date\r\n }\r\n public var jsonValue: JSONValue {\r\n return ISO8601DateFormatter().string(from: self)\r\n }\r\n}\r\n```\r\n\r\n**I have reviewed schema JSON have a Date variable but API.swift still string type.**\r\nHere is my graphql mutation.\r\n```graphql\r\nmutation AddPeriod($uid:ID!, $start_time : Date!, $flow: PeriodFlowInput){\r\n addPeriod(uid:$uid, start_time : $start_time, flow: $flow){\r\n id\r\n start_time\r\n end_time\r\n flow {\r\n value\r\n flow_time\r\n }\r\n }\r\n}\r\n```\r\n\r\nHow can I pass date in GraphQL mutation. Please help me. Thanks in advance","author":{"__typename":"User","login":"Renish-Development","id":"MDQ6VXNlcjQ3Njg0NzE5","name":"Renish_Development"}},{"__typename":"IssueComment","body":"Hi @Renish-Development - I updated your comment to add some formatting. \r\n\r\nIt looks like your type is called `Date` rather than `DateTime`, which would mean I believe you need to have your typealias be:\r\n\r\n```swift\r\ntypealias Date = Swift.Date\r\n```\r\n\r\nAnd then have your extension be on `Date` rather than `DateTime`. Give that a shot, let me know how it goes.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd , \r\n\r\n**1. Swift Date is Not available. I'm using Xcode 12. Please look at the attached screen shot.**\r\n\r\n**2. I'm also facing issue with execute --passthrough-custom-scalars. Please let me know what I missed for custom scalars**\r\n\r\n**$APOLLO_FRAMEWORK_PATH/check-and-run-apollo-codegen.sh generate $(find . -name '*.graphql') --schema schema.json --output API.swift --passthrough-custom-scalars**\r\n\r\n\"Screenshot\r\n","author":{"__typename":"User","login":"Renish-Development","id":"MDQ6VXNlcjQ3Njg0NzE5","name":"Renish_Development"}},{"__typename":"IssueComment","body":"Argh, I meant `Foundation.Date`. I always forget what's swift and what's foundation📈\r\n\r\nAnd `--output API.swift` has to be the last argument - move `--passthrough-custom-scalars` before that. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd , Its' not working. Please can I do any mistake or issue due to the updated version of Xcode 12. I'm using Xcode 12. Please check with your side and let me know it's work or not. Happy top share more information","author":{"__typename":"User","login":"Renish-Development","id":"MDQ6VXNlcjQ3Njg0NzE5","name":"Renish_Development"}},{"__typename":"IssueComment","body":"I did notice that the param is `--passthroughCustomScalars` rather than `--passthrough-custom-scalars` - that could be part of it. If that's not what's not working, please let me know in more detail what isn't working and in what way it is not working. Thanks. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Hi @Renish-Development is there anything more I can help with here or can we close this issue out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"You're far from the only person who's asked a ton of questions about this so I've added a page to our example playground to try and clarify this. Please see #1474 for further details","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd , Please add verify and step by step code or make tutorial as per latest version of GIT repo. Also I have not found proper documentation regarding custom scalar, pass token in API call, generate schema file with auth token and so on. I'm happy to help you anyway and if you can guide I will write tutorial for the same. Looking forward....","author":{"__typename":"User","login":"GlobesyncTechnologies","id":"MDQ6VXNlcjUzNDc1MDIx","name":"Renish | GlobeSync Technologies"}},{"__typename":"IssueComment","body":"@GlobesyncTechnologies Please see the PR I linked for an example of using a custom scalar. Please check out [our full tutorial](https://www.apollographql.com/docs/ios/tutorial) for full setup instructions. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Mismatched stores for ApolloClient/LegacyInterceptorProvider","author":{"__typename":"User","login":"danpalmer","id":"MDQ6VXNlcjIwMjQwMA==","name":"Dan Palmer"},"body":"## Bug report\r\n\r\nCaveat: this isn't quite a bug, perhaps more of a design bug, but we nearly shipped a bug in our app because of it. Also, I may just be missing things!\r\n\r\nThere are two ways to set up an `ApolloStore` for the networking in Apollo, and unless both are done, in the same way, I believe there can be inconsistencies.\r\n\r\nFor example, we previously did this in our `ApolloClient` setup:\r\n\r\n```swift\r\nlet networkTransport = HTTPNetworkTransport(url: baseURL)\r\nlet cache = InMemoryNormalizedCache()\r\nlet store = ApolloStore(cache: cache)\r\nlet client = ApolloClient(networkTransport: networkTransport, store: store)\r\n```\r\n\r\nWhen upgrading to the newest version of Apollo, we originally re-wrote this as:\r\n\r\n```swift\r\nlet provider = LegacyInterceptorProvider()\r\nlet networkTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: baseURL)\r\nlet cache = InMemoryNormalizedCache()\r\nlet store = ApolloStore(cache: cache)\r\nlet client = ApolloClient(networkTransport: networkTransport, store: store)\r\n```\r\n\r\nAs far as I can tell (please tell me if I'm wrong!) this has set up a store that is now not being used at all. We can still call `client.clearCache()` or `client.cacheKeyForObject` and it will use the store that we created, but this would _not_ affect the store being used by the interceptors.\r\n\r\nSimilarly, we could have configured a more complex cache setup, but that would not be used by the interceptors.\r\n\r\nIf we corrected this in the following way...\r\n\r\n```swift\r\nlet cache = InMemoryNormalizedCache()\r\nlet store = ApolloStore(cache: cache)\r\nlet provider = LegacyInterceptorProvider(store: store)\r\nlet networkTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: baseURL)\r\nlet client = ApolloClient(networkTransport: networkTransport)\r\n```\r\n\r\n...this would also introduce bugs because while our correct store is being used for the networking, `client.clearCache` or `client.cacheKeyForObject` are pointing to the `ApolloClient`'s default store from its init method.\r\n\r\n## Versions\r\n\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 12.0\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nSee above for the process that can lead to incorrect use. This is roughly the steps that we took while upgrading Apollo to 0.34.x – i.e. we went through two invalid implementations before reaching one that we believe is valid.\r\n\r\n## Further details\r\n\r\nAs mentioned above, this isn't really a bug, but I think it's a design issue that could be improved. My recommendation would be to eliminate the store from the `ApolloClient` entirely, and leave it up to the user to coordinate the store with their interceptor provider. Potentially the store could become part of the interceptor provider protocol so that the client could still back `cacheKeyForObject`/`clearCache` onto the provider's store.\r\n\r\nAn alternative would be to eliminate the store from the interceptor provider, and ensure that in the client the store is set correctly on the provider so that they always line up.\r\n\r\nLastly, if maintaining backwards compatibility is key, the store from the provider and the store from the client could be compared at the end of the client initialiser, and an error raised if they are not exactly the same object.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Is there a particular using you're not passing in the `store` parameter for `client` on that last version? eg: \r\n\r\n```swift\r\nlet cache = InMemoryNormalizedCache()\r\nlet store = ApolloStore(cache: cache)\r\nlet provider = LegacyInterceptorProvider(store: store)\r\nlet networkTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: baseURL)\r\nlet client = ApolloClient(networkTransport: networkTransport, store: store)\r\n```\r\n\r\nThat would ensure you have the same store in all places. \r\n\r\nI do agree it's a little overcomplicated at the moment - I do plan to keep evolving this, and I appreciate the feedback.\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> Is there a particular using you're not passing in the store parameter for client on that last version? eg:\r\n\r\nNot particularly, but we did go through this stage on the way to our fully working version, which is pretty much what you have in your example. The fact that there were multiple opportunities for human error in getting to that working solution suggests there's a better design possible.\r\n\r\nIdeally these would be caught by the type system, or made un-representable, as I don't believe they are states of the system with valid use-cases.\r\n\r\nWould you accept a PR to address this? If so, what's your preferred approach out of those options I outlined, or is there another way you'd like to solve this?","author":{"__typename":"User","login":"danpalmer","id":"MDQ6VXNlcjIwMjQwMA==","name":"Dan Palmer"}},{"__typename":"IssueComment","body":"If you're not using a custom interceptor provider, the default initializer for `ApolloClient` initializes all this stuff for you - is that more what you're thinking? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> If you're not using a custom interceptor provider, the default initializer for ApolloClient initializes all this stuff for you - is that more what you're thinking?\r\n\r\nI think that route is safe.\r\n\r\nWe were transitioning from the legacy networking stack where we used `HTTPNetworkTransportPreflightDelegate` though. To maintain compatibility we decided to use `LegacyInterceptorProvider` and add an additional interceptor that did what our preflight delegate implementation had previously done, hence ending up with needing to pass the store into two different places, and this getting out of sync in two different ways before we realised the implicit dependency between those two places.\r\n\r\nAlso, just realised that the 3rd code example in the issue body is roughly what's in `Network.swift` in the docs here: https://www.apollographql.com/docs/ios/tutorial/tutorial-mutations/ – following the docs here will result in an invalid construction of the networking stack I think.\r\n\r\nHaving thought about this a bit more, I think there's a more common way this could also be done incorrectly:\r\n\r\n```swift\r\nlet provider = LegacyInterceptorProvider()\r\nlet networkTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: baseURL)\r\nlet client = ApolloClient(networkTransport: networkTransport, store: store)\r\n```\r\n\r\nIf not manually constructing a store at all, but instantiating a custom interceptor provider, there are two different stores being used and therefore it's impossible to clear the cache of the \"real\" one, but no error would be raised clearing the cache of the unused one.\r\n\r\nIt's possible I've missed somewhere that the stores get \"joined up\" – I'm new to Swift and don't know much about the Apollo codebase and may not understand the intention here. Apologies if that's the case!\r\n\r\n- - -\r\n\r\nI think there are 3 possible options here (although very open to more suggestions!):\r\n\r\n1. Eliminate the store from the ApolloClient entirely, leave it up to the user to coordinate the store with their interceptor provider. User will need to hold a reference to it for setting/getting the cache key, or clearing the cache.\r\n\r\n2. Eliminate the store from the interceptor provider init, have the client inject it into the interceptor provider. This way the user only has one place to pass it in, and if they don't the default one is still the same.\r\n\r\n3. If maintaining backwards compatibility is key, the store from the provider and the store from the client could be compared at the end of the client initialiser, and an error raised if they are not exactly the same object.\r\n\r\n","author":{"__typename":"User","login":"danpalmer","id":"MDQ6VXNlcjIwMjQwMA==","name":"Dan Palmer"}},{"__typename":"IssueComment","body":"Good catch on the example in the tutorial, that's definitely an error.\r\n\r\nThere are (rare) instances where someone intentionally wants to use different stores, but you're right that most of the time, that's not the case. \r\n\r\nI think of the options you propose, 2 probably makes the most sense. I'll try to see what I can do here. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> There are (rare) instances where someone intentionally wants to use different stores, but you're right that most of the time, that's not the case.\r\n\r\nInteresting! I'm not sure I quite understand what the use-case is for the client to have a different store to the interceptor provider? I can't see how that client store gets used apart from by the user... which means if I've understood correctly, it's not plugged in to the Apollo internals?","author":{"__typename":"User","login":"danpalmer","id":"MDQ6VXNlcjIwMjQwMA==","name":"Dan Palmer"}},{"__typename":"IssueComment","body":"basically there are some people who use multiple clients with multiple stores, and there are some...odd ways people make that work. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I've shipped the PR removing the default stores with `0.36.0` - I took a couple swipes at doing something else besides that, but everything I tried wound up *far* more complicated than \"actually make people select what store they're passing\". \r\n\r\nGoing to close this one out, please open a new issue if you think you've got a better suggestion!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Nice one! PRs look good. Straightforward approach sounds good – I can't see myself making the mistakes above if this was in place. Better API ergonomics can come later if they're needed at all.\r\n\r\nThanks for your work on this!","author":{"__typename":"User","login":"danpalmer","id":"MDQ6VXNlcjIwMjQwMA==","name":"Dan Palmer"}}]}},{"__typename":"Issue","title":"Can not find 'GenericScalar' in scope","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null},"body":"## Bug report\r\n\r\nBackend is JWT and when i'll try to execute a mutation for tokenVerification it gives me an error. We have Payload (Scalar Type) as response it in. I have added --passthroughCustomScalars in run script also.\r\n\r\n`SCRIPT_PATH=\"${PODS_ROOT}/Apollo/scripts\"\r\ncd \"${SRCROOT}/${TARGET_NAME}\"\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=\"schema.json\" --passthroughCustomScalars API.swift\r\n`\r\n\r\n## Versions\r\n\r\n\r\n- `apollo-ios` SDK version: POD 0.34.0\r\n- Xcode version: XCode 12\r\n- Swift version: Swift 5\r\n\r\n## Steps to reproduce\r\n\r\nPlease add Scalar type response in mutation/query and try to build the project (first clear build folder)\r\n\r\n## Further details\r\n\r\nI have tried to do Type Conversion using this help : https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/JSONStandardTypeConversions.swift\r\n\r\nBut its not working as we are using swift 5 i think.\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! Can you clarify a bit: \r\n\r\n- What is the name of your custom scalar type, `Payload` or `GenericScalar`? \r\n- What is the underlying type of your custom scalar? It sounds like it's a string containing the JWT, I just want to double check\r\n- Have you tried using a `typealias` to define the scalar type? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@tapannathvani Hi, do you have answers to any of the questions I asked? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Closing this issue as i am not using Payload response data now.","author":{"__typename":"User","login":"tapannathvani","id":"MDQ6VXNlcjEwMzY4OTU1","name":null}}]}},{"__typename":"Issue","title":"Add example for direct writing to the cache","author":{"__typename":"User","login":"michael-mckenna","id":"MDQ6VXNlcjE0MDM1MTQ4","name":null},"body":"## Feature request\r\n\r\nAdd examples for writing directly to the cache, hopefully for all variants of the \"write\" function:\r\n```\r\ntransaction.write(object:withKey:)\r\ntransaction.write(data:forQuery:)\r\ntransaction.write(object:withKey:variables:)\r\n```\r\n\r\nLooks like only `read` and `update` are in the docs at the moment.\r\nhttps://github.com/apollographql/apollo-ios/blob/main/docs/source/caching.mdx#direct-cache-access\r\n\r\n## Motivation\r\n\r\nI'm new to GraphQL and using it for a side project has a learning experience. I don't want to get the whole server and datasource set up yet - would like to just do the iOS portion and have some sort of proof of concept going before pursuing it further. Because of this, I'm using the direct cache access exclusively for now. The extra examples in the readme will help me and future devs a lot. I come from using Realm and Core Data so this is quite a bit different for me.\r\n\r\n## Outstanding Questions\r\n\r\nIs there a sample app that utilizes direct cache access? If so, it'd be great to add a reference to that.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi, I can certainly add one, but I will say that the idea is that you avoid manually reading from or writing to the cache unless you absolutely have to, and let the store handle most of the nonsense around dealing with cache keys and things like that.\r\n\r\nIf it's your first time messing around with it and you just want to get an idea of how it works, I'd recommend checking out the app from the [Tutorial](https://www.apollographql.com/docs/ios/tutorial/), which uses a server that's already set up. You can then more easily inspect how things go into the in-memory cache or, if you want to, you can switch to using the SQLite cache and examine the SQLite database. \r\n\r\nThat will also allow you to have a base to mess around from if you are interested in seeing how the writing works if you need it.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd Just to clarify, it is still the expectation though that you should use manual cache updating after mutations / incoming subscriptions, correct? Recently I started to receive JSON `missingValue` errors in my cache updates and I'm not sure if it has anything to do with the major architectural changes that have been going on. ","author":{"__typename":"User","login":"Nickersoft","id":"MDQ6VXNlcjIxMDQxMjk=","name":"Tyler Nickerson"}},{"__typename":"IssueComment","body":"Subscriptions don't hit the cache at all at the moment - I wasn't part of that decision but it makes sense from a standpoint of \"This is constantly changing information, we don't necessarily want to cache all of it\", and also from a performance standpoint. So yes, that you'd need to do manually.\r\n\r\nMutation results can update the cache, though if you're not using a `cacheKeyForObject` function that says the cache key should be based on a unique identifier, you will need to update any related queries manually. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Can't update the RequestBodyCreator for WebSocketTransport","author":{"__typename":"User","login":"lowki93","id":"MDQ6VXNlcjU0NzMwMTc=","name":"budain"},"body":"## Bug report\r\n\r\nWe use `WebSocketTransport` and we need to override the `requestBodyCreator` parameters.\r\nWe define `CustomBodyCreator`:\r\n```\r\nstruct CustomBodyCreator: RequestBodyCreator {\r\n \r\n public func requestBody(\r\n for operation: Operation,\r\n sendOperationIdentifiers: Bool\r\n ) -> GraphQLMap {\r\n .....\r\n }\r\n \r\n}\r\n\r\n```\r\n\r\nwe put it when we initialize the `WebSocketTransport`: \r\n```\r\n WebSocketTransport(request: request, requestBodyCreator: CustomBodyCreator())\r\n```\r\n\r\nThe method call in `WebSocketTransport` don't use the method define in the procotol :\r\n```\r\n func sendHelper(operation: Operation, resultHandler: @escaping (_ result: Result) -> Void) -> String? {\r\n let body = requestBodyCreator.requestBody(for: operation, sendOperationIdentifiers: self.sendOperationIdentifiers)\r\n ....\r\n return sequenceNumber\r\n }\r\n```\r\nBut `requestBody` from our struct is never call.\r\n\r\nThere is a an extension for `RequestBodyCreator` that define the function in the protocol : \r\n```\r\nextension RequestBodyCreator {\r\n /// Creates a `GraphQLMap` out of the passed-in operation\r\n ///\r\n /// - Parameters:\r\n /// - operation: The operation to use\r\n /// - sendOperationIdentifiers: Whether or not to send operation identifiers. Defaults to false.\r\n /// - sendQueryDocument: Whether or not to send the full query document. Defaults to true.\r\n /// - autoPersistQuery: Whether to use auto-persisted query information. Defaults to false.\r\n /// - Returns: The created `GraphQLMap`\r\n public func requestBody(for operation: Operation,\r\n sendOperationIdentifiers: Bool = false,\r\n sendQueryDocument: Bool = true,\r\n autoPersistQuery: Bool = false) -> GraphQLMap {\r\n.....\r\n}\r\n```\r\n\r\nWhy can put this default implementation in `ApolloRequestBodyCreator` directly ?\r\n```\r\n// Helper struct to create requests independently of HTTP operations.\r\npublic struct ApolloRequestBodyCreator: RequestBodyCreator {\r\n // Internal init methods cannot be used in public methods\r\n public init() { }\r\n}\r\n```\r\n\r\nWhy we can't override this ?\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 12.0.1\r\n- Swift version: 5.2 \r\n\r\n## Further details\r\n\r\nWe need to override this to make `WebSocketTransport`with `AppSync`from AWS","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi, apologies for the delay, I was under the weather. \r\n\r\nYou can't override `ApolloRequestBodyCreator` because it's not intended to be overridden - that's why `RequestBodyCreator` is a protocol with a default implementation: That way your custom implementation can use the default implementation without having to implement it yourself if you don't need to. \r\n\r\nThat being said, there've been some changes to this class recently (mostly, removing all the stuff that was going on for uploads) that might make changes make sense. \r\n\r\nI'm not sure why your custom implementation wouldn't be getting called - I would double check that the request creator is being passed in everywhere you expect it to be by setting some breakpoints and validating whether you've got your `CustomRequestCreator` or an `ApolloRequestBodyCreator`, and then working backwards to try to figure out where things are going wrong. If it is the custom request creator, that's definitely a bug. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"OK updating a test, I am now seeing the issue you're having - looks like something I gave [literally an entire talk on](https://speakerdeck.com/designatednerd/protocols-all-the-way-down-dotswift-paris-january-2018?slide=63) just came to bite me because I have angered the gods of iOS development 🤦‍♀️ \r\n\r\nThe issue is the default implementation is getting called even if it's overridden when the only type the compiler knows about is the protocol itself. \r\n\r\nUnfortunately I think the approach in #1448 is going to break things too hard - it removes the ability for anyone to use the default implementation at all. I will make some changes with some tests to validate it works though. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"This has shipped with `0.35.0`. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Am running to this error `Cannot find 'HTTPNetworkTransport' in scope` and `Cannot find type 'HTTPNetworkTransportDelegate' in scope` when am trying to make calls, ApolloClient Version 0.34.1","author":{"__typename":"User","login":"gbrigens","id":"MDQ6VXNlcjQyMTAxNTY=","name":"Гералд Бирген"},"body":"Am running to this error `Cannot find 'HTTPNetworkTransport' in scope` and `Cannot find type 'HTTPNetworkTransportDelegate' in scope` when am trying to make calls, ApolloClient Version 0.34.1\r\n\r\nHere is my code;\r\n```\r\nfinal class Network {\r\n static let shared = Network()\r\n private lazy var networkTransport: NetworkTransport = {\r\n \r\n let transport = HTTPNetworkTransport(url: URL(string: \"https://exampe.com/grapghql\")!)\r\n transport.delegate = self\r\n \r\n return transport\r\n }()\r\n \r\n private(set) lazy var apollo = ApolloClient(networkTransport: self.networkTransport)\r\n}\r\n\r\nextension Network: HTTPNetworkTransportDelegate {\r\n func networkTransport(_ networkTransport: NetworkTransport, shouldSend request: URLRequest) -> Bool {\r\n return true\r\n }\r\n \r\n func networkTransport(_ networkTransport: NetworkTransport, willSend request: inout URLRequest) {\r\n \r\n let token = \"\"\r\n var headers = request.allHTTPHeaderFields ?? [String: String]()\r\n headers[\"Authorization\"] = \"Bearer \\(token)\"\r\n \r\n request.allHTTPHeaderFields = headers\r\n }\r\n}\r\n```\r\nI appreciate your feedback.\r\n\r\n_Originally posted by @gbrigens in https://github.com/apollographql/apollo-ios/issues/909#issuecomment-706535757_","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Hi! In 0.34.0 after an RFC and multiple betas, we released an updated networking stack which removed these methods in favor of a `RequestChainNetworkTransport`. Please see the [0.34.0 release notes](https://github.com/apollographql/apollo-ios/releases/tag/0.34.0) for links to updated documentation.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd this is my first time working with Apolloclient and GraphQL. I have ted the one from the link still running into errors `Cannot find 'NetworkInterceptorProvider' in scope`... Do you have an example that shows passing authorization headers?","author":{"__typename":"User","login":"gbrigens","id":"MDQ6VXNlcjQyMTAxNTY=","name":"Гералд Бирген"}},{"__typename":"IssueComment","body":"Yes, the [tutorial bit on additional mutations](https://www.apollographql.com/docs/ios/tutorial/tutorial-mutations/) has an example","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd thank you for your help, hope in future there will be more tutorials on iOS. I have been searching for content online and there isn't much compared to Android.","author":{"__typename":"User","login":"gbrigens","id":"MDQ6VXNlcjQyMTAxNTY=","name":"Гералд Бирген"}},{"__typename":"IssueComment","body":"Yes, definitely in the long term plan to beef that up.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Cannot query field \"currencyTypes\" on type \"Query\".","author":{"__typename":"User","login":"Hazem-Mohammed","id":"MDQ6VXNlcjU1Mjk4MDg0","name":null},"body":"Hello all,\r\n\r\nThis is my first time to work with GraphQl and i have a very weird issue if i try to add any new query to my .graphql file i get error Cannot query field on type\r\ni faced this issue once and the solution was simply download the new schema file and it is work just fine now it doesn't work and if the Backend add any new query and i try to use it i get the same error even after update the schema file.\r\n\r\nnow i have the same issue again and i have tried almost everything:\r\n1- remove schema and download the new one.\r\n2- remove the (Generate Apollo GraphQL API) and add it again\r\n3- remove apollo SDK and reinstall it (cocoapods)\r\n4- update apollo SDK to the latest version\r\n5- make sure the schema have the new query's (works fine with the android)\r\n\r\n1- screenshot from Altair GraphQl Client:\r\n\"Screen\r\n\r\n\r\n2- screenshot from Xcode:\r\n\"Screen\r\n\"Screen\r\n\r\n3- screenshot from schema file this one show that the query is there.\r\n\"Screen\r\n\r\n4- screenshot from .graphql file:\r\n\"Screen\r\n\r\ni really don't know what is the issue here i have tried to clean project file , restart Xcode, restart Mac and the 5 steps mentioned above with no result and the same schema file work just fine with the android team.\r\n\r\nany help will be much appreciated \r\n- `apollo-ios` SDK version: 0.33.0\r\n- Xcode version: 11.6\r\n- Swift version: 5","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"finally i solved the issue.\r\ni was downloading the schema file from terminal using this command:\r\napollo schema:download --endpoint=https://myEndPoint schema.json\r\n\r\nthat was working with me in past but for some unknown reason using this command cause the problem\r\n\r\nThe solution:\r\nDownload schema using CLI script:\r\nSCRIPT_PATH=\"${PODS_ROOT}/Apollo/scripts\"\r\ncd \"${SRCROOT}/${TARGET_NAME}\"\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh schema:download --endpoint=http://myEndPoint schema.json\r\n","author":{"__typename":"User","login":"Hazem-Mohammed","id":"MDQ6VXNlcjU1Mjk4MDg0","name":null}}]}},{"__typename":"Issue","title":"Crash in Alamofire","author":{"__typename":"User","login":"tspecht","id":"MDQ6VXNlcjYwMzE0NA==","name":null},"body":"## Bug report\r\n\r\nSince upgrading to the latest `0.34.0` release line with the revamped networking stack, we are seeing intermittent failures in conjunction with Alamofire. Is this a known issue?\r\n\r\n```\r\nCode Type: X86-64 (Native)\r\nParent Process: launchd_sim [2352]\r\nResponsible: SimulatorTrampoline [2256]\r\nUser ID: 501\r\n\r\nDate/Time: 2020-10-13 14:15:09.012 +0000\r\nOS Version: Mac OS X 10.15.5 (19F101)\r\nReport Version: 12\r\nAnonymous UUID: 4763FA26-E06C-409D-9FAC-0174438B0AC7\r\n\r\n\r\nTime Awake Since Boot: 2500 seconds\r\n\r\nSystem Integrity Protection: disabled\r\n\r\nCrashed Thread: 7 Dispatch queue: org.alamofire.session.rootQueue\r\n\r\nException Type: EXC_BAD_ACCESS (SIGSEGV)\r\nException Codes: KERN_INVALID_ADDRESS at 0x000027b7a55693a0\r\nException Note: EXC_CORPSE_NOTIFY\r\n\r\nTermination Signal: Segmentation fault: 11\r\nTermination Reason: Namespace SIGNAL, Code 0xb\r\nTerminating Process: exc handler [6910]\r\n\r\nVM Regions Near 0x27b7a55693a0:\r\n mapped file 000000011638b000-000000011caba000 [103.2M] r--/rwx SM=COW Object_id=254d583f\r\n--> \r\n MALLOC_NANO 0000600000000000-0000600008000000 [128.0M] rw-/rwx SM=ALI \r\n\r\nApplication Specific Information:\r\nCoreSimulator 704.12.2 - Device: iPhone 11 (********-****-****-****-************) - Runtime: iOS 13.7 (17H22) - DeviceType: iPhone 11\r\n\r\nThread 7 Crashed:: Dispatch queue: org.alamofire.session.rootQueue\r\n0 libobjc.A.dylib \t0x00007fff512b7c6a objc_retain + 10\r\n1 com.apple.Foundation \t0x00007fff259243bf NSKeyValueWillChange + 510\r\n2 com.apple.Foundation \t0x00007fff25923ff7 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 487\r\n3 com.apple.Foundation \t0x00007fff259249f2 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 68\r\n4 com.apple.Foundation \t0x00007fff2591f6da _NSSetLongLongValueAndNotify + 269\r\n5 com.apple.CFNetwork \t0x00007fff230f3bfc 0x7fff22f52000 + 1711100\r\n6 com.apple.Foundation \t0x00007fff2594f28c __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7\r\n7 com.apple.Foundation \t0x00007fff2594f1ad -[NSBlockOperation main] + 80\r\n8 com.apple.Foundation \t0x00007fff259520dc __NSOPERATION_IS_INVOKING_MAIN__ + 17\r\n9 com.apple.Foundation \t0x00007fff2594e3ee -[NSOperation start] + 731\r\n10 com.apple.Foundation \t0x00007fff25952a20 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 17\r\n11 com.apple.Foundation \t0x00007fff25952540 __NSOQSchedule_f + 182\r\n12 libdispatch.dylib \t0x00007fff520e9344 _dispatch_block_async_invoke2 + 83\r\n13 libdispatch.dylib \t0x00007fff520dc8cb _dispatch_client_callout + 8\r\n14 libdispatch.dylib \t0x00007fff520e260c _dispatch_lane_serial_drain + 707\r\n15 libdispatch.dylib \t0x00007fff520e3044 _dispatch_lane_invoke + 388\r\n16 libdispatch.dylib \t0x00007fff520ed0c4 _dispatch_workloop_worker_thread + 626\r\n17 libsystem_pthread.dylib \t0x00007fff52301a3d _pthread_wqthread + 290\r\n18 libsystem_pthread.dylib \t0x00007fff52300b77 start_wqthread + 15\r\n```\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: `0.34.0`\r\n- Xcode version: 11.7 as well as 12.0\r\n- Swift version: 5.1 as well as 5.3\r\n\r\n## Steps to reproduce\r\n\r\nHappens intermittently, hard to come up with exact steps.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"That's a new one on me - under the hood we're using the same `URLSessionClient` that wraps `URLSession` as we were previously, so there shouldn't be anything messing with `URLSession` that wasn't already happening before. \r\n\r\nThe crash is happening on the Alamofire queue, but it looks like it's happening pretty deep within foundation when a block operation tries to change a value and it triggers KVO, and then something blows up. \r\n\r\nFew questions:\r\n- Have you seen this happen on device or just on sim? \r\n- Have you cleaned your build folder since this happened? \r\n- Did Alamofire also update versions or is it still an older version?\r\n- Are you using the apollo-alamofire wrapper (which is totally separate from this repo) or are you just using AF in parallel to what we're doing? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I see several people have 👍'd this - any further details from anyone would be helpful","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd we have been doing some more experiments on our end, the common denominator so far seems to be recent versions of Firebase. We opened a separate issue in their repository hoping to get some insights on that, would be helpful to know if any of the other users upvoting this here are also using Firebase in their projects. Wondering if there might be some method swizzling going on somewhere? 🤔 \r\n\r\nhttps://github.com/firebase/firebase-ios-sdk/issues/6734","author":{"__typename":"User","login":"tspecht","id":"MDQ6VXNlcjYwMzE0NA==","name":null}},{"__typename":"IssueComment","body":"Oh interesting - yes that definitely seems plausible. For what it's worth our codebase is entirely in Swift, which doesn't completely prevent us from using swizzling but does make it way more of a pain. Either way, we do not use any swizzling. \r\n\r\nFor others running into this issue, are you also using Firebase? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd I am also using Firebase","author":{"__typename":"User","login":"ethan021021","id":"MDQ6VXNlcjE1MzI5NjU4","name":"Ethan"}},{"__typename":"IssueComment","body":"OK - since the stack trace doesn't show anything from the Apollo API, we're not doing any swizzling that could cause the crashes in the stack trace, and there seems to be an issue with the Firebase SDK and other people having this issue seem to also be using Firebase, I'm going to close this issue and direct folks to the [Firebase issue where this is being discussed in significantly more detail](https://github.com/firebase/firebase-ios-sdk/issues/6734). \r\n\r\nThanks all for the heads up on this!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"run-bundled-codegen.sh: No such file or directory","author":{"__typename":"User","login":"mobile-simformsolutions","id":"MDQ6VXNlcjYzMjI1OTEz","name":null},"body":"## run-bundled-codegen.sh: No such file or directory\r\n\r\ni'm implementing this demo as per the documentation (https://www.apollographql.com/docs/ios/tutorial/tutorial-obtain-schema) but after adding script into build phase it will showing me this error:\r\n\r\n**Command PhaseScriptExecution failed with a nonzero exit code**\r\n**Script-3E447D9625386A88004AD507.sh: line 10: /run-bundled-codegen.sh: No such file or directory\r\nCommand PhaseScriptExecution failed with a nonzero exit code**\r\n\r\n![Screenshot 2020-10-16 at 10 32 30 AM](https://user-images.githubusercontent.com/63225913/96215184-e8337a00-0f9a-11eb-8a38-b02591340731.png)\r\n\r\n## Versions\r\n0.34.1\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 12.0.1\r\n- Swift version: 5","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"It looks like you may have skipped step 6, in which you add the build script where the script path is retrieved. It links to [these instructions](https://www.apollographql.com/docs/ios/installation/#adding-a-code-generation-build-step) which are separated out by package manager. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"got it thanks but one suggestion for documentation please make one section where whole script was there.","author":{"__typename":"User","login":"mobile-simformsolutions","id":"MDQ6VXNlcjYzMjI1OTEz","name":null}},{"__typename":"IssueComment","body":"Appreciate the feedback - for what it's worth the reason it's linked is because those instructions had been changing enough that having it in two places meant that it was going to constantly get out of sync. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Help wanted migrating to new Networking stack","author":{"__typename":"User","login":"taher-mosbah","id":"MDQ6VXNlcjIzMDAwODc=","name":"Mohamed Taher Mosbah"},"body":"## Question\r\nGreetings 👋 \r\n\r\nWe are trying to update our custom implementation of a `NetworkTransport` to the new networking stack in version 0.34 but can't seem to figure out where to start, we took a look at the release notes and the documentation `RequestChainNetworkTransport` seems promising but can't figure out how to achieve the same results.\r\n\r\nHere is the current implementation:\r\n\r\n```\r\nimport Foundation\r\nimport Apollo\r\n\r\n/// A network transport that uses HTTP POST requests to send GraphQL operations to a server, and that uses `URLSession` as the networking implementation.\r\npublic class ApolloHTTPGETNetworkTransport: NetworkTransport {\r\n public enum NetworkError: Swift.Error {\r\n case invalidURLComponents\r\n }\r\n\r\n let url: URL\r\n let session: URLSession\r\n let serializationFormat = JSONSerializationFormat.self\r\n let jsonEncoder = JSONEncoder()\r\n\r\n /// Creates a network transport with the specified server URL and session configuration.\r\n ///\r\n /// - Parameters:\r\n /// - url: The URL of a GraphQL server to connect to.\r\n /// - configuration: A session configuration used to configure the session. Defaults to `URLSessionConfiguration.default`.\r\n /// - sendOperationIdentifiers: Whether to send operation identifiers rather than full operation text, for use with servers that support query persistence. Defaults to false.\r\n public init(url: URL, configuration: URLSessionConfiguration = URLSessionConfiguration.default, sendOperationIdentifiers: Bool = false) {\r\n self.url = url\r\n self.session = URLSession(configuration: configuration)\r\n self.sendOperationIdentifiers = sendOperationIdentifiers\r\n }\r\n\r\n /// Send a GraphQL operation to a server and return a response.\r\n ///\r\n /// - Parameters:\r\n /// - operation: The operation to send.\r\n /// - completionHandler: A closure to call when a request completes.\r\n /// - response: The response received from the server, or `nil` if an error occurred.\r\n /// - error: An error that indicates why a request failed, or `nil` if the request was successful.\r\n /// - Returns: An object that can be used to cancel an in progress request.\r\n public func send(operation: Operation, completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable where Operation: GraphQLOperation {\r\n let query = requestBody(for: operation)\r\n guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else {\r\n completionHandler(.failure(NetworkError.invalidURLComponents))\r\n return EmptyCancellable()\r\n }\r\n urlComponents.queryItems = query.compactMap { queryMapItem -> URLQueryItem? in\r\n guard let queryMapItemValue = queryMapItem.value else { return nil }\r\n if let queryMapItemValue = queryMapItemValue as? JSONObject {\r\n guard let queryItemValue = ((try? String(data: JSONSerializationFormat.serialize(value: queryMapItemValue), encoding: .utf8)) as String??) else { return nil }\r\n return URLQueryItem(name: queryMapItem.key, value: queryItemValue)\r\n }\r\n if let queryMapItemValue = queryMapItemValue as? String {\r\n return URLQueryItem(name: queryMapItem.key, value: queryMapItemValue)\r\n }\r\n return nil\r\n }\r\n\r\n var request = URLRequest(url: url)\r\n request.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\r\n request.httpMethod = \"GET\"\r\n request.url = urlComponents.url\r\n let task = session.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Swift.Error?) in\r\n if let error = error {\r\n completionHandler(.failure(error))\r\n return\r\n }\r\n\r\n guard let httpResponse = response as? HTTPURLResponse else {\r\n fatalError(\"Response should be an HTTPURLResponse\")\r\n }\r\n\r\n if !httpResponse.isSuccessful {\r\n completionHandler(.failure(GraphQLHTTPResponseError(body: data, response: httpResponse, kind: .errorResponse)))\r\n return\r\n }\r\n\r\n guard let data = data else {\r\n completionHandler(.failure(GraphQLHTTPResponseError(body: nil, response: httpResponse, kind: .invalidResponse)))\r\n return\r\n }\r\n\r\n do {\r\n guard let body = try self.serializationFormat.deserialize(data: data) as? JSONObject else {\r\n throw GraphQLHTTPResponseError(body: data, response: httpResponse, kind: .invalidResponse)\r\n }\r\n let response = GraphQLResponse(operation: operation, body: body)\r\n completionHandler(.success(response))\r\n } catch {\r\n completionHandler(.failure(error))\r\n }\r\n }\r\n\r\n task.resume()\r\n\r\n return task\r\n }\r\n\r\n private let sendOperationIdentifiers: Bool\r\n\r\n private func requestBody(for operation: Operation) -> GraphQLMap {\r\n if sendOperationIdentifiers {\r\n guard let operationIdentifier = operation.operationIdentifier else {\r\n preconditionFailure(\"To send operation identifiers, Apollo types must be generated with operationIdentifiers\")\r\n }\r\n return [\"id\": operationIdentifier, \"variables\": operation.variables]\r\n }\r\n return [\"query\": operation.queryDocument, \"variables\": operation.variables]\r\n }\r\n}\r\n\r\nfileprivate extension HTTPURLResponse {\r\n var isSuccessful: Bool {\r\n return (200..<300).contains(statusCode)\r\n }\r\n\r\n var statusCodeDescription: String {\r\n return HTTPURLResponse.localizedString(forStatusCode: statusCode)\r\n }\r\n\r\n var textEncoding: String.Encoding? {\r\n guard let encodingName = textEncodingName else { return nil }\r\n\r\n return String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString)))\r\n }\r\n}\r\n\r\n```\r\n\r\nfeel free to ask me any questions about the code and thanks for your time !\r\n\r\n## Versions\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 120.1\r\n- Swift version: 5.3","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"So it looks like you could probably get to this point with what you're doing by passing in a custom `RequestBodyCreator` to `RequestChainNetworkTransport` and then setting the `useGETForQueries` parameter to `true` - I believe almost all the rest of this is handled for you automatically in the RCNT otherwise.\r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@taher-mosbah Anything else I can help with here? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"thanks for your answer, it's clear will try to implement as soon as I got the time 😄 ","author":{"__typename":"User","login":"taher-mosbah","id":"MDQ6VXNlcjIzMDAwODc=","name":"Mohamed Taher Mosbah"}}]}},{"__typename":"Issue","title":"Swift scripting error with xcode 12","author":{"__typename":"User","login":"jdevng","id":"MDQ6VXNlcjI2ODE3NDEw","name":null},"body":"## Bug report\r\n\r\nInitialization of Codegen directory at \r\n\r\nhttps://www.apollographql.com/docs/ios/swift-scripting/\r\n\r\nresults in error.\r\n\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.35\r\n- Xcode version: 12.0.1\r\n- Swift version: Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)\r\n\r\n## Steps to reproduce\r\n```\r\n\r\n% swift packet init --type executable\r\nerror: unable to invoke subcommand: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-packet (No such file or directory)\r\n```\r\n\r\n\r\n## Further details\r\n\r\nPlease replace this line with any further details or context necessary to understand the problem. Delete this section if you don't have anything further to add.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I think you mean `swift package --init` rather than `swift packet --init`","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I'm blind. Will delete :) Thank you. Should learn to copy!","author":{"__typename":"User","login":"jdevng","id":"MDQ6VXNlcjI2ODE3NDEw","name":null}}]}},{"__typename":"Issue","title":"set the timeout of the ApolloCodegenLib","author":{"__typename":"User","login":"wongzigii","id":"MDQ6VXNlcjczODQyODg=","name":"Zigii Wong"},"body":"I am following the guide to download zip file with CLI.\r\nHow can I set the timeout of the ApolloCodegenLib:CLIDownloader ?\r\nMy network is so bad :(\r\n\r\n```\r\nswift run\r\n[DEBUG - ApolloCodegenLib:CLIDownloader.swift:72] - Downloading zip file with the CLI...\r\ndownloadTimedOut(after: 30.0)\r\n```","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"For anyone stumbling across this, all of the methods to call into the codegen lib should have a `timeout` parameter. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Create WebsocketTransport without connecting automatically","author":{"__typename":"User","login":"winstondu","id":"MDQ6VXNlcjgxNzQzMTA=","name":"Winston Du"},"body":"## Feature request\r\n\r\nCurrently, the designated initializer for the WebSocketTransport[ immediately connects the websocket. ](https://github.com/apollographql/apollo-ios/blob/cf537701e407bed1a13df6dd6288d641abdda42a/Sources/ApolloWebSocket/WebSocketTransport.swift#L128)\r\n\r\nWe wish to manually control when it does its first connection.\r\n\r\n## Motivation\r\n\r\nWe want to our app's webservers to able to handle load, and at high traffic times we actually want the ability to disable automatic websocket connections to our server at app startup.\r\n\r\n## Proposed solution\r\n\r\nAdd a parameter to the [designated initializer](https://github.com/apollographql/apollo-ios/blob/cf537701e407bed1a13df6dd6288d641abdda42a/Sources/ApolloWebSocket/WebSocketTransport.swift#L128) on whether the websocket should connect immediately on initialization. In otherwords, wrap the `websocket.connect()` call in an `if` statement.\r\n\r\nAdditional notes: \r\nBecause the mutex-locked `reconnect` parameter only comes into play after the the first disconnection (which can only happen after the first connection), that parameter does not affect things.\r\n \r\n## Outstanding Questions\r\n- It is up to the implementor to decide whether there should be a separate api for the first websocket connection, or if the developer can just call `reconnectWebSocket()`","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Seems like a reasonable request, and thank you for adding a PR! I'll keep feedback over on the PR just for the sake of clarity. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"allowSpecificHTTPSCertificateForHost warning in iOS 14","author":{"__typename":"User","login":"DiwakarThapa","id":"MDQ6VXNlcjI5OTE3Nzk5","name":"diwakar thapa"},"body":"I started receiving following warning on Xcode after I update my iPhone to iOS 14. How to fix this warning? \r\n ## Warning\r\nnil host used in call to allowSpecificHTTPSCertificateForHost: \r\nnil host used in call to allowAnyHTTPSCertificateForHost:\r\nnil host used in call to allowSpecificHTTPSCertificateForHost: \r\nnil host used in call to allowAnyHTTPSCertificateForHost:\r\n\r\n## Network Transport \r\nprivate var networkTransport: HTTPNetworkTransport {\r\n let configuration = URLSessionConfiguration.default\r\n configuration.timeoutIntervalForResource = 65\r\n configuration.timeoutIntervalForRequest = 65\r\n let client = URLSessionClient(sessionConfiguration: configuration)\r\n let transport = HTTPNetworkTransport(url: URL(string: self.baseUrl)!, client: client)\r\n transport.delegate = self\r\n return transport\r\n }\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.30.0\r\n- Xcode version: 11.2.1\r\n- Swift version: 5","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Wow, weird! Never seen that before. We're not doing anything that I'm aware of that should be calling any of those methods. \r\n\r\nWould be curious if this is still happening in versions `0.34.0` and above - we made some pretty significant changes to the networking stack there. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@DiwakarThapa Is there any further information you can share here? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Since I haven't heard back in a couple weeks, I'm going to close this out - @DiwakarThapa if you get more info feel free to reopen. Anyone else with a similar problem, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Initializer default values make it very easy to accidentally create 2 distinct ApolloStore's","author":{"__typename":"User","login":"namolnad","id":"MDQ6VXNlcjYxNDg0ODA=","name":"Dan Loman"},"body":"## Bug report\r\n\r\nCurrently it's very easy, through default initializer values, to end up with multiple ApolloStore's and the inability to properly invalidate your cache. I just spent a fair amount of time debugging this issue, which I think could be resolved by removing some default values in one or both the `ApolloClient`'s and `LegacyInterceptorProvider`'s initializers. The problem is as follows:\r\n\r\n``` swift\r\nlet interceptorProvider: LegacyInterceptorProvider = .init() // More likely to use your own subclass for authentication\r\nlet transport: RequestChainNetworkTransport = .init(\r\n interceptorProvider: interceptorProvider,\r\n endpointURL: baseUrl.appendingPathComponent(\"graphql\")\r\n)\r\nlet client: ApolloClient = .init(\r\n networkTransport: transport\r\n)\r\n```\r\n\r\nThe above code creates two separate `ApolloStore`'s with default caches of `InMemoryNormalizedCache()` for both the `LegacyInterceptorProvider` and for the `ApolloClient`. When going to invalidate your cache here, you will invalidate one of the caches (the ApolloStore one), but the InterceptorProvider's cache will remain untouched, which is where results seem to be fetched from, thus making it impossible to actually invalidate the cache. Without these default values, I believe this problem would be obvious to the developer.\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.0\r\n- Xcode version: 12.0.1\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nInitialize the ApolloClient using default values, as above.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Yeah this is basically a dupe of #1438 - I'm going to take a look at your solution, I was still pondering exactly how to get this set up in a friendlier way. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yup, definitely a dupe — sorry for missing that and thanks for taking a look!","author":{"__typename":"User","login":"namolnad","id":"MDQ6VXNlcjYxNDg0ODA=","name":"Dan Loman"}},{"__typename":"IssueComment","body":"This has shipped with `0.36.0`!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"graphql file with description","author":{"__typename":"User","login":"wongzigii","id":"MDQ6VXNlcjczODQyODg=","name":"Zigii Wong"},"body":"Any way to add description to graphql file? This results in errors in compile time.\r\n\r\nA good example would be:\r\n\r\n```\r\n\"\"\"\r\nA simple GraphQL schema which is well described.\r\n\"\"\"\r\nschema {\r\n query: Query\r\n}\r\n```\r\n\r\nhttp://spec.graphql.org/draft/#sec-Descriptions\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"In theory that should not result in errors - can you give an example of a file where this is resulting in errors, along with the errors? Any information around your setup would also be really helpful. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Just add \r\n\r\n \"\"\"\r\n A simple GraphQL schema which is well described.\r\n \"\"\"\r\n\r\nto the first line of any .graphql file and Build then you will see the error.\r\n\r\n Showing Recent Messages\r\n Error: Syntax error in \r\n\r\n file:///Users/mac/a.graphql: Syntax \r\n\r\n Error: Unexpected Name \"query\".\r\n\r\n","author":{"__typename":"User","login":"wongzigii","id":"MDQ6VXNlcjczODQyODg=","name":"Zigii Wong"}},{"__typename":"IssueComment","body":"Are you trying to add this to your operation graphQL files, or to the Schema graphQL file? This syntax is intended for the schema - you can see an example in [the version of the GitHub Schema we're using for some tests](https://github.com/apollographql/apollo-ios/blob/main/Sources/GitHubAPI/schema.docs.graphql). \r\n\r\nIf you were to try to add this to an operation's graphQL file like: \r\n\r\n```graphQL\r\n\"\"\"\r\nA simple GraphQL schema which is well described.\r\n\"\"\"\r\nquery UserInfo($id: ID!) {\r\n user(id: $id) {\r\n name\r\n }\r\n}\r\n```\r\n\r\nThat would not compile. Does that help? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@wongzigii Any thoughts on my response? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Good to know! Thanks @designatednerd ","author":{"__typename":"User","login":"wongzigii","id":"MDQ6VXNlcjczODQyODg=","name":"Zigii Wong"}}]}},{"__typename":"Issue","title":"Is there any way to have a hybrid cache instead of memory/disk exclusively?","author":{"__typename":"User","login":"malonehedges","id":"MDQ6VXNlcjEyMDkyMjk2","name":"Malone Hedges"},"body":"Is there any official (or community) support for a hybrid cache for Apollo iOS?","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Not at this time but I have had at least one customer talk to us about this. We're gonna be doing some heavy work around the cache in the next couple months but probably after that we can take a look. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Awesome, would love to adopt a hybrid cache when one is available","author":{"__typename":"User","login":"malonehedges","id":"MDQ6VXNlcjEyMDkyMjk2","name":"Malone Hedges"}}]}},{"__typename":"Issue","title":"some thoughts on Interceptors","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"},"body":"## Feedback\r\n\r\nI just update from 0.33.0 to 0.36.0 and want to share some thoughts on Interceptors.\r\n\r\n- confusing what does proceedAsync, handleErrorAsync, retry and kickoff do. If I have error in response and want to retry do I call retry? or kickoff?\r\n- `Request`ChainNetworkTransport but you pass response Interceptors to it (as request and response interceptors are the same list)\r\n- confusing that same call used for request and response, only way to check for response == nil in `interceptAsync`\r\n- `TokenAddingInterceptor` from docs adds Authorization header to request not depending if its request or response. Is that how it should be?\r\n- `RequestChainNetworkTransport` have `additionalHeaders` - shouldn't this be interceptor?\r\n- there is `AutomaticPersistedQueryInterceptor` and also `autoPersistQueries` on `RequestChainNetworkTransport` what should I use?\r\n- There is `LegacyInterceptorProvider` but something not \"legacy\" (`NetworkInterceptorProvider`) only mentioned in documentation. How do I create custom provider where I add only my interceptors and leave \"default\" ones untouched? `NetworkInterceptorProvider` from docs have 10 interceptors, `LegacyInterceptorProvider` have 7. Should I inherit from `LegacyInterceptorProvider` or should I copy one from docs and constantly track if new Interceptor will just appear in the list?\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.36.0\r\n- Swift version: 5.3","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"comment about `TokenAddingInterceptor` is invalid as it is inserted in first place (so it can't be response)","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"> confusing what does proceedAsync, handleErrorAsync, retry and kickoff do. If I have error in response and want to retry do I call retry? or kickoff?\r\n\r\n- `proceedAsync` is called anytime you want to have the chain proceed to the next interceptor\r\n- `handleErrorAsync` is called anytime you want to have the chain return an error to the original caller\r\n- `kickoff` should only be called by you when you want to start the chain from scratch.\r\n- `retry` should be called if you want to retry a request - it will [reset the interceptor index under the hood and call `kickoff` to restart the chain](https://github.com/apollographql/apollo-ios/blob/9c624bbcfa1c8b3b909ee0c53ec43ebb1a50e944/Sources/Apollo/RequestChain.swift#L129). You should use this method rather than trying to reset the index yourself. Basically, don't call `kickoff` on the chain from within an interceptor, call `retry`. \r\n\r\n> RequestChainNetworkTransport but you pass response Interceptors to it (as request and response interceptors are the same list) confusing that same call used for request and response, only way to check for response == nil in interceptAsync\r\n\r\nI'm not totally clear on what the question here is - is it \"Why are we using the same interceptors for preparing a request as handling a response?\" If yes, please confirm, if not, please clarify. Thanks. \r\n\r\n> TokenAddingInterceptor from docs adds Authorization header to request not depending if its request or response. Is that how it should be?\r\n\r\nYes - the idea of that is that you put it first so that it is the first change applied before a request goes out. \r\n\r\n> RequestChainNetworkTransport have additionalHeaders - shouldn't this be interceptor?\r\n\r\nThese are intended to be additional headers that must be added to every single request, and which do not change (for example, an API key or a language setting). The interceptors are intended for things which may change (for example, a user's authentication token). \r\n\r\n> there is AutomaticPersistedQueryInterceptor and also autoPersistQueries on RequestChainNetworkTransport what should I use?\r\n\r\nThe short answer is both - `autoPersistQueries` tells you whether auto-persisted queries should be used at all, and the interceptor does the work of checking for APQ-related errors and auto-retrying when needed. Essentially, `autoPersistQueries` tells you if you should send APQ hashes outgoing, and the interceptor handles incoming responses to tell if you need to retry due to an APQ failure. \r\n\r\n> There is LegacyInterceptorProvider but something not \"legacy\" (NetworkInterceptorProvider) only mentioned in documentation. How do I create custom provider where I add only my interceptors and leave \"default\" ones untouched? NetworkInterceptorProvider from docs have 10 interceptors, LegacyInterceptorProvider have 7. Should I inherit from LegacyInterceptorProvider or should I copy one from docs and constantly track if new Interceptor will just appear in the list?\r\n\r\nYou _can_ inherit from `LegacyInterceptorProvider`, and override the method providing the array of interceptors. This is easier if you're putting interceptors at the beginning or end of the array rather than interspersing them throughout. If they're interspersed, it's likely better create your own implementation of `InterceptorProvider` and using the array provided by `LegacyInterceptorProvider` as a starting point. \r\n\r\nI will call out in release notes if any changes are made to the `LegacyInterceptorProvider`, particularly new interceptors - the intent is that the core interceptors should not change. \r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I was going through a similar thinking process as @RolandasRazma yesterday doing the same 0.33->0.36 migration. Would be super helpful if you added these explanations to the documentation for other people. ","author":{"__typename":"User","login":"Nealsoni00","id":"MDQ6VXNlcjcwMTMxOTE=","name":"Neal Soni"}},{"__typename":"IssueComment","body":"Have y'all had a chance to read through [the updated client creation documentation](https://www.apollographql.com/docs/ios/initialization/#advanced-client-creation), particularly the [section on how the request chain works](https://www.apollographql.com/docs/ios/initialization/#how-the-requestchain-works)? I would be particularly interested in where you feel like that's not clear enough. Thanks!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I did, I think for me most confusion would have been averted if:\r\n\r\n- there would be 2 lists: pre server call and post server call having different call signature (no reply in \"pre\" ones)\r\n- there would be no \"Legacy\" in class names as it made not clear what to use\r\n- don't feel feel comfortable of just copying list of \"default\" interceptors as that list might change without the realising","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"> there would be 2 lists: pre server call and post server call having different call signature (no reply in \"pre\" ones)\r\n\r\nOne of the reasons I went with a single chain is we've had repeated feature requests to have the data associated with what was being requested passed through to the completion handler. I will be taking a look at some options based on feedback here, I think maybe there could be some other options that might make `NetworkTransport` unnecessary and allow the user to send data through any transport (ie, send it with a websocket if you really feel like it). \r\n\r\n> there would be no \"Legacy\" in class names as it made not clear what to use\r\n\r\nOK. I believe I tried to explain \"Legacy\" vs \"Codable\" as \"What we've been using\" vs \"What we will be using in the future\" in those docs, but it sounds like that didn't help. I'll try to clarify that.\r\n\r\n> don't feel feel comfortable of just copying list of \"default\" interceptors as that list might change without the realising\r\n\r\nI mean, that's going to be a problem no matter what if you need to intersperse different interceptors - if you're subclassing hte default list and relying on the default order in terms of where to insert your interceptors, that's going to cause problems too. Again, I can certainly commit to making sure I make it very clear in release notes when any of this changes. \r\n","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@RolandasRazma @Nealsoni00 I've just opened a PR with updated docs. Would love your feedback on #1484. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> One of the reasons I went with a single chain is we've had repeated feature requests to have the data associated \r\n\r\nEverything could still work as it does now under the hood. 2 list would allow to not have \"response\" in pre list\r\n\r\n> I mean, that's going to be a problem no matter what\r\n\r\nthat's not necessary true if there would be 2 lists as in most cases you need \"pre action\" and \"post action\"\r\n\r\n\r\nI already migrated and now it's more clear what's going on so I'm not advocating for a change. Most likely all new users will do better as they have no expectations ","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"> 2 list would allow to not have \"response\" in pre list\r\n\r\nThat's fair. \r\n\r\n> I'm not advocating for a change.\r\n\r\nI think if we're gonna make one it's better to do it sooner rather than later, honestly. I also need to think a few things over, to be honest.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"OK, I've merged #1464. I will continue to think about what could work to make it easier to deal with when an interceptor will be called - pre or post response - and see what I can come up with. However, I wanted to check - do you feel there's anything else here that still needs to be directly addressed before we can close this issue out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I will close it","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"@RolandasRazma thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Crash in 0.36.0","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"},"body":"## Bug report\r\n\r\nCrash using interceptors\r\n\r\n\"Screenshot\r\n\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.36.0\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nI have TokenAddingInterceptor that retrieves token from server and asynchronously calls `chain.proceedAsync`. I have check for TokenAddingInterceptor being released to not call up the chain on dealloc, so that's not the case.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"The crash is happening in the `URLSessionClient` rather than in any of the interceptors - it looks like the client either a) Hasn't had a chance to set up its `URLSession` or b) has had the session torn down. \r\n\r\nCan you share how you're setting up your `TokenAddingService`? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"There is nothing interesting to see there. It just check for token validity if it it expired updates it from server and calls back. I will try to trace/fix crash as it's blocking us, but as its another race condition its not going to be simple as I can't even replicate it reliably. Sometimes it crashes every run (tests) sometimes I hit https://github.com/apollographql/apollo-ios/issues/1376 and sometimes all tests passes without any problem :)","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"I can replicate it with example from https://www.apollographql.com/docs/ios/tutorial/tutorial-mutations/\r\n\r\n```swift\r\nclass TokenAddingInterceptor: ApolloInterceptor {\r\n func interceptAsync(chain: RequestChain, request: HTTPRequest, response: HTTPResponse?, completion: @escaping (Result, Error>) -> Void) {\r\n DispatchQueue.main.async { [weak self] in\r\n guard self != nil else { return }\r\n chain.proceedAsync(request: request, response: response, completion: completion)\r\n }\r\n }\r\n \r\n}\r\n```","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"This is how memory graph looks for crashing client\r\n\r\n\"Screenshot\r\n","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"NetworkFetchInterceptor:32 don't you need `self.currentTask?.cancel()` before it?\r\n\r\nP.S. adding cancel didn't stop crash, but still, don't you need it there? (made PR https://github.com/apollographql/apollo-ios/pull/1476)","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"Ok, what's happening is that `RequestChain` (created in `RequestChainNetworkTransport`) lifetime is longer than `LegacyInterceptorProvider` and `LegacyInterceptorProvider` does `shouldInvalidateClientOnDeinit` \r\n\r\n`RequestChain` is created in `RequestChainNetworkTransport`, `LegacyInterceptorProvider` is released invalidating client and `RequestChain` knows nothing about it. \r\n\r\nI managed to \"solve\" it by retaining link to chain in `RequestChainNetworkTransport` and canceling it in `deinit` - not sure if that's correct thing to do, as that would imply that I need to cancel it on send as well (or retain all references created by send)","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"sorry for spam @designatednerd ","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"I thought not retaining chain would help\r\n\r\n```swift\r\nclass TokenAddingInterceptor: ApolloInterceptor {\r\n func interceptAsync(chain: RequestChain, request: HTTPRequest, response: HTTPResponse?, completion: @escaping (Result, Error>) -> Void) {\r\n DispatchQueue.main.async { [weak self, weak chain] in\r\n guard self != nil else { return }\r\n chain?.proceedAsync(request: request, response: response, completion: completion)\r\n }\r\n }\r\n \r\n}\r\n```\r\n\r\nbut that's not the case - it is deallocated before we can update token and call to server never executed","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"right - if you let go of the chain there there's nothing hanging on to it, so ARC smashes it. \r\n\r\nI'm surprised the legacy interceptor provider is getting deallocated - that indicates that the Request Chain Network Transport itself is getting deallocated. I would really like to see how you're setting this stuff up for tests - it seems like maybe something is calling into an old instance of RCNT in different tests. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"`RequestChainNetworkTransport` is deallocated, but the problem is not that it is deallocated, the problem is that it doesn't cleanup properly while it does that\r\n\r\n```swift\r\nclass TokenAddingInterceptor: ApolloInterceptor {\r\n func interceptAsync(chain: RequestChain, request: HTTPRequest, response: HTTPResponse?, completion: @escaping (Result, Error>) -> Void) {\r\n DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in\r\n guard self != nil else { return }\r\n chain?.proceedAsync(request: request, response: response, completion: completion)\r\n }\r\n }\r\n}\r\n\r\nlet transport = RequestChainNetworkTransport(...)\r\nlet apolloClient = ApolloClient(networkTransport: transport, ...)\r\napolloClient.fetch(query: ...)\r\n```\r\n\r\nwill make whole app crash in 1 second because `ApolloClient` will be deallocated together with `RequestChainNetworkTransport` while `RequestChain` will be retained by block (and it has to be)\r\n\r\nCrash will happen because deallocatingin `LegacyInterceptorProvider` will call `client.invalidate()` that will nil `URLSessionClient.sesion` and after 1 sec it will be accessed with force unwrap","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"this is the crash https://github.com/apollographql/apollo-ios/pull/1480","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"I guess easy workaround would be to remove force unwrap, but the real problem is that `RequestChain` don't know that it is no longer needed. Correct fix would be to add \"cancel\" for chain in `RequestChainNetworkTransport` as mentioned in https://github.com/apollographql/apollo-ios/issues/1473#issuecomment-717173144 the only difficulty it that there is multiple chains per transport and all of them needs to be cancelled","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"Created PR with workaround https://github.com/apollographql/apollo-ios/pull/1481 but somehow don't fee good about it :) It doe's work, but feels like some code smell","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"should I close this?","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"I'll close it when it actually ships","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"GraphQLError parsing issue in response?.parsedResponse ","author":{"__typename":"User","login":"StanislavCekunov","id":"MDQ6VXNlcjk3NzQ0Nzc=","name":null},"body":"Hello Apollo community,\r\nI am currently updating our codebase to support `RequestChainNetworkTransport` interface. \r\nIn a previous structure I used `HTTPNetworkTransportGraphQLErrorDelegate` to catch `GraphQLError` to initiate access token update and retryHandler to retry faild request. \r\n\r\nWith the new `RequestChain` structure I am perfoming same action inside ResponseCodeInterceptor. Though, `GraphQLError` is not being parced anymore. I am accessing it by `response?.parsedResponse?.errors`\r\n\r\nHere is the response raw data: \r\n`{\"errors\":[{\"message\":\"Access denied\",\"path\":[\"getUserDetails\"],\"locations\":[{\"line\":2,\"column\":1}],\"extensions\":{\"code\":\"accessTokenExpired\"}}],\"data\":null}`\r\n\r\nWould love to get some help or suggestions where is the right way to fetch `GraphQLError` this time.\r\nAm I doing something wrong? \r\nThanks\r\n\r\n## Versions\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.36.0\r\n- Swift version: 5.3\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I would probably do this check in an interceptor that runs after `LegacyParsingInterceptor` - that's where the actual parsing takes place, and after it's gone through that inteceptor, you should be able to access it using `response?.parsedResponse?.errors`. \r\n\r\nThe `ResponseCodeInterceptor` that's provided by default is mostly just checking to make sure the response code is something vaguely sane before attempting to parse the result","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Thank you @designatednerd !\r\nI have added a new interceptor `AccessTokenValidationInterceptor` right after `LegacyParsingInterceptor`. \r\nSolved. 🙌 \r\n\r\n","author":{"__typename":"User","login":"StanislavCekunov","id":"MDQ6VXNlcjk3NzQ0Nzc=","name":null}},{"__typename":"IssueComment","body":"@StanislavCekunov Mind if we close this out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Using same query with different set of fields","author":{"__typename":"User","login":"vani2","id":"MDQ6VXNlcjQ3MzQ5ODM=","name":"Ivan Vavilov"},"body":"## Question\r\n\r\nI have query of `draftProfile` and `profile`\r\n\r\n```GraphQL\r\nquery fetchProfile {\r\n draftProfile {\r\n firstName\r\n secondName\r\n },\r\n profile {\r\n firstName\r\n secondName \r\n }\r\n}\r\n```\r\n\r\nLater I need to make the same query but only `profile` object.\r\n\r\n```GraphQL\r\nquery fetchProfile {\r\n profile {\r\n firstName\r\n secondName \r\n }\r\n}\r\n``` \r\n\r\nIf I declare these two queries I get the error `There are multiple definitions for the `fetchProfile` operation. Please rename or remove all operations with the duplicated name before continuing.`.\r\n\r\nHow I can make it possible? \r\n\r\n## Versions\r\n\r\n- `apollo-ios` SDK version: 0.35\r\n- Xcode version: 12.0\r\n- Swift version: 5.3","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"You need to give the two queries different names at the `query fetchProfile` point. Maybe `query fetchProfileWithDraft` for that top one and just `fetchProfile` for the bottom one? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Oh, yes, that's easy. Thanks.","author":{"__typename":"User","login":"vani2","id":"MDQ6VXNlcjQ3MzQ5ODM=","name":"Ivan Vavilov"}}]}},{"__typename":"Issue","title":"XCode 12 : Could not find module ‘Apollo’ for target ‘arm64-apple-ios-simulator’; found: x86_64-apple-ios-simulator, x86_64","author":{"__typename":"User","login":"poorvasingh04","id":"MDQ6VXNlcjIwMDkwODU5","name":"Poorva Singh"},"body":"## Bug report\r\n\r\nXCode 12 : Could not find module ‘Apollo’ for target ‘arm64-apple-ios-simulator’; found: x86_64-apple-ios-simulator, x86_64\r\nUnable to build app against iOS simulator using XCode 12.\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.27.1 and 0.36.0\r\n- Xcode version: 12\r\n- Swift version: 5\r\n\r\n## Steps to reproduce\r\nBuild code against iOS simulator. I am using app to build against iOS simulator for UI tests.\r\n\r\n## Further details\r\n\r\nCode fails to compile. I also added following post install script in podfile:\r\n\r\npost_install do |pi|\r\n pi.pods_project.targets.each do |t|\r\n t.build_configurations.each do |config|\r\n config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0'\r\n config.build_settings[\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\"] = \"arm64\"\r\n end\r\n end\r\nend\r\n\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"It looks like your post-install script's change `EXCLUDED_ARCHS` is actively excluding the `arm64` type that the compiler is looking for. Is there a particular reason why you're excluding that? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd yes. To compile with Xcode 12 against iOS simulator, we need to exclude arm64 architecture in app and all the linked pods. This is same issue as described here: https://stackoverflow.com/questions/63607158/xcode-12-building-for-ios-simulator-but-linking-in-object-file-built-for-ios","author":{"__typename":"User","login":"poorvasingh04","id":"MDQ6VXNlcjIwMDkwODU5","name":"Poorva Singh"}},{"__typename":"IssueComment","body":"Interesting - there's a related suggestion in there about making sure that `ONLY_ACTIVE_ARCH` is set to yes for your debug setup. In a sample CocoaPods app I've got where that's set up I have not seen this issue.\r\n\r\nI *think* as long as you're not building on a developer transition kit, setting that up should help with this, since it seems like Xcode is trying to build the universe, then complaining that the thing you specifically told it not to build isn't there.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd ONLY_ACTIVE_ARCH is already set to Yes","author":{"__typename":"User","login":"poorvasingh04","id":"MDQ6VXNlcjIwMDkwODU5","name":"Poorva Singh"}},{"__typename":"IssueComment","body":"🤔 That's...very odd if you're not on a developer transition kit. Are you on a developer transition kit? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd no. I am not in a developer transition kit. I am trying to build app against simulator for my UI tests but it fails with Xcode 12.1","author":{"__typename":"User","login":"poorvasingh04","id":"MDQ6VXNlcjIwMDkwODU5","name":"Poorva Singh"}},{"__typename":"IssueComment","body":"Here's a couple other things I can think of that are unlikely but worth checking: \r\n\r\n- If there's more than one target in your project, are all targets in your project set for `ONLY_ACTIVE_ARCH`, or just the main application?\r\n- Is your scheme set to run the tests in release mode rather than debug mode? \r\n- Is there something about XCUI tests that's trying to build the app for release even though your tests are set in debug?\r\n\r\nIf none of those turn up the problem, do you mind either emailing me your project or a sample project that reproduces this issue? ellen at apollographql dot com. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Were you ever able to figure this out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Race condition when unsubscribing","author":{"__typename":"User","login":"marioradonic","id":"MDQ6VXNlcjQxNTg3Mzc=","name":null},"body":"## Bug report\r\n\r\nI've been randomly (but often) getting `.unprocessedMessage` errors in my `.subscribe(...` handlers. I had a look at the code and it seems to me that there is a possible race condition.\r\n\r\nWhen [unsubscribing](https://github.com/apollographql/apollo-ios/blob/e0f65fee8c197239dbefbf1386b8e7f83b684f25/Sources/ApolloWebSocket/WebSocketTransport.swift#L301) from a subscribe task websocket message is sent requesting the subscription to stop and handler is released. It might be possible that a message is received from the socket with the update before the backend has time process this stop message and stop sending the messages. So in the [processMessage](https://github.com/apollographql/apollo-ios/blob/e0f65fee8c197239dbefbf1386b8e7f83b684f25/Sources/ApolloWebSocket/WebSocketTransport.swift#L146) method we end up in [this clause](https://github.com/apollographql/apollo-ios/blob/e0f65fee8c197239dbefbf1386b8e7f83b684f25/Sources/ApolloWebSocket/WebSocketTransport.swift#L177) because there is no subscription handlers any more. And then **all** the other handlers are notified about this error. This doesn't seem right to me as there was nothing wrong with other subscriptions.\r\n\r\nI'm not an expert in web sockets, so I don't know what the best solution would be. Maybe wait for the ack message from backend? But then the subscriber might get a message after cancelling the task, which is not nice. Maybe keep an intermittent array of task ids whose cancellation hasn't been acknowledged by the backend and ignore messages for those subscribers? That is if there is a stop acknowledge message from backend.\r\n\r\nI don't mind creating a PR if someone suggests the approach on how to fix this.\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.35.0\r\n- Xcode version: 12.1\r\n- Swift version: 5.3\r\n\r\n## Steps to reproduce\r\n\r\nI have a rx code in format of:\r\n`subscribeSomething().flatMapLatest { subscribeSomethingElse(using: $0) }`\r\n\r\nWhen the first subscription updates the second one is cancelled and new one is created.\r\n\r\n## Further details\r\n\r\nI can probably restructure my query so it's all done in one subscription, which would fix my issue but the underlying problem will still be there although it might happen less often.\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"I don't have any bright ideas on this one, websockets are also not my area of expertise. \r\n\r\n@fassko, if you're around, would love to hear any thoughts you have.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I was using GraphQL subscriptions with just one subscription. Otherwise, you can run into these weird side effects that you explained.","author":{"__typename":"User","login":"fassko","id":"MDQ6VXNlcjI5NDgy","name":"Kristaps Grinbergs"}},{"__typename":"IssueComment","body":"@fassko Well, it was worth a shot 🙃\r\n\r\n@marioradonic - Are you subscribing to the same `subscription` from your schema multiple times, or are there different `subscription`s defined that you're using? Basically, are your multiple subscriptions all returning the same information, or different information?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@designatednerd I am using multiple. Basically, I am subscribing to entity A, and when it updates I subscribe to entity B, cancelling the previous B subscription if there was any. (this cancelled subscription causes the problem - if the message comes from the backend with the cancelled subscription id the first entity A subscriber and the new B subscriber get the error message.\r\n\r\nI had another look at the websocket connection and it seems there is no closing acknowledgment message from the backend upon closing the subscription. So I'm not sure at which point should an unhandled message be considered an internal error. In any case I don't think it's a good API design that all the other subscribers get the error message, since nothing is wrong with their subscriptions. Maybe there could be a global error handler for these kinds of errors?\r\n\r\n","author":{"__typename":"User","login":"marioradonic","id":"MDQ6VXNlcjQxNTg3Mzc=","name":null}},{"__typename":"IssueComment","body":">cancelling the previous B subscription if there was any. \r\n\r\nIn theory you shouldn't have to cancel any existing subscription to entity B - if you've already got a running subscription it should continue to get all updates.\r\n\r\nIt may help me understand a bit better if you can give a concrete example of what entity A and entity B are representing. To take an example from our sample code, if you've subscribed to all reviews of Star Wars episodes, then as soon as you get a review of _Return of the Jedi_ kick off a second subscription that only handles _Jedi_ reviews, any further reviews that come in on that first subscription for _Jedi_ would also come in on the second subscription, without needing to stop and restart. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"spectrum.chat/apollo link is unavailable, Heroku error shown","author":{"__typename":"User","login":"gemmakbarlow","id":"MDQ6VXNlcjMzNzk2Mw==","name":"Gemma Barlow"},"body":"## Bug report\r\n\r\nMorning folks ! \r\n\r\nNot technically an Apollo bug, but I wanted to flag that https://spectrum.chat/apollo, linked from [CONTRIBUTING.md](https://github.com/apollographql/apollo-ios/blob/main/CONTRIBUTING.md), is currently returning a Heroku error.\r\n\r\n\"Screen\r\n\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- N / A\r\n\r\n## Steps to reproduce\r\n\r\n- N / A\r\n\r\n## Further details\r\n\r\nPlease feel free to close this if it isn't something you are in control of / hosting yourselves. I wasn't able to find a status page for the tool / platform and am not familiar with it. Google results get mixed in with the ISP provider unfortunately. 😄 ","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Haha, i have the same problem with the ISP, particularly since they are _my_ ISP. \r\n\r\nSpectrum is a chat platform that got bought out by GitHub about a year and a half ago - we'd been using them prior to that buyout and have been continuing to do so. Thanks for the heads up on this, but unfortunately there isn't much we can do about their deploys failing. Upside is it seems to be back up and running now, though!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"How to handle errors correctly","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null},"body":"Hi,\r\nI am currently on the stage of migrating from 0.33 -> 0.36. Gone through all the provided documentation, but I am still confused on what would be the correct way of handling errors(also read the suggested article: https://medium.com/@sachee/200-ok-error-handling-in-graphql-7ec869aec9bc).\r\n\r\nBefore going to write this question, I just wanted to give it a try myself.\r\nOne of the most important use cases related to error handling is that we want to cover the case when a auth token expires on the backend, which results in an error when performing the next app query or mutation. At this stage, we want to catch the error, perform automatically a relogin(call `login` mutation), which basically will return a new auth token and after all that re-execute the failed request(query/mutation).\r\nAs far as I managed to understand, the best way to do this is through `ApolloErrorInterceptor`, which I basically did. I created a custom `ApolloErrorInterceptor`, returned it in `InterceptorProvider.additionalErrorInterceptor`.\r\nThe first problem I met is that it seems that not absolutely all errors get through this interceptor. Which left me without ideas on how to continue, but since this new apollo sdk approach is pretty fresh, I also left some space to consider it might be a bug, `full stop`.\r\n\r\nNow my question is: what is the correct way of handling errors? Can we improve the documentation to provide more examples about it?\r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Interesting, I thought it was me but maybe `InterceptorProvider.additionalErrorInterceptor` is not what we expect.\r\nI just went through same update and had same problem as you do. what worked for me was:\r\n\r\n```swift\r\n/// InterceptorProvider\r\n func interceptors(for operation: Operation) -> [ApolloInterceptor] {\r\n return [\r\n MaxRetryInterceptor(),\r\n LegacyCacheReadInterceptor(store: self.store),\r\n TokenAddingInterceptor(...),\r\n NetworkFetchInterceptor(client: self.client),\r\n TokenErrorInterceptor(...),\r\n ResponseCodeInterceptor(),\r\n LegacyParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject),\r\n AutomaticPersistedQueryInterceptor(),\r\n LegacyCacheWriteInterceptor(store: self.store),\r\n ]\r\n }\r\n\r\n func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? {\r\n return nil\r\n }\r\n```\r\n\r\n```swift\r\n/// TokenErrorInterceptor\r\n func interceptAsync(chain: RequestChain, request: HTTPRequest, response: HTTPResponse?, completion: @escaping (Result, Error>) -> Void) {\r\n guard\r\n let responseStatusCode = response?.httpResponse.statusCode,\r\n responseStatusCode == 401\r\n else {\r\n chain.proceedAsync(request: request, response: response, completion: completion)\r\n return\r\n }\r\n \r\n tokenService.renewAccessToken { [weak self] (error: OAuthSwiftError?) in\r\n guard self != nil else { return }\r\n \r\n if let error = error {\r\n chain.handleErrorAsync(error, request: request, response: response, completion: completion)\r\n } else {\r\n chain.retry(request: request, completion: completion)\r\n }\r\n }\r\n }\r\n```\r\n\r\nneither `additionalErrorInterceptor` nor having `TokenErrorInterceptor` after `ResponseCodeInterceptor` worked","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"`additionalErrorInterceptor` is generally intended for error handling *after* something has been dealt with by the request chain. In this case, you want to deal with it *within* the request chain, so that you can call retry. \r\n\r\n@RolandasRazma's example is a great one if the token error is coming back from middleware and causing a `401 Unauthorized` to be returned. \r\n\r\nIf there's something within GraphQL that's returning the error, you'll get a `200 OK` and an error on `GraphQLResult`'s `errors` property. In that case, you would want to insert your `TokenErrorInterceptor` after the `LegacyParsingInterceptor`, since that's where those would actually be parsed.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> `additionalErrorInterceptor` is generally intended for error handling _after_ something has been dealt with by the request chain.\r\n\r\nJust for the sake of understanding it better, what does it mean and why in some particular conditions it is not called.? I guess some of the docs needs to be more explicit about the use cases when it should be used.","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null}},{"__typename":"IssueComment","body":"It only wouldn't be called if it doesn't exist. It's designed to be a place to have all errors, no matter what the origin, pass through before being handed back to the caller. This allows for things like error logging that are hard to do without a centralized error handler. \r\n\r\nI'll work on clarifying this in the docs.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@odanu @RolandasRazma Added some docs on the additional error interceptor to #1484 ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"OK, that's merged - is there anything else here I can help clarify, or do you mind if we close this out?","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I think you can close this ticket. Though you have to maybe give it a try for different use cases around `additionalErrorInterceptor`. As written above, it looks like it doesn't catch all the errors.","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null}},{"__typename":"IssueComment","body":"> nor having `TokenErrorInterceptor` after `ResponseCodeInterceptor` worked\r\n\r\nHere the issue would be that the `401` response code would be caught by the `ResponseCodeInterceptor` [and returned as an error through `handleErrorAsync`](https://github.com/apollographql/apollo-ios/blob/a00031c2a357c03a2f58a5dda0afb35462dfef42/Sources/Apollo/ResponseCodeInterceptor.swift#L44) (which in turn [calls the `additionalErrorInterceptor` if it exists](https://github.com/apollographql/apollo-ios/blob/a00031c2a357c03a2f58a5dda0afb35462dfef42/Sources/Apollo/RequestChain.swift#L149)) and the chain would not proceed. \r\n\r\nThat would mean `TokenErrorInterceptor` wouldn't get called because an error has already been caught. That's why you have to put it before the `ResponseCodeInterceptor`. \r\n\r\nDoes that help explain why that wouldn't work? Or is there another place where things aren't showing up where you expect them to? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"No Ellen. I was not referring this part. Let's sum up again the thoughts.\r\nThe documentation and you, assures that `additionalErrorInterceptor` gets called, having the error which was collected in any of the interceptors. Which basically means that no matter at which level of the request/response/parsing/etc an error occurs, it will arrive to the `additionalErrorInterceptor`.\r\nNow as mentioned in the initial question, it seems that not all of the errors reach the `additionalErrorInterceptor`. That was my initial test. I just thought it would be the right place to handle all the errors, but got blocked because some of the errors didn't get to it. Check the question again please :).","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null}},{"__typename":"IssueComment","body":"Right, and my question is, what are the errors that are not passed through in your testing? \r\n\r\nNote that if there is an _expected_ error, which is handled by the interceptor (for example, the auto-persisted-query-specific error which is handled by the `AutomaticPersistedQueryInterceptor`), then that is not passed on since that is an error that was expected and handled. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"I will try to collect the information tomorrow;)","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null}},{"__typename":"IssueComment","body":"So I can find 2 cases when `additionalErrorInterceptor` is not used:\r\n1. when an interceptor caught the error triggered retry... the example with expired token\r\n2. `GraphQLError` objects which arrive through `GraphQLResults.errors` array.\r\n\r\nBut I guess both of these cases is expected behaviour.","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null}},{"__typename":"IssueComment","body":"You're correct - because a `GraphQLResult` can contain partial results with an error explaining what's missing, simply having `errors` be non-empty doesn't indicate that a request failed. \r\n\r\nYou can see an example of where we're looking for _specific_ errors to handle in that array in the `AutomaticPersistedQueryInterceptor`, and if you know your backend will be returning _specific_ errors you need to handle in that array (for example, token expiration errors there instead of as a 401), you can add your own interceptors to handle those. \r\n\r\nOtherwise, `GraphQLError`s should be returned as part of the `GraphQLResult`.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"@odanu Anything else here or can I close this out? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Oh sorry. All good. I had to close it earlier.","author":{"__typename":"User","login":"odanu","id":"MDQ6VXNlcjExMTA0MDg=","name":null}},{"__typename":"IssueComment","body":"👍 Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"How to fix that error?","author":{"__typename":"User","login":"zinminphyo","id":"MDQ6VXNlcjMzMzY4MzQ3","name":"Zin Min Phyo"},"body":"## Bug report\r\n\r\nPlease replace this line with a short description of the problem. Make sure you've read `CHANGELOG.md` in the root of the repo to make sure a new version hasn't already addressed your problem!\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.34.1\r\n- Xcode version: 12.0\r\n- Swift version: 5\r\n\"Screen\r\n\r\n- Package manager:\r\n\r\n## Steps to reproduce\r\n\r\nPlease replace this line with steps to reproduce the problem.\r\n\r\n## Further details\r\n\r\nPlease replace this line with any further details or context necessary to understand the problem. Delete this section if you don't have anything further to add.","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"@zinminphyo Can you please share more details about when and how this happened? It's not something I can necessarily tell you why it's happening without more detail. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Since I haven't gotten any further details here, I'm going to close this out. @zinminphyo Please reopen with further details if you have them. Anyone else with a similar problem, please open a new issue. Thank you!","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Generate Apollo GraphQL Api Bitrise issue","author":{"__typename":"User","login":"Kevin94singh","id":"MDQ6VXNlcjIxMzQ3NDg5","name":"Kevin Singh"},"body":"Hi,\r\n\r\nWhen building on a local machine with Fastlane, everything works ok. However, when I try to upload my build with Bitrise, I'm getting an error: \r\n\r\n```\r\n- ▸ Running script 'Generate Apollo GraphQL API'\r\n** ARCHIVE FAILED **\r\nThe following build commands failed:\r\n\tPhaseScriptExecution Generate\\ Apollo\\ GraphQL\\ API /Users/vagrant/Library/Developer/Xcode/DerivedData/project_name-asogvanbfzdyhybkhoculdmlwwfk/Build/Intermediates.noindex/ArchiveIntermediates/project_name_beta/IntermediateBuildFilesPath/project_name.build/Release-iphoneos/project_name_beta/Script-7A325491234C77FE003B1AE2.sh\r\n(1 failure)\r\n[11:36:34]: Exit status: 65\r\n```\r\n**Our Generate Apollo GraphQL API script**\r\n\r\n```\r\nSCRIPT_PATH=\"${PODS_ROOT}/Apollo/scripts\"\r\ncd \"${SRCROOT}/ProjectName\"\r\n\"${SCRIPT_PATH}\"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile=\"schema.json\" API.swift\r\n```\r\n\r\n| - project_folder\r\n | project.xcodeproj\r\n | - target_folder \r\n | schema.json\r\n | AppDelegate.swift\r\n | ViewController.swift\r\n | etc...\r\n | - another_folders\r\n | etc...\r\n\r\n**Apollo version: 0.30, iOS, Bitrise Fastlane version 2.7.x ** We have two targets (prod and beta), currently trying to build for Beta.\r\n\r\nI think that there might be an issue with NPM. In our workflow on Bitrise, I've set `run npm command`- `install -g apollo@2.25` - the version I have on my machine. But this step doesn't help. \r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"If you're using `run-bundled-codegen` it shouldn't be an issue with NPM - the bundled codegen downloads Node and all dependencies as a workaround because we were having *so* many problems with NPM. It certainly seems like another issue is happening that's causing the code generation to fail but isn't spitting out a reason correctly. \r\n\r\nI take it things build correctly when you try to run this locally? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"> If you're using `run-bundled-codegen` it shouldn't be an issue with NPM - the bundled codegen downloads Node and all dependencies as a workaround because we were having _so_ many problems with NPM. It certainly seems like another issue is happening that's causing the code generation to fail but isn't spitting out a reason correctly.\r\n> \r\n> I take it things build correctly when you try to run this locally?\r\n\r\nYes, when I run this locally with Fastlane, it builds correctly.","author":{"__typename":"User","login":"Kevin94singh","id":"MDQ6VXNlcjIxMzQ3NDg5","name":"Kevin Singh"}},{"__typename":"IssueComment","body":"Weird - and are you using Fastlane on bitrise as well, or something else? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yes, we are using Fastlane. Our steps for a workflow are Activate SSH Key, Git Clone repository, and Fastlane (set to a version 2.x.x, that is currently 2.7.1).","author":{"__typename":"User","login":"Kevin94singh","id":"MDQ6VXNlcjIxMzQ3NDg5","name":"Kevin Singh"}},{"__typename":"IssueComment","body":"Cool, thanks for clarifying - how are you setting things to \"beta\" - using a Scheme or a build configuration or some combination thereof? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"We have two schemes - \"beta\" and \"prod\". Each has its own target. The script is implemented in both targets .","author":{"__typename":"User","login":"Kevin94singh","id":"MDQ6VXNlcjIxMzQ3NDg5","name":"Kevin Singh"}},{"__typename":"IssueComment","body":"And am I correct in assuming the `.graphql` files and `API.swift` output are in the same folder (under `\"${SRCROOT}/ProjectName\"`), just shared between both targets? \r\n\r\nHonestly, if it's working locally and the only error info you're getting from Bitrise is a generic exit code 65, I'm not sure how much help I can be - you may want to reach out to them to see if you can get more detailed logs about what's not building on your beta version. \r\n\r\nOne thing I have tried in the past when something's building locally but not on CI for me is to check it back out in a separate folder and try from there - I've definitely found issues where there's some kind of local config not checked into version control that means it works in your main working directory, but not for anyone else (including CI) that checks it out. Probably worth a shot just to rule that out as a cause.","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Yes, it is shared between both targets. Prod build shows the same failure as a beta. \r\n\r\nI'll try to get more detailed logs and let you know. Thank you for your time! 😊","author":{"__typename":"User","login":"Kevin94singh","id":"MDQ6VXNlcjIxMzQ3NDg5","name":"Kevin Singh"}}]}},{"__typename":"Issue","title":"callbackQueue is not used in WebSocketTransport","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"},"body":"## Bug report\r\n\r\nhttps://github.com/apollographql/apollo-ios/blob/185d6b784538691b5a4287c25df9cae140abec02/Sources/ApolloWebSocket/WebSocketTransport.swift#L361 callbackQueue is unused\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.36.0\r\n\r\n## Steps to reproduce\r\n\r\nsubscribe using any callbackQueue, callback is done on some internal one","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Welp, that's embarrassing. Fix is up in #1507. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"thanks","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"Thank YOU for catching it","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"WebSocketTransport.send completionHandler is called in non escaping manner in case of error","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"},"body":"## Bug report\r\n\r\nhttps://github.com/apollographql/apollo-ios/blob/185d6b784538691b5a4287c25df9cae140abec02/Sources/ApolloWebSocket/WebSocketTransport.swift#L364\r\n\r\ncompletionHandler is called in non escaping manner in case of error\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.36.0","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Do you mean it's not called on the callback queue? ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"Was thinking about @escaping but yes, calling it on callback cue would fix that","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}},{"__typename":"IssueComment","body":"It's declared as [`@escaping` here](https://github.com/apollographql/apollo-ios/blob/185d6b784538691b5a4287c25df9cae140abec02/Sources/ApolloWebSocket/WebSocketTransport.swift#L362) - declaring escaping does not require it to escape, though. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}},{"__typename":"IssueComment","body":"sure, but it might break flow depending on what's happening internally\r\n\r\n```swift\r\nWebSocketTransport.send {\r\n print(\"a\")\r\n}\r\n\r\nprint(\"b\")\r\n```\r\n\r\nwhat order will be output depends on internal state and that's not great.\r\n\r\nIn any case, closing as https://github.com/apollographql/apollo-ios/pull/1507 fixes it","author":{"__typename":"User","login":"RolandasRazma","id":"MDQ6VXNlcjEwMjcxODc=","name":"Rolandas Razma"}}]}},{"__typename":"Issue","title":"Compatibility issues on Linux with CommonCrypto","author":{"__typename":"User","login":"abdimaye","id":"MDQ6VXNlcjI5MDIzNzI2","name":null},"body":"## Feature request\r\n\r\nThe CommonCrypto module is only available in Xcode 10+. It would be nice to have this replaced with an open source module such that the apollo client can run on other platforms.\r\n\r\n## Motivation\r\n\r\nWe are currently trying to run parts of our codebase on Linux.\r\n\r\n## Proposed solution\r\n\r\nReplace CommonCrypto with an open source library. There are only two files in ApolloCore that use it and the diff wouldn't be that big. \r\n\r\nI was looking at `swift-crypto` https://swift.org/blog/crypto/ but there are compatibility issues where it requires mocos 10.15 and apollo requires 10.10. \r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"We don't *officially* support Linux, but I would very much like to. My thought is that we could make some kind of protocol that uses `swift-crypto` for Linux band still uses `CommonCrypto` on iOS etc. Would be more than open to a PR if you have some time, I'm buried at the moment. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}},{"__typename":"Issue","title":"Apollo CLI step fails to locate SourcePackages directory ","author":{"__typename":"User","login":"alcamla","id":"MDQ6VXNlcjI5MDQ1Mjk=","name":"Alejandro Camacho"},"body":"## Bug report\r\n\r\nI am following the steps on the tutorial for iOS. I added Apollo to the project using SPM. After adding the corresponding CLI script, and building the project, I get the following error: \r\n`error: Unable to locate SourcePackages directory from BUILD_ROOT: '/Users/myUser/Library/Developer/Xcode/DerivedData/Build/Products'`\r\nI have noticed that BUILD_ROOT is set to that folder directly, so there is no chance that the while loop finds the SourcePackages folder. I am running on Xcode 12.1\r\n\r\n## Versions\r\n\r\nPlease fill in the versions you're currently using: \r\n\r\n- `apollo-ios` SDK version: 0.36\r\n- Xcode version: 12.1\r\n- Swift version: 5.3\r\n- Package manager: Swift package manager\r\n\r\n## Steps to reproduce\r\n\r\n1. Create project\r\n2. Add Apollo dependency using SPM\r\n3. Add new run script phase with the code generation build step for SPM\r\n4. Modify the last line to download the schema on first run\r\n5. Build the project \r\n","comments":{"__typename":"IssueCommentConnection","nodes":[{"__typename":"IssueComment","body":"Ugh, I bet they changed the damned location of the source packages in 12.1 - it's definitely undocumented. \r\n\r\nI'll get a look at this tomorrow, but I think I'm going to recommend trying the [Swift Scripting Setup](https://www.apollographql.com/docs/ios/swift-scripting/) - that doesn't have any dependency on going diving through the derived data folder. ","author":{"__typename":"User","login":"designatednerd","id":"MDQ6VXNlcjE5NzY0OTg=","name":"Ellen Shapiro"}}]}}]}}}} diff --git a/Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift b/Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift deleted file mode 100644 index 91e81acac8..0000000000 --- a/Tests/ApolloServerIntegrationTests/DefaultInterceptorProviderIntegrationTests.swift +++ /dev/null @@ -1,79 +0,0 @@ -import Apollo -import XCTest -import StarWarsAPI - -/// Tests that the `DefaultInterceptorProvider` configures an `ApolloClient` that successfully -/// communicates with an external Apollo Server. -/// -/// - Precondition: These tests will only pass if a local instance of the Star Wars server is -/// running on port 8080. -/// This server can be found at https://github.com/apollographql/starwars-server -class DefaultInterceptorProviderIntegrationTests: XCTestCase { - - var client: ApolloClient! - - override func setUp() { - let url = TestServerURL.starWarsServer.url - let store = ApolloStore() - let provider = DefaultInterceptorProvider(store: store) - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: url) - - client = ApolloClient(networkTransport: transport, store: store) - } - - override func tearDown() { - client = nil - - super.tearDown() - } - - func testLoading() { - let expectation = self.expectation(description: "loaded with default client") - client.fetch(query: HeroNameQuery()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - expectation.fulfill() - } - - self.wait(for: [expectation], timeout: 10) - } - - func testInitialLoadFromNetworkAndSecondaryLoadFromCache() { - let initialLoadExpectation = self.expectation(description: "loaded with default client") - client.fetch(query: HeroNameQuery()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - initialLoadExpectation.fulfill() - } - - self.wait(for: [initialLoadExpectation], timeout: 10) - - let secondLoadExpectation = self.expectation(description: "loaded with default client") - client.fetch(query: HeroNameQuery()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - secondLoadExpectation.fulfill() - } - - self.wait(for: [secondLoadExpectation], timeout: 10) - } -} diff --git a/Tests/ApolloServerIntegrationTests/Info.plist b/Tests/ApolloServerIntegrationTests/Info.plist deleted file mode 100644 index 64d65ca495..0000000000 --- a/Tests/ApolloServerIntegrationTests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift b/Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift deleted file mode 100644 index 9b1b126a32..0000000000 --- a/Tests/ApolloServerIntegrationTests/SchemaRegistryApolloSchemaDownloaderTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -#if os(macOS) -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class SchemaRegistryApolloSchemaDownloaderTests: XCTestCase { - func testDownloadingSchema_fromSchemaRegistry_shouldOutputSDL() throws { - let testOutputFolderURL = CodegenTestHelper.outputFolderURL() - XCTAssertFalse(FileManager.default.apollo.fileExists(at: testOutputFolderURL)) - - guard let apiKey = ProcessInfo.processInfo.environment["REGISTRY_API_KEY"] else { - throw XCTSkip("No API key could be fetched from the environment to test downloading from the schema registry") - } - - let settings = ApolloSchemaDownloadConfiguration.DownloadMethod.ApolloRegistrySettings(apiKey: apiKey, graphID: "Apollo-Fullstack-8zo5jl") - let configuration = ApolloSchemaDownloadConfiguration(using: .apolloRegistry(settings), - outputFolderURL: CodegenTestHelper.schemaFolderURL()) - - try ApolloSchemaDownloader.fetch(with: configuration) - XCTAssertTrue(FileManager.default.apollo.fileExists(at: configuration.outputURL)) - - // Can it be turned into the expected schema? - let frontend = try ApolloCodegenFrontend() - let source = try frontend.makeSource(from: configuration.outputURL) - let schema = try frontend.loadSchemaFromSDL(source) - let rocketType = try schema.getType(named: "Rocket") - XCTAssertEqual(rocketType?.name, "Rocket") - } -} -#endif diff --git a/Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift deleted file mode 100644 index 7157729c80..0000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsApolloSchemaDownloaderTests.swift +++ /dev/null @@ -1,43 +0,0 @@ -#if os(macOS) -import XCTest -import ApolloTestSupport -import ApolloCodegenTestSupport -@testable import ApolloCodegenLib - -class StarWarsApolloSchemaDownloaderTests: XCTestCase { - - func testDownloadingSchema_usingIntrospection_shouldOutputSDL() throws { - let testOutputFolderURL = CodegenTestHelper.outputFolderURL() - let configuration = ApolloSchemaDownloadConfiguration(using: .introspection(endpointURL: TestServerURL.starWarsServer.url), - outputFolderURL: testOutputFolderURL) - - // Delete anything existing at the output URL - try FileManager.default.apollo.deleteFile(at: configuration.outputURL) - XCTAssertFalse(FileManager.default.apollo.fileExists(at: configuration.outputURL)) - - try ApolloSchemaDownloader.fetch(with: configuration) - - // Does the file now exist? - XCTAssertTrue(FileManager.default.apollo.fileExists(at: configuration.outputURL)) - - // Is it non-empty? - let data = try Data(contentsOf: configuration.outputURL) - XCTAssertFalse(data.isEmpty) - - // It should not be JSON - XCTAssertNil(try? JSONSerialization.jsonObject(with: data, options: []) as? [AnyHashable:Any]) - - // Can it be turned into the expected schema? - let frontend = try ApolloCodegenFrontend() - let source = try frontend.makeSource(from: configuration.outputURL) - let schema = try frontend.loadSchemaFromSDL(source) - let episodeType = try schema.getType(named: "Episode") - XCTAssertEqual(episodeType?.name, "Episode") - - // OK delete it now - try FileManager.default.apollo.deleteFile(at: configuration.outputURL) - XCTAssertFalse(FileManager.default.apollo.fileExists(at: configuration.outputURL)) - } - -} -#endif diff --git a/Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift deleted file mode 100644 index de8f260eba..0000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsServerCachingRoundtripTests.swift +++ /dev/null @@ -1,103 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class SQLiteStarWarsServerCachingRoundtripTests: StarWarsServerCachingRoundtripTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class StarWarsServerCachingRoundtripTests: XCTestCase, CacheDependentTesting { - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5 - - var cache: NormalizedCache! - var store: ApolloStore! - var client: ApolloClient! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - store = ApolloStore(cache: cache) - let provider = DefaultInterceptorProvider(store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url) - - client = ApolloClient(networkTransport: network, store: store) - } - - override func tearDownWithError() throws { - cache = nil - store = nil - client = nil - - try super.tearDownWithError() - } - - func testHeroAndFriendsNamesQuery() { - let query = HeroAndFriendsNamesQuery() - - fetchAndLoadFromStore(query: query) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroAndFriendsNamesQueryWithVariable() { - let query = HeroAndFriendsNamesQuery(episode: .jedi) - - fetchAndLoadFromStore(query: query) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroAndFriendsNamesWithIDsQuery() { - client.store.cacheKeyForObject = { $0["id"] } - - let query = HeroAndFriendsNamesWithIDsQuery() - - fetchAndLoadFromStore(query: query) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - // MARK: - Helpers - - private func fetchAndLoadFromStore(query: Query, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Query.Data) -> Void) { - let fetchedFromServerExpectation = expectation(description: "Fetched query from server") - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData) { result in - defer { fetchedFromServerExpectation.fulfill() } - XCTAssertSuccessResult(result, file: file, line: line) - } - - wait(for: [fetchedFromServerExpectation], timeout: Self.defaultWaitTimeout) - - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let loadedFromStoreExpectation = resultObserver.expectation(description: "Loaded query from store", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - store.load(query: query, resultHandler: resultObserver.handler) - - wait(for: [loadedFromStoreExpectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift deleted file mode 100644 index 925e7efa25..0000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsServerTests.swift +++ /dev/null @@ -1,364 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class StarWarsServerAPQsGetMethodTests: StarWarsServerTests { - override func setUp() { - super.setUp() - config = APQsWithGetMethodConfig() - } -} - -class StarWarsServerAPQsTests: StarWarsServerTests { - override func setUp() { - super.setUp() - config = APQsConfig() - } -} - -class SQLiteStarWarsServerAPQsGetMethodTests: StarWarsServerAPQsGetMethodTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteStarWarsServerAPQsTests: StarWarsServerAPQsTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteStarWarsServerTests: StarWarsServerTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class StarWarsServerTests: XCTestCase, CacheDependentTesting { - var config: TestConfig! - - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5 - - var cache: NormalizedCache! - var client: ApolloClient! - - override func setUpWithError() throws { - try super.setUpWithError() - - config = DefaultConfig() - - cache = try makeNormalizedCache() - let store = ApolloStore(cache: cache) - - client = ApolloClient(networkTransport: config.network(store: store), store: store) - } - - override func tearDownWithError() throws { - cache = nil - client = nil - config = nil - - try super.tearDownWithError() - } - - // MARK: Queries - - func testHeroNameQuery() { - fetch(query: HeroNameQuery()) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - func testHeroNameQueryWithVariable() { - fetch(query: HeroNameQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - } - - func testHeroAppearsInQuery() { - fetch(query: HeroAppearsInQuery()) { data in - XCTAssertEqual(data.hero?.appearsIn, [.newhope, .empire, .jedi]) - } - } - - func testHeroAndFriendsNamesQuery() { - fetch(query: HeroAndFriendsNamesQuery()) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroFriendsOfFriendsNamesQuery() { - fetch(query: HeroFriendsOfFriendsNamesQuery()) { data in - let friendsOfFirstFriendNames = data.hero?.friends?.first??.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsOfFirstFriendNames, ["Han Solo", "Leia Organa", "C-3PO", "R2-D2"]) - } - } - - func testHumanQueryWithNullMass() { - fetch(query: HumanQuery(id: "1004")) { data in - XCTAssertEqual(data.human?.name, "Wilhuff Tarkin") - XCTAssertNil(data.human?.mass) - } - } - - func testHumanQueryWithNullResult() { - fetch(query: HumanQuery(id: "9999")) { data in - XCTAssertNil(data.human) - } - } - - func testHeroDetailsQueryDroid() { - fetch(query: HeroDetailsQuery()) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - - guard let droid = data.hero?.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsQueryHuman() { - fetch(query: HeroDetailsQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - - guard let human = data.hero?.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testHeroDetailsWithFragmentQueryDroid() { - fetch(query: HeroDetailsWithFragmentQuery()) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "R2-D2") - - guard let droid = data.hero?.fragments.heroDetails.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsWithFragmentQueryHuman() { - fetch(query: HeroDetailsWithFragmentQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "Luke Skywalker") - - guard let human = data.hero?.fragments.heroDetails.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testDroidDetailsWithFragmentQueryDroid() { - fetch(query: DroidDetailsWithFragmentQuery()) { data in - XCTAssertEqual(data.hero?.fragments.droidDetails?.name, "R2-D2") - XCTAssertEqual(data.hero?.fragments.droidDetails?.primaryFunction, "Astromech") - } - } - - func testDroidDetailsWithFragmentQueryHuman() { - fetch(query: DroidDetailsWithFragmentQuery(episode: .empire)) { data in - XCTAssertNil(data.hero?.fragments.droidDetails) - } - } - - - func testHeroTypeDependentAliasedFieldDroid() { - fetch(query: HeroTypeDependentAliasedFieldQuery()) { data in - XCTAssertEqual(data.hero?.asDroid?.property, "Astromech") - XCTAssertNil(data.hero?.asHuman?.property) - } - } - - func testHeroTypeDependentAliasedFieldHuman() { - fetch(query: HeroTypeDependentAliasedFieldQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.asHuman?.property, "Tatooine") - XCTAssertNil(data.hero?.asDroid?.property) - } - } - - func testHeroParentTypeDependentFieldDroid() { - fetch(query: HeroParentTypeDependentFieldQuery()) { data in - XCTAssertEqual(data.hero?.asDroid?.friends?.first??.asHuman?.height, 1.72) - } - } - - func testHeroParentTypeDependentFieldHuman() { - fetch(query: HeroParentTypeDependentFieldQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.asHuman?.friends?.first??.asHuman?.height, 5.905512) - } - } - - func testStarshipCoordinates() { - fetch(query: StarshipQuery()) { data in - XCTAssertEqual(data.starship?.coordinates?[0], [1, 2]) - XCTAssertEqual(data.starship?.coordinates?[1], [3, 4]) - } - } - - // MARK: @skip / @include directives - - func testHeroNameConditionalExclusion() { - fetch(query: HeroNameConditionalExclusionQuery(skipName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalExclusionQuery(skipName: true)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalInclusion() { - fetch(query: HeroNameConditionalInclusionQuery(includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalInclusionQuery(includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalBoth() { - fetch(query: HeroNameConditionalBothQuery(skipName: false, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothQuery(skipName: true, includeName: true)) { data in - XCTAssertNil(data.hero?.name) - } - - fetch(query: HeroNameConditionalBothQuery(skipName: false, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - - fetch(query: HeroNameConditionalBothQuery(skipName: true, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalBothSeparate() { - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: false, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: true, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: false, includeName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: true, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroDetailsInlineConditionalInclusion() { - fetch(query: HeroDetailsInlineConditionalInclusionQuery(includeDetails: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.appearsIn, [.newhope, .empire, .jedi]) - } - - fetch(query: HeroDetailsInlineConditionalInclusionQuery(includeDetails: false)) { data in - XCTAssertNil(data.hero?.name) - XCTAssertNil(data.hero?.appearsIn) - } - } - - func testHeroDetailsFragmentConditionalInclusion() { - fetch(query: HeroDetailsFragmentConditionalInclusionQuery(includeDetails: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.primaryFunction, "Astromech") - } - - fetch(query: HeroDetailsFragmentConditionalInclusionQuery(includeDetails: false)) { data in - XCTAssertNil(data.hero?.name) - XCTAssertNil(data.hero?.asDroid?.primaryFunction) - } - } - - func testHeroNameTypeSpecificConditionalInclusion() { - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(includeName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(episode: .empire, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(episode: .empire, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - // MARK: Mutations - - func testCreateReviewForEpisode() { - perform(mutation: CreateReviewForEpisodeMutation(episode: .jedi, review: ReviewInput(stars: 5, commentary: "This is a great movie!"))) { data in - XCTAssertEqual(data.createReview?.stars, 5) - XCTAssertEqual(data.createReview?.commentary, "This is a great movie!") - } - } - - // MARK: - Helpers - - private func fetch(query: Query, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Query.Data) -> Void) { - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Fetched query from server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } - - private func perform(mutation: Mutation, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Mutation.Data) -> Void) { - let resultObserver = makeResultObserver(for: mutation, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Performing mutation on server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.perform(mutation: mutation, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift deleted file mode 100644 index 05669fd8cd..0000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsSubscriptionTests.swift +++ /dev/null @@ -1,521 +0,0 @@ -import XCTest -import Apollo -import ApolloTestSupport -@testable import ApolloWebSocket -import StarWarsAPI - -class StarWarsSubscriptionTests: XCTestCase { - var concurrentQueue: DispatchQueue! - var client: ApolloClient! - var webSocketTransport: WebSocketTransport! - - var connectionStartedExpectation: XCTestExpectation? - var disconnectedExpectation: XCTestExpectation? - var reconnectedExpectation: XCTestExpectation? - - override func setUp() { - super.setUp() - - concurrentQueue = DispatchQueue(label: "com.apollographql.test.\(self.name)", attributes: .concurrent) - - connectionStartedExpectation = self.expectation(description: "Web socket connected") - - webSocketTransport = WebSocketTransport( - websocket: WebSocket( - request: URLRequest(url: TestServerURL.starWarsWebSocket.url), - protocol: .graphql_ws - ), - store: ApolloStore() - ) - webSocketTransport.delegate = self - client = ApolloClient(networkTransport: webSocketTransport, store: ApolloStore()) - - self.wait(for: [self.connectionStartedExpectation!], timeout: 5) - } - - override func tearDownWithError() throws { - client = nil - webSocketTransport = nil - connectionStartedExpectation = nil - disconnectedExpectation = nil - reconnectedExpectation = nil - concurrentQueue = nil - - try super.tearDownWithError() - } - - private func waitForSubscriptionsToStart(for delay: TimeInterval = 0.1, on queue: DispatchQueue = .main) { - /// This method works around changes to the subscriptions package which mean that subscriptions do not start passing on data the absolute instant they are created. - let waitExpectation = self.expectation(description: "Waited!") - - queue.asyncAfter(deadline: .now() + delay) { - waitExpectation.fulfill() - } - - self.wait(for: [waitExpectation], timeout: delay + 1) - } - - // MARK: Subscriptions - - func testSubscribeReviewJediEpisode() { - let expectation = self.expectation(description: "Subscribe single review") - - let sub = client.subscribe(subscription: ReviewAddedSubscription(episode: .jedi)) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertEqual(data.reviewAdded?.episode, .jedi) - XCTAssertEqual(data.reviewAdded?.stars, 6) - XCTAssertEqual(data.reviewAdded?.commentary, "This is the greatest movie!") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - client.perform(mutation: CreateReviewForEpisodeMutation( - episode: .jedi, - review: ReviewInput(stars: 6, commentary: "This is the greatest movie!"))) - - waitForExpectations(timeout: 10, handler: nil) - sub.cancel() - } - - func testSubscribeReviewAnyEpisode() { - let expectation = self.expectation(description: "Subscribe any episode") - - let sub = client.subscribe(subscription: ReviewAddedSubscription()) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertEqual(data.reviewAdded?.stars, 13) - XCTAssertEqual(data.reviewAdded?.commentary, "This is an even greater movie!") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - client.perform(mutation: CreateReviewForEpisodeMutation(episode: .empire, review: ReviewInput(stars: 13, commentary: "This is an even greater movie!"))) - - waitForExpectations(timeout: 2, handler: nil) - sub.cancel() - } - - func testSubscribeReviewDifferentEpisode() { - let expectation = self.expectation(description: "Subscription to specific episode - expecting timeout") - expectation.isInverted = true - - let sub = client.subscribe(subscription: ReviewAddedSubscription(episode: .jedi)) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertNotEqual(data.reviewAdded?.episode, .jedi) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - client.perform(mutation: CreateReviewForEpisodeMutation(episode: .empire, review: ReviewInput(stars: 10, commentary: "This is an even greater movie!"))) - - waitForExpectations(timeout: 3, handler: nil) - sub.cancel() - } - - func testSubscribeThenCancel() { - let expectation = self.expectation(description: "Subscription then cancel - expecting timeout") - expectation.isInverted = true - - let sub = client.subscribe(subscription: ReviewAddedSubscription(episode: .jedi)) { _ in - XCTFail("Received subscription after cancel") - } - - self.waitForSubscriptionsToStart() - - sub.cancel() - - client.perform(mutation: CreateReviewForEpisodeMutation(episode: .jedi, review: ReviewInput(stars: 10, commentary: "This is an even greater movie!"))) - - waitForExpectations(timeout: 3, handler: nil) - } - - func testSubscribeMultipleReviews() { - let count = 50 - let expectation = self.expectation(description: "Multiple reviews") - expectation.expectedFulfillmentCount = count - - let sub = client.subscribe(subscription: ReviewAddedSubscription(episode: .empire)) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - guard let data = graphQLResult.data else { - XCTFail("No subscription result data") - return - } - - XCTAssertEqual(data.reviewAdded?.episode, .empire) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForSubscriptionsToStart() - - for i in 1...count { - let review = ReviewInput(stars: i, commentary: "The greatest movie ever!") - _ = client.perform(mutation: CreateReviewForEpisodeMutation(episode: .empire, review: review)) - } - - waitForExpectations(timeout: 10, handler: nil) - sub.cancel() - } - - func testMultipleSubscriptions() { - // Multiple subscriptions, one for any episode and one for each of the episode - // We send count reviews and expect to receive twice that number of subscriptions - - let count = 20 - - let expectation = self.expectation(description: "Multiple reviews") - expectation.expectedFulfillmentCount = count * 2 - - var allFulfilledCount = 0 - var newHopeFulfilledCount = 0 - var empireFulfilledCount = 0 - var jediFulfilledCount = 0 - - let subAll = client.subscribe(subscription: ReviewAddedSubscription()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - allFulfilledCount += 1 - } - - let subEmpire = client.subscribe(subscription: ReviewAddedSubscription(episode: .empire)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - empireFulfilledCount += 1 - } - - let subJedi = client.subscribe(subscription: ReviewAddedSubscription(episode: .jedi)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - jediFulfilledCount += 1 - } - - let subNewHope = client.subscribe(subscription: ReviewAddedSubscription(episode: .newhope)) { result in - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - XCTAssertNotNil(graphQLResult.data) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - expectation.fulfill() - newHopeFulfilledCount += 1 - } - - self.waitForSubscriptionsToStart() - - let episodes : [Episode] = [.empire, .jedi, .newhope] - - var selectedEpisodes = [Episode]() - for i in 1...count { - let review = ReviewInput(stars: i, commentary: "The greatest movie ever!") - let episode = episodes.randomElement()! - selectedEpisodes.append(episode) - _ = client.perform(mutation: CreateReviewForEpisodeMutation(episode: episode, review: review)) - } - - waitForExpectations(timeout: 10, handler: nil) - XCTAssertEqual(allFulfilledCount, - count, - "All not fulfilled proper number of times. Expected \(count), got \(allFulfilledCount)") - let expectedNewHope = selectedEpisodes.filter { $0 == .newhope }.count - XCTAssertEqual(newHopeFulfilledCount, - expectedNewHope, - "New Hope not fulfilled proper number of times. Expected \(expectedNewHope), got \(newHopeFulfilledCount)") - let expectedEmpire = selectedEpisodes.filter { $0 == .empire }.count - XCTAssertEqual(empireFulfilledCount, - expectedEmpire, - "Empire not fulfilled proper number of times. Expected \(expectedEmpire), got \(empireFulfilledCount)") - let expectedJedi = selectedEpisodes.filter { $0 == .jedi }.count - XCTAssertEqual(jediFulfilledCount, - expectedJedi, - "Jedi not fulfilled proper number of times. Expected \(expectedJedi), got \(jediFulfilledCount)") - - subAll.cancel() - subEmpire.cancel() - subJedi.cancel() - subNewHope.cancel() - } - - // MARK: Data races tests - - func testConcurrentSubscribing() { - let firstSubscription = ReviewAddedSubscription(episode: .empire) - let secondSubscription = ReviewAddedSubscription(episode: .empire) - - let expectation = self.expectation(description: "Subscribers connected and received events") - expectation.expectedFulfillmentCount = 2 - - var sub1: Cancellable? - var sub2: Cancellable? - - concurrentQueue.async { - sub1 = self.client.subscribe(subscription: firstSubscription) { _ in - expectation.fulfill() - } - } - - concurrentQueue.async { - sub2 = self.client.subscribe(subscription: secondSubscription) { _ in - expectation.fulfill() - } - } - - self.waitForSubscriptionsToStart(on: concurrentQueue) - - // dispatched with a barrier flag to make sure - // this is performed after subscription calls - concurrentQueue.sync(flags: .barrier) { - // dispatched on the processing queue with barrier flag to make sure - // this is performed after subscribers are processed - self.webSocketTransport.processingQueue.async(flags: .barrier) { - _ = self.client.perform(mutation: CreateReviewForEpisodeMutation(episode: .empire, review: ReviewInput(stars: 5, commentary: "The greatest movie ever!"))) - } - } - - waitForExpectations(timeout: 10, handler: nil) - sub1?.cancel() - sub2?.cancel() - } - - func testConcurrentSubscriptionCancellations() { - let firstSubscription = ReviewAddedSubscription(episode: .empire) - let secondSubscription = ReviewAddedSubscription(episode: .empire) - - let expectation = self.expectation(description: "Subscriptions cancelled") - expectation.expectedFulfillmentCount = 2 - let invertedExpectation = self.expectation(description: "Subscription received callback - expecting timeout") - invertedExpectation.isInverted = true - - let sub1 = client.subscribe(subscription: firstSubscription) { _ in - invertedExpectation.fulfill() - } - let sub2 = client.subscribe(subscription: secondSubscription) { _ in - invertedExpectation.fulfill() - } - - self.waitForSubscriptionsToStart(on: concurrentQueue) - - concurrentQueue.async { - sub1.cancel() - expectation.fulfill() - } - concurrentQueue.async { - sub2.cancel() - expectation.fulfill() - } - - wait(for: [expectation], timeout: 10) - - _ = self.client.perform(mutation: CreateReviewForEpisodeMutation(episode: .empire, review: ReviewInput(stars: 5, commentary: "The greatest movie ever!"))) - - wait(for: [invertedExpectation], timeout: 2) - } - - func testConcurrentSubscriptionAndConnectionClose() { - let empireReviewSubscription = ReviewAddedSubscription(episode: .empire) - let expectation = self.expectation(description: "Connection closed") - let invertedExpectation = self.expectation(description: "Subscription received callback - expecting timeout") - invertedExpectation.isInverted = true - - let sub = self.client.subscribe(subscription: empireReviewSubscription) { _ in - invertedExpectation.fulfill() - } - - self.waitForSubscriptionsToStart(on: concurrentQueue) - - concurrentQueue.async { - sub.cancel() - } - concurrentQueue.async { - self.webSocketTransport.closeConnection() - expectation.fulfill() - } - - wait(for: [expectation], timeout: 10) - - _ = self.client.perform(mutation: CreateReviewForEpisodeMutation(episode: .empire, review: ReviewInput(stars: 5, commentary: "The greatest movie ever!"))) - - wait(for: [invertedExpectation], timeout: 2) - } - - func testConcurrentConnectAndCloseConnection() { - let webSocketTransport = WebSocketTransport( - websocket: MockWebSocket( - request: URLRequest(url: TestServerURL.starWarsWebSocket.url), - protocol: .graphql_ws - ), - store: ApolloStore() - ) - - let expectation = self.expectation(description: "Connection closed") - expectation.expectedFulfillmentCount = 2 - - concurrentQueue.async { - if let websocket = webSocketTransport.websocket as? MockWebSocket { - websocket.reportDidConnect() - expectation.fulfill() - } - } - - concurrentQueue.async { - webSocketTransport.closeConnection() - expectation.fulfill() - } - - waitForExpectations(timeout: 10, handler: nil) - } - - func testPausingAndResumingWebSocketConnection() { - let subscription = ReviewAddedSubscription() - let reviewMutation = CreateAwesomeReviewMutation() - - // Send the mutations via a separate transport so they can still be sent when the websocket is disconnected - let store = ApolloStore() - let interceptorProvider = DefaultInterceptorProvider(store: store) - let alternateTransport = RequestChainNetworkTransport(interceptorProvider: interceptorProvider, - endpointURL: TestServerURL.starWarsServer.url) - let alternateClient = ApolloClient(networkTransport: alternateTransport, store: store) - - func sendReview() { - let reviewSentExpectation = self.expectation(description: "review sent") - alternateClient.perform(mutation: reviewMutation) { mutationResult in - switch mutationResult { - case .success: - break - case .failure(let error): - XCTFail("Unexpected error sending review: \(error)") - } - - reviewSentExpectation.fulfill() - } - self.wait(for: [reviewSentExpectation], timeout: 10) - } - - let subscriptionExpectation = self.expectation(description: "Received review") - // This should get hit twice - once before we pause the web socket and once after. - subscriptionExpectation.expectedFulfillmentCount = 2 - let reviewAddedSubscription = self.client.subscribe(subscription: subscription) { subscriptionResult in - switch subscriptionResult { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.reviewAdded?.episode, .jedi) - subscriptionExpectation.fulfill() - case .failure(let error): - if let wsError = error as? WebSocket.WSError { - // This is an expected error on disconnection, ignore it. - XCTAssertEqual(wsError.code, 1000) - } else { - XCTFail("Unexpected error receiving subscription: \(error)") - subscriptionExpectation.fulfill() - } - } - } - - self.waitForSubscriptionsToStart() - sendReview() - - self.disconnectedExpectation = self.expectation(description: "Web socket disconnected") - webSocketTransport.pauseWebSocketConnection() - self.wait(for: [self.disconnectedExpectation!], timeout: 10) - - // This should not go through since the socket is paused - sendReview() - - self.reconnectedExpectation = self.expectation(description: "Web socket reconnected") - webSocketTransport.resumeWebSocketConnection() - self.wait(for: [self.reconnectedExpectation!], timeout: 10) - self.waitForSubscriptionsToStart() - - // Now that we've reconnected, this should go through to the same subscription. - sendReview() - - self.wait(for: [subscriptionExpectation], timeout: 10) - - // Cancel subscription so it doesn't keep receiving from other tests. - reviewAddedSubscription.cancel() - } -} - -extension StarWarsSubscriptionTests: WebSocketTransportDelegate { - - func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) { - self.connectionStartedExpectation?.fulfill() - } - - func webSocketTransportDidReconnect(_ webSocketTransport: WebSocketTransport) { - self.reconnectedExpectation?.fulfill() - } - - func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error: Error?) { - self.disconnectedExpectation?.fulfill() - } -} diff --git a/Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift b/Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift deleted file mode 100755 index a38c4bb424..0000000000 --- a/Tests/ApolloServerIntegrationTests/StarWarsWebSocketTests.swift +++ /dev/null @@ -1,335 +0,0 @@ -import XCTest -import Apollo -import ApolloTestSupport -@testable import ApolloWebSocket -import StarWarsAPI - -class StarWarsWebSocketTests: XCTestCase, CacheDependentTesting { - - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5 - - var cache: NormalizedCache! - var client: ApolloClient! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - let store = ApolloStore(cache: cache) - - let networkTransport = WebSocketTransport( - websocket: WebSocket(request: URLRequest(url: TestServerURL.starWarsWebSocket.url), - protocol: .graphql_ws), - store: store - ) - - client = ApolloClient(networkTransport: networkTransport, store: store) - } - - override func tearDownWithError() throws { - cache = nil - client = nil - - try super.tearDownWithError() - } - - // MARK: Queries - - func testHeroNameQuery() { - fetch(query: HeroNameQuery()) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - func testHeroNameQueryWithVariable() { - fetch(query: HeroNameQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - } - - func testHeroAppearsInQuery() { - fetch(query: HeroAppearsInQuery()) { data in - XCTAssertEqual(data.hero?.appearsIn, [.newhope, .empire, .jedi]) - } - } - - func testHeroAndFriendsNamesQuery() { - fetch(query: HeroAndFriendsNamesQuery()) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - - func testHeroFriendsOfFriendsNamesQuery() { - fetch(query: HeroFriendsOfFriendsNamesQuery()) { data in - let friendsOfFirstFriendNames = data.hero?.friends?.first??.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsOfFirstFriendNames, ["Han Solo", "Leia Organa", "C-3PO", "R2-D2"]) - } - } - - func testHumanQueryWithNullMass() { - fetch(query: HumanQuery(id: "1004")) { data in - XCTAssertEqual(data.human?.name, "Wilhuff Tarkin") - XCTAssertNil(data.human?.mass) - } - } - - func testHumanQueryWithNullResult() { - fetch(query: HumanQuery(id: "9999")) { data in - XCTAssertNil(data.human) - } - } - - func testHeroDetailsQueryDroid() { - fetch(query: HeroDetailsQuery()) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - - guard let droid = data.hero?.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsQueryHuman() { - fetch(query: HeroDetailsQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - - guard let human = data.hero?.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testHeroDetailsWithFragmentQueryDroid() { - fetch(query: HeroDetailsWithFragmentQuery()) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "R2-D2") - - guard let droid = data.hero?.fragments.heroDetails.asDroid else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - } - - func testHeroDetailsWithFragmentQueryHuman() { - fetch(query: HeroDetailsWithFragmentQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.fragments.heroDetails.name, "Luke Skywalker") - - guard let human = data.hero?.fragments.heroDetails.asHuman else { - XCTFail("Wrong type") - return - } - - XCTAssertEqual(human.height, 1.72) - } - } - - func testDroidDetailsWithFragmentQueryDroid() { - fetch(query: DroidDetailsWithFragmentQuery()) { data in - XCTAssertEqual(data.hero?.fragments.droidDetails?.name, "R2-D2") - XCTAssertEqual(data.hero?.fragments.droidDetails?.primaryFunction, "Astromech") - } - } - - func testDroidDetailsWithFragmentQueryHuman() { - fetch(query: DroidDetailsWithFragmentQuery(episode: .empire)) { data in - XCTAssertNil(data.hero?.fragments.droidDetails) - } - } - - - func testHeroTypeDependentAliasedFieldDroid() { - fetch(query: HeroTypeDependentAliasedFieldQuery()) { data in - XCTAssertEqual(data.hero?.asDroid?.property, "Astromech") - XCTAssertNil(data.hero?.asHuman?.property) - } - } - - func testHeroTypeDependentAliasedFieldHuman() { - fetch(query: HeroTypeDependentAliasedFieldQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.asHuman?.property, "Tatooine") - XCTAssertNil(data.hero?.asDroid?.property) - } - } - - func testHeroParentTypeDependentFieldDroid() { - fetch(query: HeroParentTypeDependentFieldQuery()) { data in - XCTAssertEqual(data.hero?.asDroid?.friends?.first??.asHuman?.height, 1.72) - } - } - - func testHeroParentTypeDependentFieldHuman() { - fetch(query: HeroParentTypeDependentFieldQuery(episode: .empire)) { data in - XCTAssertEqual(data.hero?.asHuman?.friends?.first??.asHuman?.height, 5.905512) - } - } - - func testStarshipCoordinates() { - fetch(query: StarshipQuery()) { data in - XCTAssertEqual(data.starship?.coordinates?[0], [1, 2]) - XCTAssertEqual(data.starship?.coordinates?[1], [3, 4]) - } - } - - // MARK: @skip / @include directives - - func testHeroNameConditionalExclusion() { - fetch(query: HeroNameConditionalExclusionQuery(skipName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalExclusionQuery(skipName: true)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalInclusion() { - fetch(query: HeroNameConditionalInclusionQuery(includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalInclusionQuery(includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalBoth() { - fetch(query: HeroNameConditionalBothQuery(skipName: false, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothQuery(skipName: true, includeName: true)) { data in - XCTAssertNil(data.hero?.name) - } - - fetch(query: HeroNameConditionalBothQuery(skipName: false, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - - fetch(query: HeroNameConditionalBothQuery(skipName: true, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroNameConditionalBothSeparate() { - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: false, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: true, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: false, includeName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - } - - fetch(query: HeroNameConditionalBothSeparateQuery(skipName: true, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - func testHeroDetailsInlineConditionalInclusion() { - fetch(query: HeroDetailsInlineConditionalInclusionQuery(includeDetails: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.appearsIn, [.newhope, .empire, .jedi]) - } - - fetch(query: HeroDetailsInlineConditionalInclusionQuery(includeDetails: false)) { data in - XCTAssertNil(data.hero?.name) - XCTAssertNil(data.hero?.appearsIn) - } - } - - func testHeroDetailsFragmentConditionalInclusion() { - fetch(query: HeroDetailsFragmentConditionalInclusionQuery(includeDetails: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.primaryFunction, "Astromech") - } - - fetch(query: HeroDetailsFragmentConditionalInclusionQuery(includeDetails: false)) { data in - XCTAssertNil(data.hero?.name) - XCTAssertNil(data.hero?.asDroid?.primaryFunction) - } - } - - func testHeroNameTypeSpecificConditionalInclusion() { - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(includeName: false)) { data in - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.asDroid?.name, "R2-D2") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(episode: .empire, includeName: true)) { data in - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - - fetch(query: HeroNameTypeSpecificConditionalInclusionQuery(episode: .empire, includeName: false)) { data in - XCTAssertNil(data.hero?.name) - } - } - - // MARK: Mutations - - func testCreateReviewForEpisode() { - perform(mutation: CreateReviewForEpisodeMutation(episode: .jedi, review: ReviewInput(stars: 5, commentary: "This is a great movie!"))) { data in - XCTAssertEqual(data.createReview?.stars, 5) - XCTAssertEqual(data.createReview?.commentary, "This is a great movie!") - } - } - - // MARK: - Helpers - - private func fetch(query: Query, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Query.Data) -> Void) { - let resultObserver = makeResultObserver(for: query, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Fetched query from server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } - - private func perform(mutation: Mutation, file: StaticString = #filePath, line: UInt = #line, completionHandler: @escaping (_ data: Mutation.Data) -> Void) { - let resultObserver = makeResultObserver(for: mutation, file: file, line: line) - - let expectation = resultObserver.expectation(description: "Performing mutation on server", file: file, line: line) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server, file: file, line: line) - XCTAssertNil(graphQLResult.errors, file: file, line: line) - - let data = try XCTUnwrap(graphQLResult.data, file: file, line: line) - completionHandler(data) - } - } - - client.perform(mutation: mutation, resultHandler: resultObserver.handler) - - wait(for: [expectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloServerIntegrationTests/SubscriptionTests.swift b/Tests/ApolloServerIntegrationTests/SubscriptionTests.swift deleted file mode 100644 index b32fc34b86..0000000000 --- a/Tests/ApolloServerIntegrationTests/SubscriptionTests.swift +++ /dev/null @@ -1,58 +0,0 @@ -import XCTest -import Apollo -import SubscriptionAPI -import ApolloWebSocket -import SQLite -import Nimble - -class SubscriptionTests: XCTestCase { - enum Connection: Equatable { - case disconnected - case connected - } - - var connectionState: Connection = .disconnected - var resultNumber: Int? = nil - - func test_subscribe_givenSubscription_shouldReceiveSuccessResult_andCancelSubscription() { - // given - let store = ApolloStore() - let webSocketTransport = WebSocketTransport( - websocket: WebSocket(url: TestServerURL.subscriptionWebSocket.url, protocol: .graphql_transport_ws), - store: store - ) - webSocketTransport.delegate = self - let client = ApolloClient(networkTransport: webSocketTransport, store: store) - - expect(self.connectionState).toEventually(equal(Connection.connected), timeout: .seconds(1)) - - // when - let subject = client.subscribe(subscription: IncrementingSubscription()) { result in - switch result { - case let .failure(error): - XCTFail("Expected .success, got \(error.localizedDescription)") - - case let .success(graphqlResult): - expect(graphqlResult.errors).to(beNil()) - self.resultNumber = graphqlResult.data?.numberIncremented - } - } - - // then - expect(self.resultNumber).toEventuallyNot(beNil(), timeout: .seconds(2)) - - subject.cancel() - webSocketTransport.closeConnection() - expect(self.connectionState).toEventually(equal(.disconnected), timeout: .seconds(2)) - } -} - -extension SubscriptionTests: WebSocketTransportDelegate { - func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) { - connectionState = .connected - } - - func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error:Error?) { - connectionState = .disconnected - } -} diff --git a/Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift b/Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift deleted file mode 100644 index 2229569dc9..0000000000 --- a/Tests/ApolloServerIntegrationTests/TestHelpers/HTTPBinAPI.swift +++ /dev/null @@ -1,59 +0,0 @@ -import Foundation - -enum HTTPBinAPI { - static let baseURL = URL(string: "https://httpbin.org")! - enum Endpoint { - case bytes(count: Int) - case get - case getWithIndex(index: Int) - case headers - case image - case post - - var toString: String { - - switch self { - case .bytes(let count): - return "bytes/\(count)" - case .get, - .getWithIndex: - return "get" - case .headers: - return "headers" - case .image: - return "image/jpeg" - case .post: - return "post" - } - } - - var queryParams: [URLQueryItem]? { - switch self { - case .getWithIndex(let index): - return [URLQueryItem(name: "index", value: "\(index)")] - default: - return nil - } - } - - var toURL: URL { - var components = URLComponents(url: HTTPBinAPI.baseURL, resolvingAgainstBaseURL: false)! - components.path = "/\(self.toString)" - components.queryItems = self.queryParams - - return components.url! - } - } -} - -struct HTTPBinResponse: Codable { - - let headers: [String: String] - let url: String - let json: [String: String]? - let args: [String: String]? - - init(data: Data) throws { - self = try JSONDecoder().decode(Self.self, from: data) - } -} diff --git a/Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift b/Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift deleted file mode 100644 index 4f55d2cf58..0000000000 --- a/Tests/ApolloServerIntegrationTests/TestHelpers/TestConfigs.swift +++ /dev/null @@ -1,47 +0,0 @@ -@testable import Apollo - -protocol TestConfig { - func network(store: ApolloStore) -> NetworkTransport -} - -class DefaultConfig: TestConfig { - - func transport(with store: ApolloStore) -> NetworkTransport { - let provider = DefaultInterceptorProvider(store: store) - return RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url) - } - - func network(store: ApolloStore) -> NetworkTransport { - return transport(with: store) - } -} - -class APQsConfig: TestConfig { - - func transport(with store: ApolloStore) -> NetworkTransport { - let provider = DefaultInterceptorProvider(store: store) - return RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url, - autoPersistQueries: true) - } - - func network(store: ApolloStore) -> NetworkTransport { - return transport(with: store) - } -} - -class APQsWithGetMethodConfig: TestConfig { - - func transport(with store: ApolloStore) -> NetworkTransport { - let provider = DefaultInterceptorProvider(store: store) - return RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestServerURL.starWarsServer.url, - autoPersistQueries: true, - useGETForPersistedQueryRetry: true) - } - - func network(store: ApolloStore) -> NetworkTransport { - return transport(with: store) - } -} diff --git a/Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift b/Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift deleted file mode 100644 index 95c504bd1c..0000000000 --- a/Tests/ApolloServerIntegrationTests/TestHelpers/TestServerURLs.swift +++ /dev/null @@ -1,15 +0,0 @@ -/// Local URLs for servers used in integration testing -import Foundation - -public enum TestServerURL: String { - case mockServer = "http://localhost/dummy_url" - case starWarsServer = "http://localhost:8080/graphql" - case starWarsWebSocket = "ws://localhost:8080/websocket" - case uploadServer = "http://localhost:4001" - case subscriptionServer = "http://localhost:4000/graphql" - case subscriptionWebSocket = "ws://localhost:4000/graphql" - - public var url: URL { - return URL(string: self.rawValue)! - } -} diff --git a/Tests/ApolloServerIntegrationTests/URLSessionClientTests.swift b/Tests/ApolloServerIntegrationTests/URLSessionClientTests.swift deleted file mode 100644 index 43af9bd74b..0000000000 --- a/Tests/ApolloServerIntegrationTests/URLSessionClientTests.swift +++ /dev/null @@ -1,256 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloUtils - -class URLSessionClientLiveTests: XCTestCase { - - var client: URLSessionClient! - - override func setUp() { - super.setUp() - - client = URLSessionClient() - } - - override func tearDown() { - client = nil - - super.tearDown() - } - - private func request(for endpoint: HTTPBinAPI.Endpoint) -> URLRequest { - URLRequest(url: endpoint.toURL, - cachePolicy: URLRequest.CachePolicy.reloadIgnoringCacheData, - timeoutInterval: 30) - } - - func testBasicGet() { - let request = self.request(for: .get) - let expectation = self.expectation(description: "Basic GET request completed") - self.client.sendRequest(request) { result in - defer { - expectation.fulfill() - } - - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let (data, httpResponse)): - XCTAssertFalse(data.isEmpty) - XCTAssertEqual(request.url, httpResponse.url) - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testGettingImage() { - let request = self.request(for: .image) - let expectation = self.expectation(description: "GET request for image completed") - self.client.sendRequest(request) { result in - defer { - expectation.fulfill() - } - - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let (data, httpResponse)): - XCTAssertFalse(data.isEmpty) - XCTAssertEqual(httpResponse.allHeaderFields["Content-Type"] as! String, "image/jpeg") - #if os(macOS) - let image = NSImage(data: data) - XCTAssertNotNil(image) - #else - let image = UIImage(data: data) - XCTAssertNotNil(image) - #endif - XCTAssertEqual(request.url, httpResponse.url) - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testGettingBytes() throws { - let randomInt = Int.random(in: 1...102_400) // 102400 is max from HTTPBin - let request = self.request(for: .bytes(count: randomInt)) - - let expectation = self.expectation(description: "GET request for a random amount of data completed") - self.client.sendRequest(request) { result in - defer { - expectation.fulfill() - } - - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let (data, response)): - XCTAssertEqual(data.count, - randomInt, - "Expected \(randomInt) bytes, got \(data.count)") - XCTAssertEqual(request.url, response.url) - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testPostingJSON() throws { - let testJSON = ["key": "value"] - let data = try JSONSerialization.data(withJSONObject: testJSON, options: .prettyPrinted) - - var request = self.request(for: .post) - request.httpBody = data - request.httpMethod = GraphQLHTTPMethod.POST.rawValue - request.addValue("application/json", forHTTPHeaderField: "Content-Type") - - let expectation = self.expectation(description: "POST request with JSON completed") - self.client.sendRequest(request) { result in - defer { - expectation.fulfill() - } - - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let (data, httpResponse)): - XCTAssertEqual(request.url, httpResponse.url) - - do { - let parsed = try HTTPBinResponse(data: data) - XCTAssertEqual(parsed.json, testJSON) - } catch { - XCTFail("Unexpected error: \(error)") - } - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testCancellingTaskDirectlyCallsCompletionWithError() throws { - let request = self.request(for: .bytes(count: 102400)) // 102400 is max from HTTPBin - - let expectation = self.expectation(description: "Cancelled task completed") - let task = self.client.sendRequest(request) { result in - defer { - expectation.fulfill() - } - - switch result { - case .failure(let error): - switch error { - case URLSessionClient.URLSessionClientError.networkError(let data, let httpResponse, let underlying): - XCTAssertTrue(data.isEmpty) - XCTAssertNil(httpResponse) - let nsError = underlying as NSError - XCTAssertEqual(nsError.domain, NSURLErrorDomain) - XCTAssertEqual(nsError.code, NSURLErrorCancelled) - default: - XCTFail("Unexpected error: \(error)") - } - case .success: - XCTFail("Task succeeded when it should have been cancelled!") - } - } - - task.cancel() - - self.wait(for: [expectation], timeout: 10) - } - - func testCancellingTaskThroughClientDoesNotCallCompletion() throws { - let request = self.request(for: .bytes(count: 102400)) // 102400 is max from HTTPBin - - let expectation = self.expectation(description: "Cancelled task completed") - expectation.isInverted = true - let task = self.client.sendRequest(request) { result in - // This shouldn't get hit since we cancel the task immediately - expectation.fulfill() - } - - self.client.cancel(task: task) - - self.wait(for: [expectation], timeout: 5) - - } - - func testMultipleSimultaneousRequests() { - let expectation = self.expectation(description: "request sent, response received") - let iterations = 20 - expectation.expectedFulfillmentCount = iterations - let taskIDs = Atomic<[Int]>([]) - - DispatchQueue.concurrentPerform(iterations: iterations, execute: { index in - let request = self.request(for: .getWithIndex(index: index)) - - let task = self.client.sendRequest(request) { result in - switch result { - case .success((let data, let response)): - XCTAssertEqual(response.url, request.url) - XCTAssertFalse(data.isEmpty) - do { - let httpBinResponse = try HTTPBinResponse(data: data) - // WORKAROUND: HTTPBin started randomly returning http instead of https - // in this field, replace until addressed. Issue: https://github.com/postmanlabs/httpbin/issues/615 - var responseURLString = httpBinResponse.url - if !responseURLString.contains("https") { - let droppedHTTP = String(responseURLString.dropFirst(4)) - responseURLString = "https" + droppedHTTP - } - - XCTAssertEqual(responseURLString, response.url?.absoluteString) - XCTAssertEqual(httpBinResponse.args?["index"], "\(index)") - } catch { - XCTFail("Parsing error: \(error) for url \(response.url!)") - } - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - - DispatchQueue.main.async { - expectation.fulfill() - } - } - - taskIDs.mutate { $0.append(task.taskIdentifier) } - }) - - self.wait(for: [expectation], timeout: 30) - - // Were the correct number of tasks created? - XCTAssertEqual(taskIDs.value.count, iterations) - - // Using a set to unique, are all task IDs different values?) - let set = Set(taskIDs.value) - XCTAssertEqual(set.count, iterations) - } - - func testInvalidatingClientAndThenTryingToSendARequestReturnsAppropriateError() { - let client = URLSessionClient() - client.invalidate() - - let expectation = self.expectation(description: "Basic GET request completed") - client.sendRequest(self.request(for: .get)) { result in - defer { - expectation.fulfill() - } - - switch result { - case .failure(let error): - switch error { - case URLSessionClient.URLSessionClientError.sessionInvalidated: - // This is what we want - break - default: - XCTFail("Unexpected error: \(error)") - } - case .success: - XCTFail("This should not have succeeded") - } - } - - self.wait(for: [expectation], timeout: 10) - } -} diff --git a/Tests/ApolloServerIntegrationTests/UploadTests.swift b/Tests/ApolloServerIntegrationTests/UploadTests.swift deleted file mode 100644 index 20a1234de9..0000000000 --- a/Tests/ApolloServerIntegrationTests/UploadTests.swift +++ /dev/null @@ -1,302 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import UploadAPI -import StarWarsAPI - -class UploadTests: XCTestCase { - - static let uploadClientURL = TestServerURL.uploadServer.url - - var client: ApolloClient! - - override func setUp() { - super.setUp() - - client = { - let store = ApolloStore() - let provider = DefaultInterceptorProvider(store: store) - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.uploadClientURL, - additionalHeaders: ["headerKey": "headerValue"]) - transport.clientName = "test" - transport.clientVersion = "test" - - return ApolloClient(networkTransport: transport, store: store) - }() - } - - override func tearDown() { - client = nil - - super.tearDown() - } - - override class func tearDown() { - // Recreate the uploads folder at the end of all tests in this suite to avoid having one billion files in there - recreateUploadsFolder() - super.tearDown() - } - - private static func recreateUploadsFolder() { - let uploadsFolderURL = TestFileHelper.uploadsFolder() - try? FileManager.default.removeItem(at: uploadsFolderURL) - - try? FileManager.default.createDirectory(at: uploadsFolderURL, withIntermediateDirectories: false) - } - - private func compareInitialFile(at initialFileURL: URL, - toUploadedFileAt path: String?, - file: StaticString = #filePath, - line: UInt = #line) { - guard let path = path else { - XCTFail("Path was nil!", - file: file, - line: line) - return - } - - let sanitizedPath = String(path.dropFirst(2)) // Gets rid of the ./ returned by the server - - let uploadedFileURL = TestFileHelper.uploadServerFolder() - .appendingPathComponent(sanitizedPath) - - do { - let initialData = try Data(contentsOf: initialFileURL) - let uploadedData = try Data(contentsOf: uploadedFileURL) - XCTAssertFalse(initialData.isEmpty, - "Initial data was empty at \(initialFileURL)", - file: file, - line: line) - XCTAssertFalse(uploadedData.isEmpty, - "Uploaded data was empty at \(uploadedFileURL)", - file: file, - line: line) - XCTAssertEqual(initialData, - uploadedData, - "Initial data at \(initialFileURL) was not equal to data uploaded at \(uploadedFileURL)", - file: file, - line: line) - } catch { - XCTFail("Unexpected error loading data to compare: \(error)", - file: file, - line: line) - } - } - - func testUploadingASingleFile() throws { - let fileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let file = try GraphQLFile(fieldName: "file", - originalName: "a.txt", - fileURL: fileURL) - - let upload = UploadOneFileMutation(file: "a.txt") - - let expectation = self.expectation(description: "File upload complete") - self.client.upload(operation: upload, files: [file]) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.singleUpload.filename, "a.txt") - self.compareInitialFile(at: fileURL, toUploadedFileAt: graphQLResult.data?.singleUpload.path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingMultipleFilesWithTheSameFieldName() throws { - let firstFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let firstFile = try GraphQLFile(fieldName: "files", - originalName: "a.txt", - fileURL: firstFileURL) - - let secondFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - - let secondFile = try GraphQLFile(fieldName: "files", - originalName: "b.txt", - fileURL: secondFileURL) - - let files = [firstFile, secondFile] - - let upload = UploadMultipleFilesToTheSameParameterMutation(files: files.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - self.client.upload(operation: upload, files: files) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 2) - let sortedUploads = uploads.sorted { $0.filename < $1.filename } - XCTAssertEqual(sortedUploads[0].filename, "a.txt") - XCTAssertEqual(sortedUploads[1].filename, "b.txt") - self.compareInitialFile(at: firstFileURL, toUploadedFileAt: sortedUploads[0].path) - self.compareInitialFile(at: secondFileURL, toUploadedFileAt: sortedUploads[1].path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingMultipleFilesWithDifferentFieldNames() throws { - let firstFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let firstFile = try GraphQLFile(fieldName: "singleFile", - originalName: "a.txt", - fileURL: firstFileURL) - - let secondFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - - let secondFile = try GraphQLFile(fieldName: "multipleFiles", - originalName: "b.txt", - fileURL: secondFileURL) - - let thirdFileURL = TestFileHelper.fileURLForFile(named: "c", extension: "txt") - - let thirdFile = try GraphQLFile(fieldName: "multipleFiles", - originalName: "c.txt", - fileURL: thirdFileURL) - - // This is the array of Files for the `multipleFiles` parameter only - let multipleFiles = [secondFile, thirdFile] - - let upload = UploadMultipleFilesToDifferentParametersMutation(singleFile: firstFile.originalName, multipleFiles: multipleFiles.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - - // This is the array of Files for all parameters - let allFiles = [firstFile, secondFile, thirdFile] - self.client.upload(operation: upload, files: allFiles) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleParameterUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 3) - let sortedUploads = uploads.sorted { $0.filename < $1.filename } - XCTAssertEqual(sortedUploads[0].filename, "a.txt") - XCTAssertEqual(sortedUploads[1].filename, "b.txt") - XCTAssertEqual(sortedUploads[2].filename, "c.txt") - self.compareInitialFile(at: firstFileURL, toUploadedFileAt: sortedUploads[0].path) - self.compareInitialFile(at: secondFileURL, toUploadedFileAt: sortedUploads[1].path) - self.compareInitialFile(at: thirdFileURL, toUploadedFileAt: sortedUploads [2].path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingASingleFileInAnArray() throws { - let fileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let file = try GraphQLFile(fieldName: "files", - originalName: "a.txt", - fileURL: fileURL) - - let filesArray = [file] - - let uploadMutation = UploadMultipleFilesToTheSameParameterMutation(files: filesArray.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - self.client.upload(operation: uploadMutation, files: filesArray) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 1) - guard let uploadedFile = uploads.first else { - XCTFail("Could not access uploaded file!") - return - } - - XCTAssertEqual(uploadedFile.filename, "a.txt") - self.compareInitialFile(at: fileURL, toUploadedFileAt: uploadedFile.path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testUploadingSingleFileInAnArrayWithAnotherFileForAnotherField() throws { - let firstFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let firstFile = try GraphQLFile(fieldName: "singleFile", - originalName: "a.txt", - fileURL: firstFileURL) - - let secondFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - - let secondFile = try GraphQLFile(fieldName: "multipleFiles", - originalName: "b.txt", - fileURL: secondFileURL) - - // This is the array of Files for the `multipleFiles` parameter only - let multipleFiles = [secondFile] - - let upload = UploadMultipleFilesToDifferentParametersMutation(singleFile: firstFile.originalName, multipleFiles: multipleFiles.map { $0.originalName }) - - let expectation = self.expectation(description: "File upload complete") - - // This is the array of Files for all parameters - let allFiles = [firstFile, secondFile] - self.client.upload(operation: upload, files: allFiles) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - guard let uploads = graphQLResult.data?.multipleParameterUpload else { - XCTFail("NOPE") - return - } - - XCTAssertEqual(uploads.count, 2) - let sortedUploads = uploads.sorted { $0.filename < $1.filename } - XCTAssertEqual(sortedUploads[0].filename, "a.txt") - XCTAssertEqual(sortedUploads[1].filename, "b.txt") - self.compareInitialFile(at: firstFileURL, toUploadedFileAt: sortedUploads[0].path) - self.compareInitialFile(at: secondFileURL, toUploadedFileAt: sortedUploads[1].path) - case .failure(let error): - XCTFail("Unexpected upload error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - -} diff --git a/Tests/ApolloTests/ApolloClientOperationTests.swift b/Tests/ApolloTests/ApolloClientOperationTests.swift deleted file mode 100644 index 56e40d9eaa..0000000000 --- a/Tests/ApolloTests/ApolloClientOperationTests.swift +++ /dev/null @@ -1,73 +0,0 @@ -import Apollo -import ApolloTestSupport -import StarWarsAPI -import XCTest - -final class ApolloClientOperationTests: XCTestCase, CacheDependentTesting, StoreLoading { - var cacheType: TestCacheProvider.Type { InMemoryTestCacheProvider.self } - - var cache: NormalizedCache! - var store: ApolloStore! - var server: MockGraphQLServer! - var client: ApolloClient! - - override func setUpWithError() throws { - try super.setUpWithError() - - self.cache = try self.makeNormalizedCache() - self.store = ApolloStore(cache: cache) - self.server = MockGraphQLServer() - self.client = ApolloClient( - networkTransport: MockNetworkTransport(server: self.server, store: self.store), - store: self.store - ) - } - - override func tearDownWithError() throws { - self.cache = nil - self.store = nil - self.server = nil - self.client = nil - - try super.tearDownWithError() - } - - func testPerformMutationRespectsPublishResultToStoreBoolean() throws { - let mutation = CreateReviewForEpisodeMutation(episode: .newhope, review: .init(stars: 3)) - let resultObserver = self.makeResultObserver(for: mutation) - - let serverRequestExpectation = self.server.expect(CreateReviewForEpisodeMutation.self) { _ in - [ - "data": [ - "createReview": [ - "__typename": "Review", - "stars": 3, - "commentary": "" - ] - ] - ] - } - let performResultFromServerExpectation = resultObserver.expectation(description: "Mutation was successful") { _ in } - - self.client.perform(mutation: mutation, publishResultToStore: false, resultHandler: resultObserver.handler) - - self.loadFromStore(query: mutation) { - try XCTAssertFailureResult($0) { error in - switch error as? JSONDecodingError { - // expected case, nothing to do - case .missingValue: - break - - // unexpected error, rethrow - case .none: - throw error - - default: - XCTFail("Unexpected json error: \(error)") - } - } - } - - self.wait(for: [serverRequestExpectation, performResultFromServerExpectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloTests/AutomaticPersistedQueriesTests.swift b/Tests/ApolloTests/AutomaticPersistedQueriesTests.swift deleted file mode 100644 index 5404a03897..0000000000 --- a/Tests/ApolloTests/AutomaticPersistedQueriesTests.swift +++ /dev/null @@ -1,529 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class AutomaticPersistedQueriesTests: XCTestCase { - - private static let endpoint = TestURL.mockServer.url - - // MARK: - Helper Methods - - private func validatePostBody(with request: URLRequest, - query: HeroNameQuery, - queryDocument: Bool = false, - persistedQuery: Bool = false, - file: StaticString = #filePath, - line: UInt = #line) throws { - - guard - let httpBody = request.httpBody, - let jsonBody = try? JSONSerializationFormat.deserialize(data: httpBody) as? JSONObject else { - XCTFail("httpBody invalid", - file: file, - line: line) - return - } - - let queryString = jsonBody["query"] as? String - if queryDocument { - XCTAssertEqual(queryString, - query.queryDocument, - file: file, - line: line) - } - - if let variables = jsonBody["variables"] as? JSONObject { - XCTAssertEqual(variables["episode"] as? String, - query.episode?.rawValue, - file: file, - line: line) - } else { - XCTFail("variables should not be nil", - file: file, - line: line) - } - - let ext = jsonBody["extensions"] as? JSONObject - if persistedQuery { - let ext = try XCTUnwrap(ext, - "extensions json data should not be nil", - file: file, - line: line) - - let persistedQuery = try XCTUnwrap(ext["persistedQuery"] as? JSONObject, - "persistedQuery is missing", - file: file, - line: line) - - let version = try XCTUnwrap(persistedQuery["version"] as? Int, - "version is missing", - file: file, - line: line) - - let sha256Hash = try XCTUnwrap(persistedQuery["sha256Hash"] as? String, - "sha256Hash is missing", - file: file, - line: line) - - XCTAssertEqual(version, 1, - file: file, - line: line) - XCTAssertEqual(sha256Hash, - query.operationIdentifier, - file: file, - line: line) - } else { - XCTAssertNil(ext, - "extensions should be nil", - file: file, - line: line) - } - } - - private func validatePostBody(with request: URLRequest, - mutation: CreateAwesomeReviewMutation, - queryDocument: Bool = false, - persistedQuery: Bool = false, - file: StaticString = #filePath, - line: UInt = #line) throws { - - guard - let httpBody = request.httpBody, - let jsonBody = try? JSONSerializationFormat.deserialize(data: httpBody) as? JSONObject else { - XCTFail("httpBody invalid", - file: file, - line: line) - return - } - - let queryString = jsonBody["query"] as? String - if queryDocument { - XCTAssertEqual(queryString, - mutation.queryDocument, - file: file, - line: line) - } - - let ext = jsonBody["extensions"] as? JSONObject - if persistedQuery { - let ext = try XCTUnwrap(ext, - "extensions json data should not be nil", - file: file, - line: line) - - let persistedQuery = try XCTUnwrap(ext["persistedQuery"] as? JSONObject, - "persistedQuery is missing", - file: file, - line: line) - - let version = try XCTUnwrap(persistedQuery["version"] as? Int, - "version is missing", - file: file, - line: line) - - let sha256Hash = try XCTUnwrap(persistedQuery["sha256Hash"] as? String, - "sha256Hash is missing", - file: file, - line: line) - - XCTAssertEqual(version, 1, - file: file, - line: line) - XCTAssertEqual(sha256Hash, - mutation.operationIdentifier, - file: file, - line: line) - } else { - XCTAssertNil(ext, - "extensions should be nil", - file: file, - line: line) - } - } - - private func validateUrlParams(with request: URLRequest, - query: HeroNameQuery, - queryDocument: Bool = false, - persistedQuery: Bool = false, - file: StaticString = #filePath, - line: UInt = #line) throws { - let url = try XCTUnwrap(request.url, - "URL not valid", - file: file, - line: line) - - let queryString = url.queryItemDictionary?["query"] - if queryDocument { - XCTAssertEqual(queryString, - query.queryDocument, - file: file, - line: line) - } else { - XCTAssertNil(queryString, - "query string should be nil", - file: file, - line: line) - } - - if let variables = url.queryItemDictionary?["variables"] { - if let episode = query.episode { - XCTAssertEqual(variables, - "{\"episode\":\"\(episode.rawValue)\"}", - file: file, - line: line) - } else { - XCTAssertEqual(variables, - "{\"episode\":null}", - file: file, - line: line) - } - } else { - XCTFail("variables should not be nil", - file: file, - line: line) - } - - let ext = url.queryItemDictionary?["extensions"] - if persistedQuery { - guard - let ext = ext, - let data = ext.data(using: .utf8), - let jsonBody = try? JSONSerializationFormat.deserialize(data: data) as? JSONObject - else { - XCTFail("extensions json data should not be nil", - file: file, - line: line) - return - } - - let persistedQuery = try XCTUnwrap(jsonBody["persistedQuery"] as? JSONObject, - "persistedQuery is missing", - file: file, - line: line) - - let sha256Hash = try XCTUnwrap(persistedQuery["sha256Hash"] as? String, - "sha256Hash is missing", - file: file, - line: line) - - let version = try XCTUnwrap(persistedQuery["version"] as? Int, - "version is missing", - file: file, - line: line) - - XCTAssertEqual(version, 1, - file: file, - line: line) - XCTAssertEqual(sha256Hash, query.operationIdentifier, - file: file, - line: line) - } else { - XCTAssertNil(ext, - "extension should be nil", - file: file, - line: line) - } - } - - - // MARK: - Tests - - func testRequestBody() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery() - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "POST") - - try self.validatePostBody(with: request, - query: query, - queryDocument: true) - } - - func testRequestBodyWithVariable() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery(episode: .jedi) - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "POST") - - try validatePostBody(with: request, - query: query, - queryDocument: true) - } - - - func testRequestBodyForAPQsWithVariable() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery(episode: .empire) - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "POST") - - try self.validatePostBody(with: request, - query: query, - persistedQuery: true) - } - - func testMutationRequestBodyForAPQs() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true) - - let expectation = self.expectation(description: "Mutation sent") - let mutation = CreateAwesomeReviewMutation() - var lastRequest: URLRequest? - let _ = network.send(operation: mutation) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "POST") - - try self.validatePostBody(with: request, - mutation: mutation, - persistedQuery: true) - } - - func testQueryStringForAPQsUseGetMethod() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true, - useGETForPersistedQueryRetry: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery() - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - XCTAssertEqual(request.url?.host, network.endpointURL.host) - - try self.validateUrlParams(with: request, - query: query, - persistedQuery: true) - } - - func testQueryStringForAPQsUseGetMethodWithVariable() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true, - useGETForPersistedQueryRetry: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery(episode: .empire) - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "GET") - - try self.validateUrlParams(with: request, - query: query, - persistedQuery: true) - } - - func testUseGETForQueriesRequest() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - additionalHeaders: ["Authorization": "Bearer 1234"], - useGETForQueries: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery() - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "GET") - XCTAssertEqual(request.allHTTPHeaderFields!["Authorization"], "Bearer 1234") - - try self.validateUrlParams(with: request, - query: query, - queryDocument: true) - } - - func testNotUseGETForQueriesRequest() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery() - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "POST") - - try self.validatePostBody(with: request, - query: query, - queryDocument: true) - } - - func testNotUseGETForQueriesAPQsRequest() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery(episode: .empire) - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "POST") - - try self.validatePostBody(with: request, - query: query, - persistedQuery: true) - } - - func testUseGETForQueriesAPQsRequest() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true, - useGETForQueries: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery(episode: .empire) - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 1) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "GET") - - try self.validateUrlParams(with: request, - query: query, - persistedQuery: true) - } - - func testNotUseGETForQueriesAPQsGETRequest() throws { - let mockClient = MockURLSessionClient() - let store = ApolloStore() - let provider = DefaultInterceptorProvider(client: mockClient, store: store) - let network = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: Self.endpoint, - autoPersistQueries: true, - useGETForPersistedQueryRetry: true) - - let expectation = self.expectation(description: "Query sent") - let query = HeroNameQuery(episode: .empire) - var lastRequest: URLRequest? - let _ = network.send(operation: query) { _ in - lastRequest = mockClient.lastRequest.value - expectation.fulfill() - } - self.wait(for: [expectation], timeout: 2) - - let request = try XCTUnwrap(lastRequest, "last request should not be nil") - - XCTAssertEqual(request.url?.host, network.endpointURL.host) - XCTAssertEqual(request.httpMethod, "GET") - - try self.validateUrlParams(with: request, - query: query, - persistedQuery: true) - } -} diff --git a/Tests/ApolloTests/BatchedLoadTests.swift b/Tests/ApolloTests/BatchedLoadTests.swift deleted file mode 100644 index 8ff3b986af..0000000000 --- a/Tests/ApolloTests/BatchedLoadTests.swift +++ /dev/null @@ -1,173 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -private final class MockBatchedNormalizedCache: NormalizedCache { - private var records: RecordSet - - var numberOfBatchLoads: Int32 = 0 - - init(records: RecordSet) { - self.records = records - } - - public func loadRecords(forKeys keys: Set) throws -> [CacheKey: Record] { - OSAtomicIncrement32(&numberOfBatchLoads) - - return keys.reduce(into: [:]) { results, key in - results[key] = records[key] - } - } - - func loadRecords(forKeys keys: [CacheKey], - callbackQueue: DispatchQueue?, - completion: @escaping (Result<[Record?], Error>) -> Void) { - OSAtomicIncrement32(&numberOfBatchLoads) - - DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(1)) { - let records = keys.map { self.records[$0] } - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .success(records)) - } - } - - func removeRecord(for key: CacheKey) throws { - records.removeRecord(for: key) - } - - func removeRecords(matching pattern: CacheKey) throws { - records.removeRecords(matching: pattern) - } - - func merge(records: RecordSet) throws -> Set { - return self.records.merge(records: records) - } - - func merge(records: RecordSet, - callbackQueue: DispatchQueue?, - completion: @escaping (Result, Error>) -> Void) { - DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(1)) { - let changedKeys = self.records.merge(records: records) - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .success(changedKeys)) - } - } - - func clear(callbackQueue: DispatchQueue?, completion: ((Result) -> Void)?) { - DispatchQueue.global().asyncAfter(deadline: .now() + .milliseconds(1)) { - self.records.clear() - DispatchQueue.apollo.returnResultAsyncIfNeeded(on: callbackQueue, - action: completion, - result: .success(())) - } - } - - func clear() throws { - records.clear() - } -} - -class BatchedLoadTests: XCTestCase { - func testListsAreLoadedInASingleBatch() { - var records = RecordSet() - let drones = (1...100).map { number in - Record(key: "Drone_\(number)", ["__typename": "Droid", "name": "Droid #\(number)"]) - } - - records.insert(Record(key: "QUERY_ROOT", ["hero": CacheReference(key: "2001")])) - records.insert(Record(key: "2001", [ - "name": "R2-D2", - "__typename": "Droid", - "friends": drones.map { CacheReference(key: $0.key) } - ])) - records.insert(contentsOf: drones) - - let cache = MockBatchedNormalizedCache(records: records) - let store = ApolloStore(cache: cache) - - let query = HeroAndFriendsNamesQuery() - - let expectation = self.expectation(description: "Loading query from store") - - store.load(query: query) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - - guard let data = graphQLResult.data else { - XCTFail("No data returned with result!") - return - } - - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.friends?.count, 100) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.waitForExpectations(timeout: 1) - - XCTAssertEqual(cache.numberOfBatchLoads, 3) - } - - func testParallelLoadsUseIndependentBatching() { - let records: RecordSet = [ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ] - - let cache = MockBatchedNormalizedCache(records: records) - let store = ApolloStore(cache: cache) - - let query = HeroAndFriendsNamesQuery() - - (1...10).forEach { number in - let expectation = self.expectation(description: "Loading query #\(number) from store") - - store.load(query: query) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertNil(graphQLResult.errors) - - guard let data = graphQLResult.data else { - XCTFail("No data returned with query!") - return - - } - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - } - - self.waitForExpectations(timeout: 1) - - XCTAssertEqual(cache.numberOfBatchLoads, 30) - } -} diff --git a/Tests/ApolloTests/BlindRetryingTestInterceptor.swift b/Tests/ApolloTests/BlindRetryingTestInterceptor.swift deleted file mode 100644 index 5e03b9b434..0000000000 --- a/Tests/ApolloTests/BlindRetryingTestInterceptor.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// BlindRetryingTestInterceptor.swift -// ApolloTests -// -// Created by Ellen Shapiro on 8/19/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import Foundation -import Apollo - -// An interceptor which blindly retries every time it receives a request. -class BlindRetryingTestInterceptor: ApolloInterceptor { - var hitCount = 0 - private(set) var hasBeenCancelled = false - - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - self.hitCount += 1 - chain.retry(request: request, - completion: completion) - } - - // Purposely not adhering to `Cancellable` here to make sure non `Cancellable` interceptors don't have this called. - func cancel() { - self.hasBeenCancelled = true - } -} diff --git a/Tests/ApolloTests/Cache/CacheDependentInterceptorTests.swift b/Tests/ApolloTests/Cache/CacheDependentInterceptorTests.swift deleted file mode 100644 index a645edf428..0000000000 --- a/Tests/ApolloTests/Cache/CacheDependentInterceptorTests.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// CacheDependentInterceptorTests.swift -// ApolloCacheDependentTests -// -// Created by Ellen Shapiro on 12/9/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import XCTest -import Apollo -import ApolloTestSupport -import StarWarsAPI - -class CacheDependentInterceptorTests: XCTestCase, CacheDependentTesting { - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - var cache: NormalizedCache! - var store: ApolloStore! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - store = ApolloStore(cache: cache) - } - - override func tearDown() { - cache = nil - store = nil - - super.tearDown() - } - - func testChangingCachePolicyInErrorInterceptorWorks() { - // Set up initial cache state - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - /// This interceptor will reroute anything that fails with a response code error to retry hitting only the cache - class RerouteToCacheErrorInterceptor: ApolloErrorInterceptor { - var handledError: Error? - - func handleErrorAsync( - error: Error, - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - self.handledError = error - - switch error { - case ResponseCodeInterceptor.ResponseCodeError.invalidResponseCode: - request.cachePolicy = .returnCacheDataDontFetch - chain.retry(request: request, completion: completion) - default: - completion(.failure(error)) - } - } - } - - - class TestProvider: DefaultInterceptorProvider { - init(store: ApolloStore) { - super.init(client: self.mockClient, - store: store) - } - - let mockClient: MockURLSessionClient = { - let client = MockURLSessionClient() - client.response = HTTPURLResponse(url: TestURL.mockServer.url, - statusCode: 401, - httpVersion: nil, - headerFields: nil) - client.data = Data() - return client - }() - - let additionalInterceptor = RerouteToCacheErrorInterceptor() - - override func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? { - self.additionalInterceptor - } - } - - let testProvider = TestProvider(store: self.store) - let network = RequestChainNetworkTransport(interceptorProvider: testProvider, - endpointURL: TestURL.mockServer.url) - - let expectation = self.expectation(description: "Request sent") - - // Send the initial request ignoring cache data so it doesn't initially get the data from the cache, - _ = network.send(operation: HeroNameQuery(), cachePolicy: .fetchIgnoringCacheData) { result in - defer { - expectation.fulfill() - } - - // Check that the final result is what we expected - switch result { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - case .success(let graphQLResult): - guard let heroName = graphQLResult.data?.hero?.name else { - XCTFail("Could not access hero name from returned result") - return - } - - XCTAssertEqual(heroName, "R2-D2") - } - - // Validate that there was a handled error before we went to the cache and we didn't just go straight to the cache - guard let handledError = testProvider.additionalInterceptor.handledError else { - XCTFail("No error was handled!") - return - } - switch handledError { - case ResponseCodeInterceptor.ResponseCodeError.invalidResponseCode(let response, _): - XCTAssertEqual(response?.statusCode, 401) - default: - XCTFail("Unexpected error on the additional error handler: \(handledError)") - } - } - - self.wait(for: [expectation], timeout: 5.0) - } -} - diff --git a/Tests/ApolloTests/Cache/CacheKeyConstructionTests.swift b/Tests/ApolloTests/Cache/CacheKeyConstructionTests.swift deleted file mode 100644 index 16ee8f7992..0000000000 --- a/Tests/ApolloTests/Cache/CacheKeyConstructionTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -import XCTest -@testable import ApolloSQLite - -final class CacheKeyConstructionTests: XCTestCase { - func testCacheKeySplitsPeriods() { - let input = "my.chemical.romance" - let expected = ["my", "chemical", "romance"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } - - func testCacheKeySplitsPeriodsButIgnoresParentheses() { - let input = "my.chemical.romance(xWv.CD-RIP.whole-album)" - let expected = ["my", "chemical", "romance(xWv.CD-RIP.whole-album)"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } - - func testCacheKeyIgnoresNestedParentheses() { - let input = "my.chemical.romance(the.(very)hidden.albums)" - let expected = ["my", "chemical", "romance(the.(very)hidden.albums)"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } - - func testDoubleNestedInput() { - let input = "my.chemical.romance(name:imnotokay.rip(xWv(the.original).HIGH-QUALITY)).mp3" - let expected = ["my", "chemical", "romance(name:imnotokay.rip(xWv(the.original).HIGH-QUALITY))", "mp3"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } - - func testUnbalancedInput() { - let input = "my.chemical.romance(name: )(.thebest.)()" - let expected = ["my", "chemical", "romance(name: )(.thebest.)()"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } - - func testUnbalancedInputContinued() { - let input = "my.chemical.romance(name: )(.thebest.)().count" - let expected = ["my", "chemical", "romance(name: )(.thebest.)()", "count"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } - - func testNoSplits() { - let input = "mychemicalromance" - let expected = ["mychemicalromance"] - - XCTAssertEqual(input.splitIntoCacheKeyComponents(), expected) - } -} diff --git a/Tests/ApolloTests/Cache/FetchQueryTests.swift b/Tests/ApolloTests/Cache/FetchQueryTests.swift deleted file mode 100644 index f76fb70fa3..0000000000 --- a/Tests/ApolloTests/Cache/FetchQueryTests.swift +++ /dev/null @@ -1,320 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class FetchQueryTests: XCTestCase, CacheDependentTesting { - - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 1 - - var cache: NormalizedCache! - var server: MockGraphQLServer! - var client: ApolloClient! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - let store = ApolloStore(cache: cache) - - server = MockGraphQLServer() - let networkTransport = MockNetworkTransport(server: server, store: store) - - client = ApolloClient(networkTransport: networkTransport, store: store) - } - - override func tearDownWithError() throws { - cache = nil - server = nil - client = nil - - try super.tearDownWithError() - } - - func testFetchIgnoringCacheDataOnlyHitsNetwork() throws { - let query = HeroNameQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - ] - ]) - - let serverRequestExpectation = server.expect(HeroNameQuery.self) { request in - [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - } - - let resultObserver = makeResultObserver(for: query) - - let fetchResultFromServerExpectation = resultObserver.expectation(description: "Received result from server") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - } - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData, resultHandler: resultObserver.handler) - - wait(for: [serverRequestExpectation, fetchResultFromServerExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReturnCacheDataAndFetchHitsCacheFirstAndNetworkAfter() throws { - let query = HeroNameQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - ] - ]) - - let serverRequestExpectation = server.expect(HeroNameQuery.self) { request in - [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - } - - let resultObserver = makeResultObserver(for: query) - - let fetchResultFromCacheExpectation = resultObserver.expectation(description: "Received result from cache") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - let fetchResultFromServerExpectation = resultObserver.expectation(description: "Received result from server") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - } - } - - client.fetch(query: query, cachePolicy: .returnCacheDataAndFetch, resultHandler: resultObserver.handler) - - wait(for: [fetchResultFromCacheExpectation, serverRequestExpectation, fetchResultFromServerExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReturnCacheDataElseFetchWhenDataIsCachedDoesntHitNetwork() throws { - let query = HeroNameQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "QUERY_ROOT.hero")], - "QUERY_ROOT.hero": [ - "name": "R2-D2", - "__typename": "Droid", - ] - ]) - - let resultObserver = makeResultObserver(for: query) - - let fetchResultFromCacheExpectation = resultObserver.expectation(description: "Received result from cache") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - client.fetch(query: query, cachePolicy: .returnCacheDataElseFetch, resultHandler: resultObserver.handler) - - wait(for: [fetchResultFromCacheExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReturnCacheDataElseFetchWhenNotAllDataIsCachedHitsNetwork() throws { - let query = HeroNameAndAppearsInQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid" - ] - ]) - - let serverRequestExpectation = server.expect(HeroNameAndAppearsInQuery.self) { request in - [ - "data": [ - "hero": [ - "name": "R2-D2", - "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], - "__typename": "Droid" - ] - ] - ] - } - - let resultObserver = makeResultObserver(for: query) - - let fetchResultFromServerExpectation = resultObserver.expectation(description: "Received result from server") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.appearsIn, [.newhope, .empire, .jedi]) - } - } - - client.fetch(query: query, cachePolicy: .returnCacheDataAndFetch, resultHandler: resultObserver.handler) - - wait(for: [serverRequestExpectation, fetchResultFromServerExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReturnCacheDataDontFetchWhenDataIsCachedDoesntHitNetwork() throws { - let query = HeroNameQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - ] - ]) - - let resultObserver = makeResultObserver(for: query) - - let fetchResultFromCacheExpectation = resultObserver.expectation(description: "Received result from cache") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch, resultHandler: resultObserver.handler) - - wait(for: [fetchResultFromCacheExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReturnCacheDataDontFetchWhenNotAllDataIsCachedReturnsError() throws { - let query = HeroNameAndAppearsInQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid" - ] - ]) - - let resultObserver = makeResultObserver(for: query) - - let cacheMissResultExpectation = resultObserver.expectation(description: "Received cache miss error") { result in - // TODO: We should check for a specific error type once we've defined a cache miss error. - XCTAssertThrowsError(try result.get()) - } - - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch, resultHandler: resultObserver.handler) - - wait(for: [cacheMissResultExpectation], timeout: Self.defaultWaitTimeout) - } - - func testClearCache() throws { - let query = HeroNameQuery() - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - ] - ]) - - let resultObserver = makeResultObserver(for: query) - - let fetchResultFromCacheExpectation = resultObserver.expectation(description: "Received result from cache") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch, resultHandler: resultObserver.handler) - - wait(for: [fetchResultFromCacheExpectation], timeout: Self.defaultWaitTimeout) - - let cacheMissResultExpectation = resultObserver.expectation(description: "Received cache miss error") { result in - // TODO: We should check for a specific error type once we've defined a cache miss error. - XCTAssertThrowsError(try result.get()) - } - - let cacheClearedExpectation = expectation(description: "Cache cleared") - client.clearCache { result in - XCTAssertSuccessResult(result) - cacheClearedExpectation.fulfill() - } - - wait(for: [cacheClearedExpectation], timeout: Self.defaultWaitTimeout) - - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch, resultHandler: resultObserver.handler) - - wait(for: [cacheMissResultExpectation], timeout: Self.defaultWaitTimeout) - } - - func testCompletionHandlerIsCalledOnTheSpecifiedQueue() { - let queue = DispatchQueue(label: "label") - - let key = DispatchSpecificKey() - queue.setSpecific(key: key, value: ()) - - let query = HeroNameQuery() - - let serverRequestExpectation = server.expect(HeroNameQuery.self) { request in - [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - } - - let resultObserver = makeResultObserver(for: query) - - let fetchResultExpectation = resultObserver.expectation(description: "Received fetch result") { result in - XCTAssertNotNil(DispatchQueue.getSpecific(key: key)) - } - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData, queue: queue, resultHandler: resultObserver.handler) - - wait(for: [serverRequestExpectation, fetchResultExpectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloTests/Cache/LoadQueryFromStoreTests.swift b/Tests/ApolloTests/Cache/LoadQueryFromStoreTests.swift deleted file mode 100644 index 9186d9cb15..0000000000 --- a/Tests/ApolloTests/Cache/LoadQueryFromStoreTests.swift +++ /dev/null @@ -1,278 +0,0 @@ -import XCTest -@testable import Apollo -#if canImport(ApolloSQLite) -import ApolloSQLite -#endif -import ApolloTestSupport -import StarWarsAPI - -class LoadQueryFromStoreTests: XCTestCase, CacheDependentTesting, StoreLoading { - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5.0 - - var cache: NormalizedCache! - var store: ApolloStore! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - store = ApolloStore(cache: cache) - } - - override func tearDownWithError() throws { - cache = nil - store = nil - - try super.tearDownWithError() - } - - func testLoadingHeroNameQuery() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery() - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - } - - func testLoadingHeroNameQueryWithVariable() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero(episode:JEDI)": CacheReference(key: "hero(episode:JEDI)")], - "hero(episode:JEDI)": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery(episode: .jedi) - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - } - } - } - - func testLoadingHeroNameQueryWithMissingName() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid"] - ]) - - let query = HeroNameQuery() - - loadFromStore(query: query) { result in - XCTAssertThrowsError(try result.get()) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero", "name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - } - - func testLoadingHeroNameQueryWithNullName() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": NSNull()] - ]) - - let query = HeroNameQuery() - - loadFromStore(query: query) { result in - XCTAssertThrowsError(try result.get()) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero", "name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.nullValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - } - - func testLoadingHeroAndFriendsNamesQueryWithoutIDs() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero(episode:JEDI)": CacheReference(key: "hero(episode:JEDI)")], - "hero(episode:JEDI)": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "hero(episode:JEDI).friends.0"), - CacheReference(key: "hero(episode:JEDI).friends.1"), - CacheReference(key: "hero(episode:JEDI).friends.2") - ] - ], - "hero(episode:JEDI).friends.0": ["__typename": "Human", "name": "Luke Skywalker"], - "hero(episode:JEDI).friends.1": ["__typename": "Human", "name": "Han Solo"], - "hero(episode:JEDI).friends.2": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery(episode: .jedi) - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - } - - func testLoadingHeroAndFriendsNamesQueryWithIDs() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003"), - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - } - } - - func testLoadingHeroAndFriendsNamesQueryWithNullFriends() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": NSNull(), - ] - ]) - - let query = HeroAndFriendsNamesQuery() - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertNil(data.hero?.friends) - } - } - } - - func testLoadingHeroAndFriendsNamesQueryWithMissingFriends() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroAndFriendsNamesQuery() - - loadFromStore(query: query) { result in - XCTAssertThrowsError(try result.get()) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero", "friends"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - } - - func testLoadingWithBadCacheSerialization() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": ["dictionary": "badValues", "nested bad val": ["subdictionary": "some value"] ] - ], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - loadFromStore(query: query) { result in - XCTAssertThrowsError(try result.get()) { error in - if let error = error as? GraphQLResultError, - case JSONDecodingError.couldNotConvert(_, let expectedType) = error.underlying { - XCTAssertEqual(error.path, ["hero", "friends", "0", "name"]) - XCTAssertTrue(expectedType == String.self) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - } - - func testLoadingQueryWithFloats() throws { - let starshipLength = 1234.5 - let coordinates = [[38.857150, -94.798464]] - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["starshipCoordinates(coordinates:\(coordinates))": CacheReference(key: "starshipCoordinates(coordinates:\(coordinates))")], - "starshipCoordinates(coordinates:\(coordinates))": ["__typename": "Starship", - "name": "Millennium Falcon", - "length": starshipLength, - "coordinates": coordinates] - ]) - - let query = StarshipCoordinatesQuery(coordinates: coordinates) - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.starshipCoordinates?.name, "Millennium Falcon") - XCTAssertEqual(data.starshipCoordinates?.length, starshipLength) - XCTAssertEqual(data.starshipCoordinates?.coordinates, coordinates) - } - } - } -} diff --git a/Tests/ApolloTests/Cache/ReadWriteFromStoreTests.swift b/Tests/ApolloTests/Cache/ReadWriteFromStoreTests.swift deleted file mode 100644 index 19ad10110d..0000000000 --- a/Tests/ApolloTests/Cache/ReadWriteFromStoreTests.swift +++ /dev/null @@ -1,854 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class ReadWriteFromStoreTests: XCTestCase, CacheDependentTesting, StoreLoading { - - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - static let defaultWaitTimeout: TimeInterval = 5.0 - - var cache: NormalizedCache! - var store: ApolloStore! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - store = ApolloStore(cache: cache) - } - - override func tearDownWithError() throws { - cache = nil - store = nil - - try super.tearDownWithError() - } - - func testReadHeroNameQuery() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery() - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Droid") - XCTAssertEqual(data.hero?.name, "R2-D2") - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroNameQueryAfterRemovingRecord() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery() - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadWriteTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Droid") - XCTAssertEqual(data.hero?.name, "R2-D2") - - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - - let removeCompletedExpectation = expectation(description: "Remove completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.removeObject(for: "hero") - }, completion: { result in - defer { removeCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [removeCompletedExpectation], timeout: Self.defaultWaitTimeout) - - let refetchExpectation = expectation(description: "Refetch completed") - - store.withinReadWriteTransaction({ transaction in - _ = try transaction.read(query: query) - }, completion: { result in - defer { refetchExpectation.fulfill() } - XCTAssertFailureResult(result) { refetchError in - guard let error = refetchError as? GraphQLResultError else { - XCTFail("Unexpected error trying to load a removed record: \(refetchError)") - return - } - - XCTAssertEqual(error.path, ["hero"]) - - switch error.underlying { - case JSONDecodingError.missingValue: - // This is correct. - break - default: - XCTFail("Unexpected error trying to load a removed record: \(refetchError)") - } - } - }) - - self.wait(for: [refetchExpectation], timeout: Self.defaultWaitTimeout) - } - - func testHeroNameQueryStillLoadsAfterAttemptingToDeleteFieldKey() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery() - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadWriteTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Droid") - XCTAssertEqual(data.hero?.name, "R2-D2") - - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - - let removeCompletedExpectation = expectation(description: "Remove completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.removeObject(for: "hero.name") - }, completion: { result in - defer { removeCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [removeCompletedExpectation], timeout: Self.defaultWaitTimeout) - - let refetchExpectation = expectation(description: "Refetch completed") - - store.withinReadWriteTransaction({ transaction in - _ = try transaction.read(query: query) - }, completion: { result in - defer { refetchExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [refetchExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroNameQueryWithVariable() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero(episode:JEDI)": CacheReference(key: "hero(episode:JEDI)")], - "hero(episode:JEDI)": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery(episode: .jedi) - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Droid") - XCTAssertEqual(data.hero?.name, "R2-D2") - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroNameQueryWithMissingName() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "hero")], - "hero": ["__typename": "Droid"] - ]) - - let query = HeroNameQuery() - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - XCTAssertThrowsError(try transaction.read(query: query)) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["hero", "name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testUpdateHeroNameQuery() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "QUERY_ROOT.hero")], - "QUERY_ROOT.hero": ["__typename": "Droid", "name": "R2-D2"] - ]) - - let query = HeroNameQuery() - - let updateCompletedExpectation = expectation(description: "Update completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.update(query: query) { data in - data.hero?.name = "Artoo" - } - }, completion: { result in - defer { updateCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [updateCompletedExpectation], timeout: Self.defaultWaitTimeout) - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "Artoo") - } - } - } - - func testWriteHeroNameQueryWhenErrorIsThrown() throws { - let writeCompletedExpectation = expectation(description: "Write completed") - - store.withinReadWriteTransaction({ transaction in - let data = HeroNameQuery.Data(unsafeResultMap: [:]) - try transaction.write(data: data, forQuery: HeroNameQuery(episode: nil)) - }, completion: { result in - defer { writeCompletedExpectation.fulfill() } - - XCTAssertFailureResult(result) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - }) - - self.wait(for: [writeCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroAndFriendsNamesQuery() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroAndFriendsNamesQueryFailsAfterRemovingFriendRecord() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - let readWriteCompletedExpectation = expectation(description: "ReadWrite completed") - - store.withinReadWriteTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - - try transaction.removeObject(for: "1003") - }, completion: { result in - defer { readWriteCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readWriteCompletedExpectation], timeout: Self.defaultWaitTimeout) - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - _ = try transaction.read(query: query) - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertFailureResult(result) { readError in - guard let error = readError as? GraphQLResultError else { - XCTFail("Unexpected error for reading removed record: \(readError)") - return - } - - /// The error should occur when trying to load all the hero's friend references, since one has been deleted - XCTAssertEqual(error.path, ["hero", "friends"]) - - switch error.underlying { - case JSONDecodingError.missingValue: - // This is what we want - return - default: - XCTFail("Unexpected error for reading removed record: \(error.underlying)") - } - } - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testUpdateHeroAndFriendsNamesQuery() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - let updateCompletedExpectation = expectation(description: "Update completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.update(query: query) { data in - data.hero?.friends?.append(.makeDroid(name: "C-3PO")) - } - }, completion: { result in - defer { updateCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [updateCompletedExpectation], timeout: Self.defaultWaitTimeout) - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa", "C-3PO"]) - } - } - } - - func testUpdateHeroAndFriendsNamesQueryWithVariable() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero(episode:NEWHOPE)": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery(episode: Episode.newhope) - - let updateCompletedExpectation = expectation(description: "Update completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.update(query: query) { data in - data.hero?.friends?.append(.makeDroid(name: "C-3PO")) - } - }, completion: { result in - defer { updateCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [updateCompletedExpectation], timeout: Self.defaultWaitTimeout) - - loadFromStore(query: query) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa", "C-3PO"]) - } - } - } - - func testReadAfterUpdateWithinSameTransaction() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - let readAfterUpdateCompletedExpectation = expectation(description: "Read after update completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.update(query: query) { data in - data.hero?.name = "Artoo" - data.hero?.friends?.append(.makeDroid(name: "C-3PO")) - } - - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.name, "Artoo") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa", "C-3PO"]) - }, completion: { result in - defer { readAfterUpdateCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readAfterUpdateCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroDetailsFragmentWithTypeSpecificProperty() throws { - mergeRecordsIntoCache([ - "2001": ["name": "R2-D2", "__typename": "Droid", "primaryFunction": "Protocol"] - ]) - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - let r2d2 = try transaction.readObject(ofType: HeroDetails.self, withKey: "2001") - - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.asDroid?.primaryFunction, "Protocol") - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadHeroDetailsFragmentWithMissingTypeSpecificProperty() throws { - mergeRecordsIntoCache([ - "2001": ["name": "R2-D2", "__typename": "Droid"] - ]) - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - XCTAssertThrowsError(try transaction.readObject(ofType: HeroDetails.self, withKey: "2001")) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["primaryFunction"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testReadFriendsNamesFragment() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let readCompletedExpectation = expectation(description: "Read completed") - - store.withinReadTransaction({ transaction in - let friendsNamesFragment = try transaction.readObject(ofType: FriendsNames.self, withKey: "2001") - - let friendsNames = friendsNamesFragment.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [readCompletedExpectation], timeout: Self.defaultWaitTimeout) - } - - func testUpdateFriendsNamesFragment() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let updateCompletedExpectation = expectation(description: "Update completed") - - store.withinReadWriteTransaction({ transaction in - try transaction.updateObject(ofType: FriendsNames.self, withKey: "2001") { friendsNames in - friendsNames.friends?.append(.makeDroid(name: "C-3PO")) - } - }, completion: { result in - defer { updateCompletedExpectation.fulfill() } - XCTAssertSuccessResult(result) - }) - - self.wait(for: [updateCompletedExpectation], timeout: Self.defaultWaitTimeout) - - loadFromStore(query: HeroAndFriendsNamesQuery()) { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - XCTAssertEqual(data.hero?.name, "R2-D2") - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa", "C-3PO"]) - } - } - } - - func test_removeObjectsMatchingPattern_givenPatternNotMatchingKeyCase_deletesCaseInsensitiveMatchingRecords() throws { - let heroKey = "hero" - - // - // 1. Merge all required records into the cache with lowercase key - // - - mergeRecordsIntoCache([ - "QUERY_ROOT": ["\(heroKey.lowercased())": CacheReference(key: "QUERY_ROOT.\(heroKey.lowercased())")], - "QUERY_ROOT.\(heroKey.lowercased())": ["__typename": "Droid", "name": "R2-D2"] - ]) - - // - // 2. Attempt to successfully read out the record - // - - let query = HeroNameQuery() - let readCompletedExpectation = expectation(description: "Read hero object from cache") - - store.withinReadTransaction({ transaction in - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.name, "R2-D2") - XCTAssertEqual(data.hero?.__typename, "Droid") - - }, completion: { result in - defer { readCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(result) - }) - - waitForExpectations(timeout: Self.defaultWaitTimeout) - - // - // 3. Remove object matching case insensitive (uppercase) key - // - This should remove `QUERY_ROOT.hero` using pattern `QUERY_ROOT.HERO` - // - - let removeRecordsCompletedExpectation = expectation(description: "Remove cache record by key pattern") - - store.withinReadWriteTransaction({ transaction in - try transaction.removeObjects(matching: "\(heroKey.uppercased())") - }, completion: { result in - defer { removeRecordsCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(result) - }) - - waitForExpectations(timeout: Self.defaultWaitTimeout) - - // - // 4. Attempt to read records after pattern removal - expected FAIL - // - - let readAfterRemoveCompletedExpectation = expectation(description: "Read from cache after removal by pattern") - - store.withinReadTransaction({ transaction in - _ = try transaction.read(query: query) - - }, completion: { result in - defer { readAfterRemoveCompletedExpectation.fulfill() } - - XCTAssertFailureResult(result) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - }) - - waitForExpectations(timeout: Self.defaultWaitTimeout) - } - - func test_removeObjectsMatchingPattern_givenKeyMatchingSubrangePattern_deletesMultipleRecords() throws { - - // - // 1. Merge all required records into the cache - // - - mergeRecordsIntoCache([ - "QUERY_ROOT": [ - "hero(episode:NEWHOPE)": CacheReference(key: "1002"), - "hero(episode:JEDI)": CacheReference(key: "1101"), - "hero(episode:EMPIRE)": CacheReference(key: "2001") - ], - "2001": [ - "id": "2001", - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1101"), - CacheReference(key: "1003") - ] - ], - "1101": ["__typename": "Human", "name": "Luke Skywalker", "id": "1101", "friends": []], - "1002": ["__typename": "Human", "name": "Han Solo", "id": "1002", "friends": []], - "1003": ["__typename": "Human", "name": "Leia Organa", "id": "1003", "friends": []], - ]) - - // - // 2. Attempt to successfully read out the three queries - // - - let readHeroNewHopeCompletedExpectation = expectation(description: "Read hero object for .newhope episode from cache") - - store.withinReadTransaction({ transaction in - let query = HeroAndFriendsNamesWithIDsQuery(episode: .newhope) - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Human") - XCTAssertEqual(data.hero?.name, "Han Solo") - - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, []) - - }, completion: { newHopeResult in - defer { readHeroNewHopeCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(newHopeResult) - }) - - let readHeroJediCompletedExpectation = expectation(description: "Read hero object for .jedi episode from cache") - - store.withinReadTransaction({ transaction in - let query = HeroAndFriendsNamesWithIDsQuery(episode: .jedi) - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Human") - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, []) - - }, completion: { jediResult in - defer { readHeroJediCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(jediResult) - }) - - let readHeroEmpireCompletedExpectation = expectation(description: "Read hero object for .empire episode from cache") - - store.withinReadTransaction({ transaction in - let query = HeroAndFriendsNamesWithIDsQuery(episode: .empire) - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Droid") - XCTAssertEqual(data.hero?.name, "R2-D2") - - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Leia Organa"]) - - }, completion: { empireResult in - defer { readHeroEmpireCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(empireResult) - }) - - waitForExpectations(timeout: Self.defaultWaitTimeout) - - // - // 3. Remove all objects matching the pattern `100` - // - This will remove `1002` (Han Solo, hero for the .newhope episode) - // - This will remove `1003` (Leia Organa, friend of the hero in .empire episode) - // - - let removeFromCacheCompletedExpectation = expectation(description: "Hero objects removed from cache by pattern") - - store.withinReadWriteTransaction({ transaction in - try transaction.removeObjects(matching: "100") - }, completion: { result in - defer { removeFromCacheCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(result) - }) - - waitForExpectations(timeout: Self.defaultWaitTimeout) - - // - // 4. Attempt to read records after pattern removal - // - .newhope episode query expected to FAIL on the `hero` path - // - .jedi episdoe query expected to SUCCEED - // - .empire episode query expected to FAIL on the `hero.friends` path - // - - let readHeroNewHopeAfterRemoveCompletedExpectation = expectation(description: "Read removed hero object for .newhope episode from cache") - - store.withinReadTransaction({ transaction in - let query = HeroAndFriendsNamesWithIDsQuery(episode: .newhope) - _ = try transaction.read(query: query) - - }, completion: { newHopeResult in - defer { readHeroNewHopeAfterRemoveCompletedExpectation.fulfill() } - - XCTAssertFailureResult(newHopeResult) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - }) - - let readHeroJediAfterRemoveCompletedExpectation = expectation(description: "Read removed hero object for .jedi episode from cache") - - store.withinReadTransaction({ transaction in - let query = HeroAndFriendsNamesWithIDsQuery(episode: .jedi) - let data = try transaction.read(query: query) - - XCTAssertEqual(data.hero?.__typename, "Human") - XCTAssertEqual(data.hero?.name, "Luke Skywalker") - - }, completion: { jediResult in - defer { readHeroJediAfterRemoveCompletedExpectation.fulfill() } - - XCTAssertSuccessResult(jediResult) - }) - - let readHeroEmpireAfterRemoveCompletedExpectation = expectation(description: "Read removed hero object for .empire episode from cache") - - store.withinReadTransaction({ transaction in - let query = HeroAndFriendsNamesWithIDsQuery(episode: .empire) - _ = try transaction.read(query: query) - - }, completion: { empireResult in - defer { readHeroEmpireAfterRemoveCompletedExpectation.fulfill() } - - XCTAssertFailureResult(empireResult) { error in - if let error = error as? GraphQLResultError { - XCTAssertEqual(error.path, ["hero.friends"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - }) - - waitForExpectations(timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloTests/Cache/SQLite/CachePersistenceTests.swift b/Tests/ApolloTests/Cache/SQLite/CachePersistenceTests.swift deleted file mode 100644 index ca5d8ec320..0000000000 --- a/Tests/ApolloTests/Cache/SQLite/CachePersistenceTests.swift +++ /dev/null @@ -1,212 +0,0 @@ -import XCTest -@testable import Apollo -@testable import ApolloSQLite -import ApolloTestSupport -import StarWarsAPI -import SQLite - -class CachePersistenceTests: XCTestCase { - - func testFetchAndPersist() throws { - let query = HeroNameQuery() - let sqliteFileURL = SQLiteTestCacheProvider.temporarySQLiteFileURL() - - try SQLiteTestCacheProvider.withCache(fileURL: sqliteFileURL) { (cache) in - let store = ApolloStore(cache: cache) - - let server = MockGraphQLServer() - let networkTransport = MockNetworkTransport(server: server, store: store) - - let client = ApolloClient(networkTransport: networkTransport, store: store) - - _ = server.expect(HeroNameQuery.self) { request in - [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - } - - let networkExpectation = self.expectation(description: "Fetching query from network") - let newCacheExpectation = self.expectation(description: "Fetch query from new cache") - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData) { outerResult in - defer { networkExpectation.fulfill() } - - switch outerResult { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - return - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.hero?.name, "Luke Skywalker") - // Do another fetch from cache to ensure that data is cached before creating new cache - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch) { innerResult in - try! SQLiteTestCacheProvider.withCache(fileURL: sqliteFileURL) { cache in - let newStore = ApolloStore(cache: cache) - let newClient = ApolloClient(networkTransport: networkTransport, store: newStore) - newClient.fetch(query: query, cachePolicy: .returnCacheDataDontFetch) { newClientResult in - defer { newCacheExpectation.fulfill() } - switch newClientResult { - case .success(let newClientGraphQLResult): - XCTAssertEqual(newClientGraphQLResult.data?.hero?.name, "Luke Skywalker") - case .failure(let error): - XCTFail("Unexpected error with new client: \(error)") - } - _ = newClient // Workaround for a bug - ensure that newClient is retained until this block is run - } - } - } - } - } - - self.waitForExpectations(timeout: 2, handler: nil) - } - } - - func testFetchAndPersistWithPeriodArguments() throws { - let query = SearchQuery(term: "Luke.Skywalker") - let sqliteFileURL = SQLiteTestCacheProvider.temporarySQLiteFileURL() - - try SQLiteTestCacheProvider.withCache(fileURL: sqliteFileURL) { (cache) in - let store = ApolloStore(cache: cache) - - let server = MockGraphQLServer() - let networkTransport = MockNetworkTransport(server: server, store: store) - - let client = ApolloClient(networkTransport: networkTransport, store: store) - - _ = server.expect(SearchQuery.self) { request in - [ - "data": [ - "search": [ - [ - "id": "1000", - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - ] - } - let networkExpectation = self.expectation(description: "Fetching query from network") - let newCacheExpectation = self.expectation(description: "Fetch query from new cache") - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData) { outerResult in - defer { networkExpectation.fulfill() } - - switch outerResult { - case .failure(let error): - XCTFail("Unexpected error: \(error)") - return - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.search?.first??.asHuman?.name, "Luke Skywalker") - // Do another fetch from cache to ensure that data is cached before creating new cache - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch) { innerResult in - try! SQLiteTestCacheProvider.withCache(fileURL: sqliteFileURL) { cache in - let newStore = ApolloStore(cache: cache) - let newClient = ApolloClient(networkTransport: networkTransport, store: newStore) - newClient.fetch(query: query, cachePolicy: .returnCacheDataDontFetch) { newClientResult in - defer { newCacheExpectation.fulfill() } - switch newClientResult { - case .success(let newClientGraphQLResult): - XCTAssertEqual(newClientGraphQLResult.data?.search?.first??.asHuman?.name, "Luke Skywalker") - case .failure(let error): - XCTFail("Unexpected error with new client: \(error)") - } - _ = newClient // Workaround for a bug - ensure that newClient is retained until this block is run - } - } - } - } - } - - self.waitForExpectations(timeout: 2, handler: nil) - } - } - - func testPassInConnectionDoesNotThrow() { - do { - let database = try SQLiteDotSwiftDatabase(connection: Connection()) - _ = try SQLiteNormalizedCache(database: database) - - } catch { - XCTFail("Passing in connection failed with error: \(error)") - } - } - - func testClearCache() throws { - let query = HeroNameQuery() - let sqliteFileURL = SQLiteTestCacheProvider.temporarySQLiteFileURL() - - try SQLiteTestCacheProvider.withCache(fileURL: sqliteFileURL) { (cache) in - let store = ApolloStore(cache: cache) - - let server = MockGraphQLServer() - let networkTransport = MockNetworkTransport(server: server, store: store) - - let client = ApolloClient(networkTransport: networkTransport, store: store) - - _ = server.expect(HeroNameQuery.self) { request in - [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - } - - let networkExpectation = self.expectation(description: "Fetching query from network") - let emptyCacheExpectation = self.expectation(description: "Fetch query from empty cache") - let cacheClearExpectation = self.expectation(description: "cache cleared") - - client.fetch(query: query, cachePolicy: .fetchIgnoringCacheData) { outerResult in - defer { networkExpectation.fulfill() } - - switch outerResult { - case .failure(let error): - XCTFail("Unexpected failure: \(error)") - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.hero?.name, "Luke Skywalker") - } - - client.clearCache(completion: { result in - switch result { - case .success: - break - case .failure(let error): - XCTFail("Error clearing cache: \(error)") - } - cacheClearExpectation.fulfill() - }) - - client.fetch(query: query, cachePolicy: .returnCacheDataDontFetch) { innerResult in - defer { emptyCacheExpectation.fulfill() } - - switch innerResult { - case .success: - XCTFail("This should have returned an error") - case .failure(let error): - if let resultError = error as? JSONDecodingError { - switch resultError { - case .missingValue: - // Correct error! - break - default: - XCTFail("Unexpected JSON error: \(error)") - } - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - } - - self.waitForExpectations(timeout: 2, handler: nil) - } - } -} diff --git a/Tests/ApolloTests/Cache/SQLite/SQLiteCacheTests.swift b/Tests/ApolloTests/Cache/SQLite/SQLiteCacheTests.swift deleted file mode 100644 index 9d6eb81c43..0000000000 --- a/Tests/ApolloTests/Cache/SQLite/SQLiteCacheTests.swift +++ /dev/null @@ -1,29 +0,0 @@ -import Foundation -import ApolloTestSupport - -// These test cases inherit all tests from their superclasses. - -class SQLiteFetchQueryTests: FetchQueryTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteLoadQueryFromStoreTests: LoadQueryFromStoreTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteReadWriteFromStoreTests: ReadWriteFromStoreTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - -class SQLiteWatchQueryTests: WatchQueryTests { - override var cacheType: TestCacheProvider.Type { - SQLiteTestCacheProvider.self - } -} - diff --git a/Tests/ApolloTests/Cache/StoreConcurrencyTests.swift b/Tests/ApolloTests/Cache/StoreConcurrencyTests.swift deleted file mode 100644 index 78039593ae..0000000000 --- a/Tests/ApolloTests/Cache/StoreConcurrencyTests.swift +++ /dev/null @@ -1,218 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class StoreConcurrencyTests: XCTestCase, CacheDependentTesting { - - var cacheType: TestCacheProvider.Type { - InMemoryTestCacheProvider.self - } - - var defaultWaitTimeout: TimeInterval = 60 - - var cache: NormalizedCache! - var store: ApolloStore! - - override func setUpWithError() throws { - try super.setUpWithError() - - cache = try makeNormalizedCache() - store = ApolloStore(cache: cache) - } - - override func tearDownWithError() throws { - cache = nil - store = nil - - try super.tearDownWithError() - } - - func testConcurrentReadsInitiatedFromMainThread() throws { - mergeRecordsIntoCache([ - "QUERY_ROOT": ["hero": CacheReference(key: "2001")], - "2001": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - CacheReference(key: "1000"), - CacheReference(key: "1002"), - CacheReference(key: "1003") - ] - ], - "1000": ["__typename": "Human", "name": "Luke Skywalker"], - "1002": ["__typename": "Human", "name": "Han Solo"], - "1003": ["__typename": "Human", "name": "Leia Organa"], - ]) - - let query = HeroAndFriendsNamesQuery() - - let numberOfReads = 1000 - - let allReadsCompletedExpectation = XCTestExpectation(description: "All reads completed") - allReadsCompletedExpectation.expectedFulfillmentCount = numberOfReads - - for _ in 0..? = GraphQLQueryWatcher(client: client, query: watchedQuery, resultHandler: resultObserver.handler) - weak var weakWatcher: GraphQLQueryWatcher? = watcher - - runActivity("Initial fetch from server") { _ in - let serverRequestExpectation = server.expect(HeroAndFriendsNamesWithIDsQuery.self) { request in - [ - "data": [ - "hero": [ - "id": "2001", - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - ["__typename": "Human", "id": "1000", "name": "Luke Skywalker"], - ] - ] - ] - ] - } - - let initialWatcherResultExpectation = resultObserver.expectation(description: "Watcher received initial result from server") { result in - try XCTAssertSuccessResult(result) { graphQLResult in - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertNil(graphQLResult.errors) - - let data = try XCTUnwrap(graphQLResult.data) - - XCTAssertEqual(data.hero?.name, "R2-D2") - - let friendsNames = data.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker"]) - - let expectedDependentKeys: Set = [ - "2001.__typename", - "2001.friends", - "2001.id", - "2001.name", - "1000.__typename", - "1000.id", - "1000.name", - "QUERY_ROOT.hero", - ] - let actualDependentKeys = try XCTUnwrap(graphQLResult.dependentKeys) - XCTAssertEqual(actualDependentKeys, expectedDependentKeys) - } - } - - watcher?.fetch(cachePolicy: .fetchIgnoringCacheData) - - wait(for: [serverRequestExpectation, initialWatcherResultExpectation], timeout: Self.defaultWaitTimeout) - } - - runActivity("make sure it gets released") { _ in - watcher = nil - cache = nil - server = nil - client = nil - - XCTAssertTrueEventually(weakWatcher == nil, message: "Watcher was not released.") - } - } -} diff --git a/Tests/ApolloTests/CacheKeyForFieldTests.swift b/Tests/ApolloTests/CacheKeyForFieldTests.swift deleted file mode 100644 index faa8ff6129..0000000000 --- a/Tests/ApolloTests/CacheKeyForFieldTests.swift +++ /dev/null @@ -1,87 +0,0 @@ -import XCTest -import Apollo -import ApolloTestSupport -import StarWarsAPI - -extension GraphQLField { - var cacheKey: String { - return try! cacheKey(with: nil) - } -} - -class CacheKeyForFieldTests: XCTestCase { - func testFieldWithResponseNameOnly() { - let field = GraphQLField("hero", type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero") - } - - func testFieldWithAlias() { - let field = GraphQLField("hero", alias: "r2", type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero") - } - - func testFieldWithAliasAndArgument() { - let field = GraphQLField("hero", alias: "r2", arguments: ["episode": "JEDI"], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero(episode:JEDI)") - } - - func testFieldWithStringArgument() { - let field = GraphQLField("hero", arguments: ["episode": "JEDI"], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero(episode:JEDI)") - } - - func testFieldWithIntegerArgument() { - let field = GraphQLField("hero", arguments: ["episode": 1], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero(episode:1)") - } - - func testFieldWithFloatArgument() { - let field = GraphQLField("hero", arguments: ["episode": 1.99], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero(episode:1.99)") - } - - func testFieldWithNilArgument() { - let field = GraphQLField("hero", arguments: ["episode": nil], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero") - } - - func testFieldWithListArgument() { - let field = GraphQLField("hero", arguments: ["episodes": [1, 1, 2]], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero(episodes:[1, 1, 2])") - } - - func testFieldWithDictionaryArgument() throws { - let field = GraphQLField("hero", arguments: ["nested": ["foo": 1, "bar": 2]], type: .scalar(String.self)) - XCTAssertEqual(field.cacheKey, "hero([nested:bar:2,foo:1])") - } - - func testFieldWithDictionaryArgumentWithVariables() throws { - let field = GraphQLField("hero", arguments: ["nested": ["foo": GraphQLVariable("a"), "bar": GraphQLVariable("b")]], type: .scalar(String.self)) - let variables: GraphQLMap = ["a": 1, "b": 2] - XCTAssertEqual(try field.cacheKey(with: variables), "hero([nested:bar:2,foo:1])") - } - - func testFieldWithMultipleArgumentsIsOrderIndependent() { - let field1 = GraphQLField("hero", arguments: ["foo": "a", "bar": "b"], type: .scalar(String.self)) - let field2 = GraphQLField("hero", arguments: ["bar": "b", "foo": "a"], type: .scalar(String.self)) - XCTAssertEqual(field1.cacheKey, field2.cacheKey) - } - - func testFieldWithInputObjectArgumentIsOrderIndependent() { - let field1 = GraphQLField("hero", arguments: ["episode": "JEDI", "nested": ["foo": "a", "bar": "b"]], type: .scalar(String.self)) - let field2 = GraphQLField("hero", arguments: ["episode": "JEDI", "nested": ["bar": "b", "foo": "a"]], type: .scalar(String.self)) - XCTAssertEqual(field1.cacheKey, field2.cacheKey) - } - - func testFieldWithVariableArgument() throws { - let field = GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .scalar(String.self)) - let variables = ["episode": Episode.jedi] - XCTAssertEqual(try field.cacheKey(with: variables), "hero(episode:JEDI)") - } - - func testFieldWithVariableArgumentWithNil() throws { - let field = GraphQLField("hero", arguments: ["episode": GraphQLVariable("episode")], type: .scalar(String.self)) - let variables: GraphQLMap = ["episode": nil as Optional] - XCTAssertEqual(try field.cacheKey(with: variables), "hero") - } -} diff --git a/Tests/ApolloTests/CancellationHandlingInterceptor.swift b/Tests/ApolloTests/CancellationHandlingInterceptor.swift deleted file mode 100644 index 726ce36349..0000000000 --- a/Tests/ApolloTests/CancellationHandlingInterceptor.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// CancellationHandlingInterceptor.swift -// ApolloTests -// -// Created by Ellen Shapiro on 9/17/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import Foundation -import Apollo - -class CancellationHandlingInterceptor: ApolloInterceptor, Cancellable { - private(set) var hasBeenCancelled = false - - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - guard !self.hasBeenCancelled else { - return - } - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - } - - func cancel() { - self.hasBeenCancelled = true - } -} diff --git a/Tests/ApolloTests/DataLoaderTests.swift b/Tests/ApolloTests/DataLoaderTests.swift deleted file mode 100644 index bd764d4e5c..0000000000 --- a/Tests/ApolloTests/DataLoaderTests.swift +++ /dev/null @@ -1,85 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class DataLoaderTests: XCTestCase { - func testSingleLoad() throws { - let loader = DataLoader { keys in - return self.wordsForNumbers(keys) - } - - XCTAssertEqual(try loader[1].get(), "one") - } - - func testMultipleLoads() throws { - var numberOfBatchLoads = 0 - - let loader = DataLoader { keys in - numberOfBatchLoads += 1 - return self.wordsForNumbers(keys) - } - - let results = [loader[1], loader[2]] - let values = try results.map { try $0.get() } - - XCTAssertEqual(values, ["one", "two"]) - XCTAssertEqual(numberOfBatchLoads, 1) - } - - func testCoalescesIdenticalRequests() throws { - var batchLoads: [Set] = [] - - let loader = DataLoader { keys in - batchLoads.append(keys) - return self.wordsForNumbers(keys) - } - - let results = [loader[1], loader[1]] - let values = try results.map { try $0.get() } - - XCTAssertEqual(values, ["one", "one"]) - XCTAssertEqual(batchLoads.count, 1) - XCTAssertEqual(batchLoads[0], [1]) - } - - func testCachesRepeatedRequests() throws { - var batchLoads: [Set] = [] - - let loader = DataLoader { keys in - batchLoads.append(keys) - return self.wordsForNumbers(keys) - } - - let results1 = [loader[1], loader[2]] - let values1 = try results1.map { try $0.get() } - - XCTAssertEqual(values1, ["one", "two"]) - XCTAssertEqual(batchLoads.count, 1) - XCTAssertEqualUnordered(batchLoads[0], [1, 2]) - - let results2 = [loader[1], loader[3]] - let values2 = try results2.map { try $0.get() } - - XCTAssertEqual(values2, ["one", "three"]) - XCTAssertEqual(batchLoads.count, 2) - XCTAssertEqual(batchLoads[1], [3]) - - let results3 = [loader[1], loader[2], loader[3]] - let values3 = try results3.map { try $0.get() } - - XCTAssertEqual(values3, ["one", "two", "three"]) - XCTAssertEqual(batchLoads.count, 2) - } - - // - Helpers - - private func wordsForNumbers(_ keys: Set) -> [Int: String] { - let formatter = NumberFormatter() - formatter.numberStyle = .spellOut - - return keys.reduce(into: [:]) { result, key in - result[key] = formatter.string(from: key as NSNumber) - } - } -} diff --git a/Tests/ApolloTests/DefaultInterceptorProviderTests.swift b/Tests/ApolloTests/DefaultInterceptorProviderTests.swift deleted file mode 100644 index 90af503b08..0000000000 --- a/Tests/ApolloTests/DefaultInterceptorProviderTests.swift +++ /dev/null @@ -1,86 +0,0 @@ -import XCTest -import Apollo -import ApolloTestSupport -import StarWarsAPI - -class DefaultInterceptorProviderTests: XCTestCase { - - var client: ApolloClient! - var mockServer: MockGraphQLServer! - - static let mockData: JSONObject = [ - "data": [ - "hero": [ - "name": "R2-D2", - "__typename": "Droid" - ] - ] - ] - - override func setUp() { - mockServer = MockGraphQLServer() - let store = ApolloStore() - let networkTransport = MockNetworkTransport(server: mockServer, store: store) - client = ApolloClient(networkTransport: networkTransport, store: store) - } - - override func tearDown() { - client = nil - mockServer = nil - - super.tearDown() - } - - func testLoading() { - let expectation = mockServer.expect(HeroNameQuery.self) { _ in - DefaultInterceptorProviderTests.mockData - } - - client.fetch(query: HeroNameQuery()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.wait(for: [expectation], timeout: 10) - } - - func testInitialLoadFromNetworkAndSecondaryLoadFromCache() { - let initialLoadExpectation = mockServer.expect(HeroNameQuery.self) { _ in - DefaultInterceptorProviderTests.mockData - } - initialLoadExpectation.assertForOverFulfill = false - - client.fetch(query: HeroNameQuery()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .server) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - self.wait(for: [initialLoadExpectation], timeout: 10) - - let secondLoadExpectation = self.expectation(description: "loaded with default client") - - client.fetch(query: HeroNameQuery()) { result in - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.source, .cache) - XCTAssertEqual(graphQLResult.data?.hero?.name, "R2-D2") - case .failure(let error): - XCTFail("Unexpected error: \(error)") - - } - secondLoadExpectation.fulfill() - } - - self.wait(for: [secondLoadExpectation], timeout: 10) - } -} diff --git a/Tests/ApolloTests/ErrorGenerationTests.swift b/Tests/ApolloTests/ErrorGenerationTests.swift deleted file mode 100644 index a7dde1e64a..0000000000 --- a/Tests/ApolloTests/ErrorGenerationTests.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// ErrorGenerationTests.swift -// Apollo -// -// Created by Ellen Shapiro on 9/9/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import Apollo -import XCTest -import StarWarsAPI - -class ErrorGenerationTests: XCTestCase { - - private func checkExtensions(on error: GraphQLError, - expectedDict: [String: Any?], - file: StaticString = #filePath, - line: UInt = #line) { - XCTAssertEqual(error.extensions?.count, - expectedDict.count, - file: file, - line: line) - - for (key, expectedValue) in expectedDict { - let actualValue = error.extensions?[key] as? String - let stringExpectedValue = expectedValue as? String - XCTAssertEqual(actualValue, - stringExpectedValue, - "Value for key \(key) did not match expected value \(String(describing: stringExpectedValue)), it was \(String(describing: actualValue))", - file: file, - line: line) - } - } - - func testSingleErrorParsing() throws { - let json = """ -{ - "data": { - "hero": null - }, - "errors": [ - { - "message": "Invalid client auth token.", - "extensions": { - "code": "INTERNAL_SERVER_ERROR" - } - } - ] -} -""" - - let data = try XCTUnwrap(json.data(using: .utf8), - "Couldn't create json data") - let deserialized = try JSONSerializationFormat.deserialize(data: data) - let jsonObject = try XCTUnwrap(deserialized as? JSONObject) - let response = GraphQLResponse(operation: HeroNameQuery(), body: jsonObject) - let result = try response.parseResultFast() - XCTAssertNotNil(result.data) - XCTAssertNil(result.data?.hero) - - XCTAssertEqual(result.errors?.count, 1) - let error = try XCTUnwrap(result.errors?.first) - XCTAssertEqual(error.message, "Invalid client auth token.") - - self.checkExtensions(on: error, expectedDict: [ - "code": "INTERNAL_SERVER_ERROR" - ]) - } - - func testLocalizedStringFromErrorResponseWithMultipleErrors() throws { - let json = """ -{ - "data": { - "hero": null - }, - "errors": [ - { - "message": "Invalid client auth token.", - "extensions": { - "code": "INTERNAL_SERVER_ERROR" - } - }, - { - "message": "Server is having a sad.", - "extensions": { - "code": "INTERNAL_SERVER_ERROR" - } - } - ] -} -""" - - let data = try XCTUnwrap(json.data(using: .utf8), - "Couldn't create json data") - let deserialized = try JSONSerializationFormat.deserialize(data: data) - let jsonObject = try XCTUnwrap(deserialized as? JSONObject) - let response = GraphQLResponse(operation: HeroNameQuery(), body: jsonObject) - let result = try response.parseResultFast() - XCTAssertNotNil(result.data) - XCTAssertNil(result.data?.hero) - - let errors = try XCTUnwrap(result.errors) - - XCTAssertEqual(errors.count, 2) - XCTAssertEqual(errors.map { $0.message }, [ - "Invalid client auth token.", - "Server is having a sad.", - ]) - - for error in errors { - self.checkExtensions(on: error, expectedDict: [ - "code": "INTERNAL_SERVER_ERROR" - ]) - } - } -} diff --git a/Tests/ApolloTests/ExecutionTests.swift b/Tests/ApolloTests/ExecutionTests.swift deleted file mode 100644 index d7c492f161..0000000000 --- a/Tests/ApolloTests/ExecutionTests.swift +++ /dev/null @@ -1,53 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport - -class ExecutionTests: XCTestCase { - static let defaultWaitTimeout = 0.5 - - var store: ApolloStore! - var server: MockGraphQLServer! - var transport: NetworkTransport! - var client: ApolloClient! - - override func setUp() { - store = ApolloStore() - server = MockGraphQLServer() - transport = MockNetworkTransport(server: server, store: store) - client = ApolloClient(networkTransport: transport, store: store) - } - - override func tearDown() { - client = nil - transport = nil - server = nil - store = nil - } - - func testClearCacheCompletion_givenNoCallbackQueue_shouldCallbackOnMainQueue() throws { - let completionCallbackExpectation = expectation(description: "clearCache completion callback on main queue") - client.clearCache() { result in - XCTAssertTrue(Thread.isMainThread) - - completionCallbackExpectation.fulfill() - } - - wait(for: [completionCallbackExpectation], timeout: Self.defaultWaitTimeout) - } - - func testCacheClearCompletion_givenCustomCallbackQueue_shouldCallbackOnCustomQueue() throws { - let label = "CustomQueue" - let queue = DispatchQueue(label: label) - let key = DispatchSpecificKey() - queue.setSpecific(key: key, value: label) - - let completionCallbackExpectation = expectation(description: "clearCache completion callback on custom queue") - client.clearCache(callbackQueue: queue) { result in - XCTAssertEqual(DispatchQueue.getSpecific(key: key), label) - - completionCallbackExpectation.fulfill() - } - - wait(for: [completionCallbackExpectation], timeout: Self.defaultWaitTimeout) - } -} diff --git a/Tests/ApolloTests/FragmentConstructionAndConversionTests.swift b/Tests/ApolloTests/FragmentConstructionAndConversionTests.swift deleted file mode 100644 index a25f76fa32..0000000000 --- a/Tests/ApolloTests/FragmentConstructionAndConversionTests.swift +++ /dev/null @@ -1,405 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class FragmentConstructionAndConversionTests: XCTestCase { - // MARK: - Manually constructing fragments - - func testConstructDroidNameFragment() throws { - let r2d2 = DroidName(name: "R2-D2") - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - } - - func testConstructCharacterNameFragmentForDroid() throws { - let r2d2 = CharacterName.makeDroid(name: "R2-D2") - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - } - - func testConstructCharacterAppearsInFragmentForDroid() throws { - let r2d2 = CharacterAppearsIn.makeDroid(appearsIn: [.newhope, .empire, .jedi]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.appearsIn, [.newhope, .empire, .jedi]) - } - - func testConstructCharacterNameAndDroidAppearsInFragmentForDroid() throws { - let r2d2 = CharacterNameAndDroidAppearsIn.makeDroid(name: "R2-D2", appearsIn: [.newhope, .empire, .jedi]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.asDroid?.appearsIn, [.newhope, .empire, .jedi]) - } - - func testConstructCharacterNameAndDroidAppearsInFragmentForHuman() throws { - let luke = CharacterNameAndDroidAppearsIn.makeHuman(name: "Luke Skywalker") - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertNil(luke.asDroid) - } - - func testConstructCharacterNameAndDroidPrimaryFunctionFragmentForDroid() throws { - let r2d2 = CharacterNameAndDroidPrimaryFunction.makeDroid(name: "R2-D2", primaryFunction: "Protocol") - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.asDroid?.primaryFunction, "Protocol") - XCTAssertEqual(r2d2.fragments.characterName.name, "R2-D2") - XCTAssertEqual(r2d2.fragments.droidPrimaryFunction?.primaryFunction, "Protocol") - } - - func testConstructCharacterNameAndDroidPrimaryFunctionFragmentForHuman() throws { - let luke = CharacterNameAndDroidPrimaryFunction.makeHuman(name: "Luke Skywalker") - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertNil(luke.asDroid) - XCTAssertEqual(luke.fragments.characterName.name, "Luke Skywalker") - XCTAssertNil(luke.fragments.droidPrimaryFunction) - } - - func testConstructDroidNameAndPrimaryFunctionFragment() throws { - let r2d2 = DroidNameAndPrimaryFunction(name: "R2-D2", primaryFunction: "Protocol") - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.primaryFunction, "Protocol") - } - - func testConstructHeroDetailsFragmentWithDroidSpecificProperty() throws { - let r2d2 = HeroDetails.makeDroid(name: "R2-D2", primaryFunction: "Protocol") - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.asDroid?.primaryFunction, "Protocol") - XCTAssertNil(r2d2.asHuman) - } - - func testConstructHeroDetailsFragmentWithMissingDroidSpecificProperty() throws { - let r2d2 = HeroDetails.makeDroid(name: "R2-D2") - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertNil(r2d2.asDroid?.primaryFunction) - XCTAssertNil(r2d2.asHuman) - } - - func testConstructHeroDetailsFragmentWithNullDroidSpecificProperty() throws { - let r2d2 = HeroDetails.makeDroid(name: "R2-D2", primaryFunction: nil) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertNil(r2d2.asDroid?.primaryFunction) - XCTAssertNil(r2d2.asHuman) - } - - func testConstructHeroDetailsFragmentWithHumanSpecificProperty() throws { - let luke = HeroDetails.makeHuman(name: "Luke Skywalker", height: 1.72) - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertEqual(luke.asHuman?.height, 1.72) - XCTAssertNil(luke.asDroid) - } - - func testConstructHeroDetailsFragmentWithMissingHumanSpecificProperty() throws { - let luke = HeroDetails.makeHuman(name: "Luke Skywalker") - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertNil(luke.asHuman?.height) - XCTAssertNil(luke.asDroid) - } - - func testConstructHeroDetailsFragmentWithNullHumanSpecificProperty() throws { - let luke = HeroDetails.makeHuman(name: "Luke Skywalker", height: nil) - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertNil(luke.asHuman?.height) - XCTAssertNil(luke.asDroid) - } - - func testConstructHumanHeightWithVariableFragment() throws { - let luke = HumanHeightWithVariable(height: 1.72) - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.height, 1.72) - } - - // MARK: - Converting fragments into JSON objects - - func testJSONObjectFromCharacterNameFragment() throws { - let r2d2 = CharacterName.makeDroid(name: "R2-D2") - - XCTAssertEqual(r2d2.jsonObject, ["__typename": "Droid", "name": "R2-D2"]) - } - - func testJSONObjectFromCharacterAppearsInFragment() throws { - let r2d2 = CharacterAppearsIn.makeDroid(appearsIn: [.newhope, .empire, .jedi]) - - XCTAssertEqual(r2d2.jsonObject, ["__typename": "Droid", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]]) - } - - func testJSONObjectFromCharacterNameAndDroidAppearsInFragmentForDroid() throws { - let r2d2 = CharacterNameAndDroidAppearsIn.makeDroid(name: "R2-D2", appearsIn: [.newhope, .empire, .jedi]) - - XCTAssertEqual(r2d2.jsonObject, ["__typename": "Droid", "name": "R2-D2", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]]) - } - - func testJSONObjectFromCharacterNameAndDroidAppearsInFragmentForHuman() throws { - let r2d2 = CharacterNameAndDroidAppearsIn.makeHuman(name: "Luke Skywalker") - - XCTAssertEqual(r2d2.jsonObject, ["__typename": "Human", "name": "Luke Skywalker"]) - } - - func testJSONObjectFromHeroDetailsFragmentWithTypeSpecificProperty() throws { - let r2d2 = HeroDetails.makeDroid(name: "R2-D2", primaryFunction: "Protocol") - - XCTAssertEqual(r2d2.jsonObject, ["__typename": "Droid", "name": "R2-D2", "primaryFunction": "Protocol"]) - } - - func testJSONObjectFromHeroDetailsFragmentWithMissingTypeSpecificProperty() throws { - let r2d2 = HeroDetails.makeDroid(name: "R2-D2") - - XCTAssertEqual(r2d2.jsonObject, ["__typename": "Droid", "name": "R2-D2", "primaryFunction": NSNull()]) - } - - func testJSONObjectFromHumanHeightWithVariableFragment() throws { - let luke = HumanHeightWithVariable(height: 1.72) - - XCTAssertEqual(luke.jsonObject, ["__typename": "Human", "height": 1.72]) - } - - // MARK: - Converting JSON objects into fragments - - func testCharacterNameFragmentForDroidFromJSONObject() throws { - let r2d2 = try CharacterName(jsonObject: ["__typename": "Droid", "name": "R2-D2"]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - } - - func testCharacterNameFragmentForDroidFromJSONObjectWithMissingName() throws { - XCTAssertThrowsError(try CharacterName(jsonObject: ["__typename": "Droid"])) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testCharacterNameFragmentForDroidFromJSONObjectWithNullName() throws { - XCTAssertThrowsError(try CharacterName(jsonObject: ["__typename": "Droid", "name": NSNull()])) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.nullValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testCharacterNameFragmentFromJSONObjectWithMissingTypename() throws { - XCTAssertThrowsError(try CharacterName(jsonObject: ["name": "R2-D2"])) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["__typename"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testCharacterNameFragmentFromJSONObjectWithUnknownTypename() throws { - let r2d2 = try CharacterName(jsonObject: ["__typename": "Pokemon", "name": "Charmander"]) - - XCTAssertEqual(r2d2.__typename, "Pokemon") - XCTAssertEqual(r2d2.name, "Charmander") - } - - func testCharacterAppearsInFragmentFromJSONObjectForDroid() throws { - let r2d2 = try CharacterAppearsIn(jsonObject: ["__typename": "Droid", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.appearsIn, [.newhope, .empire, .jedi]) - } - - func testCharacterNameAndDroidAppearsInFragmentFromJSONObjectForDroid() throws { - let r2d2 = try CharacterNameAndDroidAppearsIn(jsonObject: ["__typename": "Droid", "name": "R2-D2", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.asDroid?.appearsIn, [.newhope, .empire, .jedi]) - } - - func testCharacterNameAndDroidAppearsInFragmentFromJSONObjectForDroidRequiresAppearsIn() throws { - XCTAssertThrowsError(try CharacterNameAndDroidAppearsIn(jsonObject: ["__typename": "Droid", "name": "R2-D2"])) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testCharacterNameAndDroidAppearsInFragmentFromJSONObjectForHuman() throws { - let luke = try CharacterNameAndDroidAppearsIn(jsonObject: ["__typename": "Human", "name": "Luke Skywalker"]) - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertNil(luke.asDroid) - } - - func testCharacterNameAndDroidAppearsInFragmentFromJSONObjectForHumanIgnoresAppearsIn() throws { - let luke = try CharacterNameAndDroidAppearsIn(jsonObject: ["__typename": "Human", "name": "Luke Skywalker", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]]) - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.name, "Luke Skywalker") - XCTAssertNil(luke.asDroid) - } - - func testHeroDetailsFragmentFromJSONObjectWithTypeSpecificProperty() throws { - let r2d2 = try HeroDetails(jsonObject: ["__typename": "Droid", "name": "R2-D2", "primaryFunction": "Protocol"]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertEqual(r2d2.asDroid?.primaryFunction, "Protocol") - XCTAssertNil(r2d2.asHuman) - } - - func testHeroDetailsFragmentFromJSONObjectWithMissingTypeSpecificProperty() throws { - XCTAssertThrowsError(try HeroDetails(jsonObject: ["__typename": "Droid", "name": "R2-D2"])) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["primaryFunction"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testHeroDetailsFragmentFromJSONObjectWithNullTypeSpecificProperty() throws { - let r2d2 = try HeroDetails(jsonObject: ["__typename": "Droid", "name": "R2-D2", "primaryFunction": NSNull()]) - - XCTAssertEqual(r2d2.__typename, "Droid") - XCTAssertEqual(r2d2.name, "R2-D2") - XCTAssertNil(r2d2.asDroid?.primaryFunction) - XCTAssertNil(r2d2.asHuman) - } - - func testHumanHeightWithVariableFragmentFromJSONObject() throws { - let luke = try HumanHeightWithVariable(jsonObject: ["__typename": "Human", "height": 1.72]) - - XCTAssertEqual(luke.__typename, "Human") - XCTAssertEqual(luke.height, 1.72) - } - - // MARK: - Converting fragments into another type of fragment - - func testConvertCharacterNameAndAppearsInFragmentIntoCharacterNameFragment() throws { - let characterNameAndAppearsIn = CharacterNameAndAppearsIn.makeDroid(name: "R2-D2", appearsIn: [.newhope, .empire, .jedi]) - - let characterName = try CharacterName(characterNameAndAppearsIn) - - XCTAssertEqual(characterName.__typename, "Droid") - XCTAssertEqual(characterName.name, "R2-D2") - } - - func testConvertCharacterNameIntoCharacterNameAndAppearsInFragment() throws { - let characterName = CharacterName.makeDroid(name: "R2-D2") - - XCTAssertThrowsError(try CharacterNameAndAppearsIn(characterName)) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testConvertCharacterNameIntoCharacterNameAndDroidAppearsInFragment() throws { - let characterName = CharacterName.makeDroid(name: "R2-D2") - - XCTAssertThrowsError(try CharacterNameAndDroidAppearsIn(characterName)) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testConvertHeroDetailsIntoCharacterNameFragment() throws { - let heroDetails = HeroDetails.makeDroid(name: "R2-D2", primaryFunction: "Protocol") - - let heroName = try CharacterName(heroDetails) - - XCTAssertEqual(heroName.__typename, "Droid") - XCTAssertEqual(heroName.name, "R2-D2") - } - - func testConvertCharacterNameIntoHeroDetailsFragment() throws { - let characterName = CharacterName.makeDroid(name: "R2-D2") - - XCTAssertThrowsError(try HeroDetails(characterName)) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["primaryFunction"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testConvertCharacterNameIntoCharacterNameAndDroidAppearsInFragmentForDroid() throws { - let characterName = CharacterName.makeDroid(name: "R2-D2") - - XCTAssertThrowsError(try CharacterNameAndDroidAppearsIn(characterName)) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testConvertCharacterNameIntoCharacterNameAndDroidAppearsInFragmentForHuman() throws { - let characterName = CharacterName.makeHuman(name: "Luke Skywalker") - - let characterNameAndDroidAppearsIn = try CharacterNameAndDroidAppearsIn(characterName) - - XCTAssertEqual(characterNameAndDroidAppearsIn.__typename, "Human") - XCTAssertEqual(characterNameAndDroidAppearsIn.name, "Luke Skywalker") - } - - func testConvertCharacterNameIntoDroidNameFragmentForDroid() throws { - let characterName = CharacterName.makeDroid(name: "R2-D2") - - let droidName = try DroidName(characterName) - - XCTAssertEqual(droidName.__typename, "Droid") - XCTAssertEqual(droidName.name, "R2-D2") - } - - // TODO: Either fix or document behavior - /* - func testConvertCharacterNameIntoDroidNameFragmentForHuman() throws { - let characterName = CharacterName.makeHuman(name: "Luke Skywalker") - - XCTAssertThrowsError(try DroidName(characterName)) { error in - } - } - */ -} diff --git a/Tests/ApolloTests/GETTransformerTests.swift b/Tests/ApolloTests/GETTransformerTests.swift deleted file mode 100644 index 6dde099df4..0000000000 --- a/Tests/ApolloTests/GETTransformerTests.swift +++ /dev/null @@ -1,220 +0,0 @@ -// -// GETTransformerTests.swift -// ApolloTests -// -// Created by Ellen Shapiro on 7/1/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class GETTransformerTests: XCTestCase { - private var requestBodyCreator: ApolloRequestBodyCreator! - private static let url = TestURL.mockPort8080.url - - override func setUp() { - super.setUp() - - requestBodyCreator = ApolloRequestBodyCreator() - } - - override func tearDown() { - requestBodyCreator = nil - - super.tearDown() - } - - func testEncodingQueryWithSingleParameter() { - let operation = HeroNameQuery(episode: .empire) - let body = requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: false, - sendQueryDocument: true, - autoPersistQuery: false) - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - XCTAssertEqual(url?.absoluteString, "http://localhost:8080/graphql?operationName=HeroName&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:%22EMPIRE%22%7D") - } - - func testEncodingQueryWithMoreThanOneParameterIncludingNonHashableValue() throws { - let operation = HeroNameTypeSpecificConditionalInclusionQuery(episode: .jedi, includeName: true) - let body = requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: false, - sendQueryDocument: true, - autoPersistQuery: false) - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - // Here, we know that everything should be encoded in a stable order, - // and we can check the encoded URL string directly. - XCTAssertEqual(url?.absoluteString, "http://localhost:8080/graphql?operationName=HeroNameTypeSpecificConditionalInclusion&query=query%20HeroNameTypeSpecificConditionalInclusion($episode:%20Episode,%20$includeName:%20Boolean!)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%20@include(if:%20$includeName)%0A%20%20%20%20...%20on%20Droid%20%7B%0A%20%20%20%20%20%20__typename%0A%20%20%20%20%20%20name%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:%22JEDI%22,%22includeName%22:true%7D") - } - - func testEncodingQueryWith2DParameter() throws { - let operation = HeroNameQuery(episode: .empire) - - let persistedQuery: GraphQLMap = [ - "version": 1, - "sha256Hash": operation.operationIdentifier - ] - - let extensions: GraphQLMap = [ - "persistedQuery": persistedQuery - ] - - let body: GraphQLMap = [ - "query": operation.queryDocument, - "variables": operation.variables, - "extensions": extensions - ] - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - let queryString = url?.absoluteString == "http://localhost:8080/graphql?extensions=%7B%22persistedQuery%22:%7B%22sha256Hash%22:%22f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671%22,%22version%22:1%7D%7D&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:%22EMPIRE%22%7D" - - XCTAssertTrue(queryString) - } - - func testEncodingQueryWithParameterWithPlusSignEncoded() throws { - let operation = HeroNameQuery(episode: .empire) - - let extensions: GraphQLMap = [ - "testParam": "+Test+Test" - ] - - let body: GraphQLMap = [ - "query": operation.queryDocument, - "variables": operation.variables, - "extensions": extensions - ] - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - let expected = "http://localhost:8080/graphql?extensions=%7B%22testParam%22:%22%2BTest%2BTest%22%7D&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:%22EMPIRE%22%7D" - - XCTAssertEqual(url?.absoluteString, expected) - } - - func testEncodingQueryWithParameterWithAmpersandEncoded() throws { - let operation = HeroNameQuery(episode: .empire) - - let extensions: GraphQLMap = [ - "testParam": "Test&Test" - ] - - let body: GraphQLMap = [ - "query": operation.queryDocument, - "variables": operation.variables, - "extensions": extensions - ] - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - let expected = "http://localhost:8080/graphql?extensions=%7B%22testParam%22:%22Test%26Test%22%7D&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:%22EMPIRE%22%7D" - - XCTAssertEqual(url?.absoluteString, expected) - } - - func testEncodingQueryWith2DWOQueryParameter() throws { - let operation = HeroNameQuery(episode: .empire) - - let persistedQuery: GraphQLMap = [ - "version": 1, - "sha256Hash": operation.operationIdentifier - ] - - let extensions: GraphQLMap = [ - "persistedQuery": persistedQuery - ] - - let body: GraphQLMap = [ - "variables": operation.variables, - "extensions": extensions - ] - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - let queryString = url?.absoluteString == "http://localhost:8080/graphql?extensions=%7B%22persistedQuery%22:%7B%22sha256Hash%22:%22f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671%22,%22version%22:1%7D%7D&variables=%7B%22episode%22:%22EMPIRE%22%7D" - XCTAssertTrue(queryString) - } - - func testEncodingQueryWithNullDefaultParameter() { - let operation = HeroNameQuery() - let body = requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: false, - sendQueryDocument: true, - autoPersistQuery: false) - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - XCTAssertEqual(url?.absoluteString, "http://localhost:8080/graphql?operationName=HeroName&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:null%7D") - } - - func testEncodingQueryWith2DNullDefaultParameter() throws { - let operation = HeroNameQuery() - - let persistedQuery: GraphQLMap = [ - "version": 1, - "sha256Hash": operation.operationIdentifier - ] - - let extensions: GraphQLMap = [ - "persistedQuery": persistedQuery - ] - - let body: GraphQLMap = [ - "query": operation.queryDocument, - "variables": operation.variables, - "extensions": extensions - ] - - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - - let url = transformer.createGetURL() - - let queryString = url?.absoluteString == "http://localhost:8080/graphql?extensions=%7B%22persistedQuery%22:%7B%22sha256Hash%22:%22f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671%22,%22version%22:1%7D%7D&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:null%7D" - XCTAssertTrue(queryString) - } - - func testEncodingQueryWithExistingParameters() throws { - let operation = HeroNameQuery(episode: .empire) - let body = requestBodyCreator.requestBody(for: operation, - sendOperationIdentifiers: false, - sendQueryDocument: true, - autoPersistQuery: false) - - var components = URLComponents(string: Self.url.absoluteString)! - components.queryItems = [URLQueryItem(name: "foo", value: "bar")] - - let transformer = GraphQLGETTransformer(body: body, url: components.url!) - - let url = transformer.createGetURL() - - XCTAssertEqual(url?.absoluteString, "http://localhost:8080/graphql?foo=bar&operationName=HeroName&query=query%20HeroName($episode:%20Episode)%20%7B%0A%20%20hero(episode:%20$episode)%20%7B%0A%20%20%20%20__typename%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22episode%22:%22EMPIRE%22%7D") - } - - func testEncodingWithEmptyQueryParameter() throws { - let body: GraphQLMap = ["variables": nil] - let transformer = GraphQLGETTransformer(body: body, url: Self.url) - let url = transformer.createGetURL() - - XCTAssertEqual(url?.absoluteString, "http://localhost:8080/graphql") - } -} diff --git a/Tests/ApolloTests/GraphQLFileTests.swift b/Tests/ApolloTests/GraphQLFileTests.swift deleted file mode 100644 index eba49c8d5c..0000000000 --- a/Tests/ApolloTests/GraphQLFileTests.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// GraphQLFileTests.swift -// ApolloTests -// -// Created by Ellen Shapiro on 3/18/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import XCTest - -@testable import Apollo -import ApolloTestSupport - -class GraphQLFileTests: XCTestCase { - - func testCreatingFileWithKnownBadURLFails() { - let url = URL(fileURLWithPath: "/known/bad/path") - do { - _ = try GraphQLFile(fieldName: "test", - originalName: "test", - fileURL: url) - } catch { - switch error { - case GraphQLFile.GraphQLFileError.couldNotGetFileSize(let fileURL): - XCTAssertEqual(fileURL, url) - default: - XCTFail("Unexpected error creating file: \(error)") - } - } - } - - func testCreatingFileWithKnownGoodURLSucceedsAndCreatesAndCanRecreateInputStream() throws { - let knownFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let file = try GraphQLFile(fieldName: "test", - originalName: "test", - fileURL: knownFileURL) - - let inputStream = try file.generateInputStream() - - inputStream.open() - XCTAssertTrue(inputStream.hasBytesAvailable) - inputStream.close() - - let inputStream2 = try file.generateInputStream() - - inputStream2.open() - XCTAssertTrue(inputStream2.hasBytesAvailable) - inputStream2.close() - } - - func testCreatingFileWithEmptyDataSucceedsAndCreatesInputStream() throws { - let data = Data() - XCTAssertTrue(data.isEmpty) - - let file = GraphQLFile(fieldName: "test", - originalName: "test", - data: data) - - let inputStream = try file.generateInputStream() - - // Shouldn't have any bytes available if data is empty - inputStream.open() - XCTAssertFalse(inputStream.hasBytesAvailable) - inputStream.close() - } - - func testCreatingFileWithNonEmptyDataSucceedsAndCreatesAndCanRecreateInputStream() throws { - let data = try XCTUnwrap("A test string".data(using: .utf8)) - XCTAssertFalse(data.isEmpty) - - let file = GraphQLFile(fieldName: "test", - originalName: "test", - data: data) - - let inputStream = try file.generateInputStream() - inputStream.open() - XCTAssertTrue(inputStream.hasBytesAvailable) - inputStream.close() - - let inputStream2 = try file.generateInputStream() - - inputStream2.open() - XCTAssertTrue(inputStream2.hasBytesAvailable) - inputStream2.close() - } -} diff --git a/Tests/ApolloTests/GraphQLMapEncodingTests.swift b/Tests/ApolloTests/GraphQLMapEncodingTests.swift deleted file mode 100644 index ea35613330..0000000000 --- a/Tests/ApolloTests/GraphQLMapEncodingTests.swift +++ /dev/null @@ -1,96 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class GraphQLMapEncodingTests: XCTestCase { - private struct MockGraphQLMapConvertible: GraphQLMapConvertible { - let graphQLMap: GraphQLMap - } - - private func serializeAndDeserialize(_ map: GraphQLMap) -> NSDictionary { - let input = MockGraphQLMapConvertible(graphQLMap: map) - let data = try! JSONSerializationFormat.serialize(value: input.jsonValue as! [String: JSONEncodable?]) - return try! JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary - } - - func testEncodeValue() { - let map: GraphQLMap = ["name": "Luke Skywalker"] - XCTAssertEqual(serializeAndDeserialize(map), ["name": "Luke Skywalker"]) - } - - func testEncodeOptionalValue() { - let map: GraphQLMap = ["name": "Luke Skywalker" as Optional] - XCTAssertEqual(serializeAndDeserialize(map), ["name": "Luke Skywalker"]) - } - - func testEncodeOptionalValueWithValueMissing() { - let map: GraphQLMap = ["name": Optional.none] - XCTAssertEqual(serializeAndDeserialize(map), [:]) - } - - func testEncodeOptionalValueWithExplicitNull() { - let map: GraphQLMap = ["name": Optional.some(.none)] - XCTAssertEqual(serializeAndDeserialize(map), ["name": NSNull()]) - } - - func testEncodeEnumValue() { - let map: GraphQLMap = ["favoriteEpisode": Episode.jedi] - XCTAssertEqual(serializeAndDeserialize(map), ["favoriteEpisode": "JEDI"]) - } - - func testEncodeMap() { - let map: GraphQLMap = ["hero": ["name": "Luke Skywalker"]] - XCTAssertEqual(serializeAndDeserialize(map), ["hero": ["name": "Luke Skywalker"]]) - } - - func testEncodeOptionalMapWithValueMissing() { - let map: GraphQLMap = ["hero": Optional.none] - XCTAssertEqual(serializeAndDeserialize(map), [:]) - } - - func testEncodeList() { - let map: GraphQLMap = ["appearsIn": [.jedi, .empire] as [Episode]] - XCTAssertEqual(serializeAndDeserialize(map), ["appearsIn": ["JEDI", "EMPIRE"]]) - } - - func testEncodeOptionalList() { - let map: GraphQLMap = ["appearsIn": [.jedi, .empire] as Optional<[Episode]?>] - XCTAssertEqual(serializeAndDeserialize(map), ["appearsIn": ["JEDI", "EMPIRE"]]) - } - - func testEncodeOptionalListWithValueMissing() { - let map: GraphQLMap = ["appearsIn": Optional<[Episode]?>.none] - XCTAssertEqual(serializeAndDeserialize(map), [:]) - } - - func testEncodeInputObject() { - let review = ReviewInput(stars: 5, commentary: "This is a great movie!") - let map: GraphQLMap = ["review": review] - XCTAssertEqual(serializeAndDeserialize(map), ["review": ["stars": 5, "commentary": "This is a great movie!"]]) - } - - func testEncodeInputObjectWithOptionalPropertyMissing() { - let review = ReviewInput(stars: 5) - let map: GraphQLMap = ["review": review] - XCTAssertEqual(serializeAndDeserialize(map), ["review": ["stars": 5]]) - } - - func testEncodeInputObjectWithExplicitNilForOptionalProperty() { - let review = ReviewInput(stars: 5, commentary: nil) - let map: GraphQLMap = ["review": review] - XCTAssertEqual(serializeAndDeserialize(map), ["review": ["stars": 5]]) - } - - func testEncodeInputObjectWithExplicitSomeNilForOptionalProperty() { - let review = ReviewInput(stars: 5, commentary: .some(nil)) - let map: GraphQLMap = ["review": review] - XCTAssertEqual(serializeAndDeserialize(map), ["review": ["stars": 5, "commentary": NSNull()]]) - } - - func testEncodeInputObjectWithNestedInputObject() { - let review = ReviewInput(stars: 5, favoriteColor: ColorInput(red: 0, green: 0, blue: 0)) - let map: GraphQLMap = ["review": review] - XCTAssertEqual(serializeAndDeserialize(map), ["review": ["stars": 5, "favorite_color": ["red": 0, "blue": 0, "green": 0]]]) - } -} diff --git a/Tests/ApolloTests/Info.plist b/Tests/ApolloTests/Info.plist deleted file mode 100644 index 2cafdf8edb..0000000000 --- a/Tests/ApolloTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - $(CURRENT_PROJECT_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/Tests/ApolloTests/InterceptorTests.swift b/Tests/ApolloTests/InterceptorTests.swift deleted file mode 100644 index 041dee362b..0000000000 --- a/Tests/ApolloTests/InterceptorTests.swift +++ /dev/null @@ -1,281 +0,0 @@ -// -// InterceptorTests.swift -// Apollo -// -// Created by Ellen Shapiro on 8/19/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import XCTest -import Apollo -import ApolloTestSupport -import StarWarsAPI - -class InterceptorTests: XCTestCase { - - // MARK: - Retry Interceptor - - func testMaxRetryInterceptorErrorsAfterMaximumRetries() { - class TestProvider: InterceptorProvider { - let testInterceptor = BlindRetryingTestInterceptor() - let retryCount = 15 - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [ - MaxRetryInterceptor(maxRetriesAllowed: self.retryCount), - self.testInterceptor, - NetworkFetchInterceptor(client: MockURLSessionClient()), - ] - } - } - - let testProvider = TestProvider() - let network = RequestChainNetworkTransport(interceptorProvider: testProvider, - endpointURL: TestURL.mockServer.url) - - let expectation = self.expectation(description: "Request sent") - - let operation = HeroNameQuery() - _ = network.send(operation: operation) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success: - XCTFail("This should not have worked") - case .failure(let error): - switch error { - case MaxRetryInterceptor.RetryError.hitMaxRetryCount(let count, let operationName): - XCTAssertEqual(count, testProvider.retryCount) - // There should be one more hit than retries since it will be hit on the original call - XCTAssertEqual(testProvider.testInterceptor.hitCount, testProvider.retryCount + 1) - XCTAssertEqual(operationName, operation.operationName) - default: - XCTFail("Unexpected error type: \(error)") - } - } - } - - self.wait(for: [expectation], timeout: 1) - } - - func testRetryInterceptorDoesNotErrorIfRetriedFewerThanMaxTimes() { - class TestProvider: InterceptorProvider { - let testInterceptor = RetryToCountThenSucceedInterceptor(timesToCallRetry: 2) - let retryCount = 3 - - let mockClient: MockURLSessionClient = { - let client = MockURLSessionClient() - client.response = HTTPURLResponse(url: TestURL.mockServer.url, - statusCode: 200, - httpVersion: nil, - headerFields: nil) - let json = [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - let data = try! JSONSerializationFormat.serialize(value: json) - client.data = data - return client - }() - - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [ - MaxRetryInterceptor(maxRetriesAllowed: self.retryCount), - self.testInterceptor, - NetworkFetchInterceptor(client: self.mockClient), - JSONResponseParsingInterceptor(), - ] - } - } - - let testProvider = TestProvider() - let network = RequestChainNetworkTransport(interceptorProvider: testProvider, - endpointURL: TestURL.mockServer.url) - - let expectation = self.expectation(description: "Request sent") - - let operation = HeroNameQuery() - _ = network.send(operation: operation) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.hero?.name, "Luke Skywalker") - XCTAssertEqual(testProvider.testInterceptor.timesRetryHasBeenCalled, testProvider.testInterceptor.timesToCallRetry) - case .failure(let error): - XCTFail("Unexpected error: \(error.localizedDescription)") - } - } - - self.wait(for: [expectation], timeout: 1) - } - - // MARK: - JSON Response Parsing Interceptor - - func testJSONResponseParsingInterceptorFailsWithEmptyData() { - class TestProvider: InterceptorProvider { - let mockClient: MockURLSessionClient = { - let client = MockURLSessionClient() - client.response = HTTPURLResponse(url: TestURL.mockServer.url, - statusCode: 200, - httpVersion: nil, - headerFields: nil) - client.data = Data() - return client - }() - - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [ - NetworkFetchInterceptor(client: self.mockClient), - JSONResponseParsingInterceptor(), - ] - } - } - - let network = RequestChainNetworkTransport(interceptorProvider: TestProvider(), - endpointURL: TestURL.mockServer.url) - - let expectation = self.expectation(description: "Request sent") - - _ = network.send(operation: HeroNameQuery()) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success: - XCTFail("This should not have succeeded") - case .failure(let error): - switch error { - case JSONResponseParsingInterceptor.JSONResponseParsingError.couldNotParseToJSON(let data): - XCTAssertTrue(data.isEmpty) - default: - XCTFail("Unexpected error type: \(error.localizedDescription)") - } - } - } - - self.wait(for: [expectation], timeout: 1) - } - - // MARK: - Response Code Interceptor - - func testResponseCodeInterceptorLetsAnyDataThroughWithValidResponseCode() { - class TestProvider: InterceptorProvider { - let mockClient: MockURLSessionClient = { - let client = MockURLSessionClient() - client.response = HTTPURLResponse(url: TestURL.mockServer.url, - statusCode: 200, - httpVersion: nil, - headerFields: nil) - client.data = Data() - return client - }() - - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [ - NetworkFetchInterceptor(client: self.mockClient), - ResponseCodeInterceptor(), - JSONResponseParsingInterceptor() - ] - } - } - - let network = RequestChainNetworkTransport(interceptorProvider: TestProvider(), - endpointURL: TestURL.mockServer.url) - - let expectation = self.expectation(description: "Request sent") - - _ = network.send(operation: HeroNameQuery()) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success: - XCTFail("This should not have succeeded") - case .failure(let error): - switch error { - case JSONResponseParsingInterceptor.JSONResponseParsingError.couldNotParseToJSON(let data): - XCTAssertTrue(data.isEmpty) - default: - XCTFail("Unexpected error type: \(error.localizedDescription)") - } - } - } - - self.wait(for: [expectation], timeout: 1) - } - - func testResponseCodeInterceptorDoesNotLetDataThroughWithInvalidResponseCode() { - class TestProvider: InterceptorProvider { - let mockClient: MockURLSessionClient = { - let client = MockURLSessionClient() - client.response = HTTPURLResponse(url: TestURL.mockServer.url, - statusCode: 401, - httpVersion: nil, - headerFields: nil) - let json = [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human" - ] - ] - ] - let data = try! JSONSerializationFormat.serialize(value: json) - client.data = data - return client - }() - - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [ - NetworkFetchInterceptor(client: self.mockClient), - ResponseCodeInterceptor(), - JSONResponseParsingInterceptor(), - ] - } - } - - let network = RequestChainNetworkTransport(interceptorProvider: TestProvider(), - endpointURL: TestURL.mockServer.url) - - let expectation = self.expectation(description: "Request sent") - - _ = network.send(operation: HeroNameQuery()) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success: - XCTFail("This should not have succeeded") - case .failure(let error): - switch error { - case ResponseCodeInterceptor.ResponseCodeError.invalidResponseCode(response: let response, let rawData): - XCTAssertEqual(response?.statusCode, 401) - - guard - let data = rawData, - let dataString = String(bytes: data, encoding: .utf8) else { - XCTFail("Incorrect data returned with error") - return - } - - XCTAssertEqual(dataString, "{\"data\":{\"hero\":{\"__typename\":\"Human\",\"name\":\"Luke Skywalker\"}}}") - default: - XCTFail("Unexpected error type: \(error.localizedDescription)") - } - } - } - - self.wait(for: [expectation], timeout: 1) - } -} diff --git a/Tests/ApolloTests/JSONTests.swift b/Tests/ApolloTests/JSONTests.swift deleted file mode 100644 index a0b52114fc..0000000000 --- a/Tests/ApolloTests/JSONTests.swift +++ /dev/null @@ -1,101 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport - -class JSONTests: XCTestCase { - func testMissingValueMatchable() { - let value = JSONDecodingError.missingValue - - XCTAssertTrue(value ~= JSONDecodingError.missingValue) - XCTAssertFalse(value ~= JSONDecodingError.nullValue) - XCTAssertFalse(value ~= JSONDecodingError.wrongType) - XCTAssertFalse(value ~= JSONDecodingError.couldNotConvert(value: 123, to: Int.self)) - } - - func testNullValueMatchable() { - let value = JSONDecodingError.nullValue - - XCTAssertTrue(value ~= JSONDecodingError.nullValue) - XCTAssertFalse(value ~= JSONDecodingError.missingValue) - XCTAssertFalse(value ~= JSONDecodingError.wrongType) - XCTAssertFalse(value ~= JSONDecodingError.couldNotConvert(value: 123, to: Int.self)) - } - - func testWrongTypeMatchable() { - let value = JSONDecodingError.wrongType - - XCTAssertTrue(value ~= JSONDecodingError.wrongType) - XCTAssertFalse(value ~= JSONDecodingError.nullValue) - XCTAssertFalse(value ~= JSONDecodingError.missingValue) - XCTAssertFalse(value ~= JSONDecodingError.couldNotConvert(value: 123, to: Int.self)) - } - - func testCouldNotConvertMatchable() { - let value = JSONDecodingError.couldNotConvert(value: 123, to: Int.self) - - XCTAssertTrue(value ~= JSONDecodingError.couldNotConvert(value: 123, to: Int.self)) - XCTAssertTrue(value ~= JSONDecodingError.couldNotConvert(value: "abc", to: String.self)) - XCTAssertFalse(value ~= JSONDecodingError.wrongType) - XCTAssertFalse(value ~= JSONDecodingError.nullValue) - XCTAssertFalse(value ~= JSONDecodingError.missingValue) - } - - func testJSONDictionaryEncodingAndDecoding() throws { - let jsonString = """ -{ - "a_dict": { - "a_bool": true, - "another_dict" : { - "a_double": 23.1, - "an_int": 8, - "a_string": "LOL wat" - }, - "an_array": [ - "one", - "two", - "three" - ], - "a_null": null - } -} -""" - let data = try XCTUnwrap(jsonString.data(using: .utf8)) - let json = try JSONSerializationFormat.deserialize(data: data) - XCTAssertNotNil(json) - - let dict = try Dictionary(jsonValue: json) - XCTAssertNotNil(dict) - - let reserialized = try JSONSerializationFormat.serialize(value: dict) - XCTAssertNotNil(reserialized) - - let stringFromReserialized = try XCTUnwrap(String(bytes: reserialized, encoding: .utf8)) - XCTAssertEqual(stringFromReserialized, """ -{"a_dict":{"a_bool":true,"a_null":null,"an_array":["one","two","three"],"another_dict":{"a_double":23.100000000000001,"a_string":"LOL wat","an_int":8}}} -""") - } - - func testEncodingNSNullDoesNotCrash() throws { - let nsNull = ["aWeirdNull": NSNull()] - let serialized = try JSONSerializationFormat.serialize(value: nsNull) - let stringFromSerialized = try XCTUnwrap(String(data: serialized, encoding: .utf8)) - - XCTAssertEqual(stringFromSerialized, #"{"aWeirdNull":null}"#) - } - - func testEncodingOptionalNSNullDoesNotCrash() throws { - let optionalNSNull = ["aWeirdNull": Optional.some(NSNull())] - let serialized = try JSONSerializationFormat.serialize(value: optionalNSNull) - let stringFromSerialized = try XCTUnwrap(String(data: serialized, encoding: .utf8)) - - XCTAssertEqual(stringFromSerialized, #"{"aWeirdNull":null}"#) - } - - func testEncodingDoubleOptionalsDoesNotCrash() throws { - let doubleOptional = ["aWeirdNull": Optional.some(Optional.none)] - let serialized = try JSONSerializationFormat.serialize(value: doubleOptional) - let stringFromSerialized = try XCTUnwrap(String(data: serialized, encoding: .utf8)) - - XCTAssertEqual(stringFromSerialized, #"{"aWeirdNull":null}"#) - } -} diff --git a/Tests/ApolloTests/MultipartFormData+Testing.swift b/Tests/ApolloTests/MultipartFormData+Testing.swift deleted file mode 100644 index b49fde370b..0000000000 --- a/Tests/ApolloTests/MultipartFormData+Testing.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation -@testable import Apollo - -extension MultipartFormData { - - func toTestString() throws -> String { - let encodedData = try self.encode() - let string = String(bytes: encodedData, encoding: .utf8)! - - // Replacing CRLF with new line as string literals uses new lines - return string.replacingOccurrences(of: MultipartFormData.CRLF, with: "\n") - } -} - diff --git a/Tests/ApolloTests/MultipartFormDataTests.swift b/Tests/ApolloTests/MultipartFormDataTests.swift deleted file mode 100644 index 32ab2a2806..0000000000 --- a/Tests/ApolloTests/MultipartFormDataTests.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// MultipartFormDataTests.swift -// Apollo -// -// Created by Ellen Shapiro on 9/21/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import XCTest -import Apollo -import ApolloTestSupport - -class MultipartFormDataTests: XCTestCase { - func testSingleFile() throws { - let alphaFileUrl = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - let alphaData = try Data(contentsOf: alphaFileUrl) - - let formData = MultipartFormData(boundary: "------------------------cec8e8123c05ba25") - try formData.appendPart(string: "{ \"query\": \"mutation ($file: Upload!) { singleUpload(file: $file) { id } }\", \"variables\": { \"file\": null } }", name: "operations") - try formData.appendPart(string: "{ \"0\": [\"variables.file\"] }", name: "map") - formData.appendPart(data: alphaData, name: "0", contentType: "text/plain", filename: "a.txt") - - let expectedString = """ ---------------------------cec8e8123c05ba25 -Content-Disposition: form-data; name="operations" - -{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } } ---------------------------cec8e8123c05ba25 -Content-Disposition: form-data; name="map" - -{ "0": ["variables.file"] } ---------------------------cec8e8123c05ba25 -Content-Disposition: form-data; name="0"; filename="a.txt" -Content-Type: text/plain - -Alpha file content. - ---------------------------cec8e8123c05ba25-- -""" - - let stringToCompare = try formData.toTestString() - XCTAssertEqual(stringToCompare, expectedString) - } - - func testMultifileFile() throws { - let bravoFileUrl = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - let charlieFileUrl = TestFileHelper.fileURLForFile(named: "c", extension: "txt") - - let bravoData = try Data(contentsOf: bravoFileUrl) - let charlieData = try Data(contentsOf: charlieFileUrl) - - let formData = MultipartFormData(boundary: "------------------------ec62457de6331cad") - try formData.appendPart(string: "{ \"query\": \"mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }\", \"variables\": { \"files\": [null, null] } }", name: "operations") - try formData.appendPart(string: "{ \"0\": [\"variables.files.0\"], \"1\": [\"variables.files.1\"] }", name: "map") - formData.appendPart(data: bravoData, name: "0", contentType: "text/plain", filename: "b.txt") - formData.appendPart(data: charlieData, name: "1", contentType: "text/plain", filename: "c.txt") - - let expectedString = """ ---------------------------ec62457de6331cad -Content-Disposition: form-data; name="operations" - -{ "query": "mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }", "variables": { "files": [null, null] } } ---------------------------ec62457de6331cad -Content-Disposition: form-data; name="map" - -{ "0": ["variables.files.0"], "1": ["variables.files.1"] } ---------------------------ec62457de6331cad -Content-Disposition: form-data; name="0"; filename="b.txt" -Content-Type: text/plain - -Bravo file content. - ---------------------------ec62457de6331cad -Content-Disposition: form-data; name="1"; filename="c.txt" -Content-Type: text/plain - -Charlie file content. - ---------------------------ec62457de6331cad-- -""" - let stringToCompare = try formData.toTestString() - XCTAssertEqual(stringToCompare, expectedString) - } - - func testBatchFile() throws { - let alphaFileUrl = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - let bravoFileUrl = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - let charlieFileUrl = TestFileHelper.fileURLForFile(named: "c", extension: "txt") - - let alphaData = try Data(contentsOf: alphaFileUrl) - let bravoData = try Data(contentsOf: bravoFileUrl) - let charlieData = try Data(contentsOf: charlieFileUrl) - - let formData = MultipartFormData(boundary: "------------------------627436eaefdbc285") - try formData.appendPart(string: "[{ \"query\": \"mutation ($file: Upload!) { singleUpload(file: $file) { id } }\", \"variables\": { \"file\": null } }, { \"query\": \"mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }\", \"variables\": { \"files\": [null, null] } }]", name: "operations") - try formData.appendPart(string: "{ \"0\": [\"0.variables.file\"], \"1\": [\"1.variables.files.0\"], \"2\": [\"1.variables.files.1\"] }", name: "map") - formData.appendPart(data: alphaData, name: "0", contentType: "text/plain", filename: "a.txt") - formData.appendPart(data: bravoData, name: "1", contentType: "text/plain", filename: "b.txt") - formData.appendPart(data: charlieData, name: "2", contentType: "text/plain", filename: "c.txt") - - let expectedString = """ ---------------------------627436eaefdbc285 -Content-Disposition: form-data; name="operations" - -[{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { id } }", "variables": { "file": null } }, { "query": "mutation($files: [Upload!]!) { multipleUpload(files: $files) { id } }", "variables": { "files": [null, null] } }] ---------------------------627436eaefdbc285 -Content-Disposition: form-data; name="map" - -{ "0": ["0.variables.file"], "1": ["1.variables.files.0"], "2": ["1.variables.files.1"] } ---------------------------627436eaefdbc285 -Content-Disposition: form-data; name="0"; filename="a.txt" -Content-Type: text/plain - -Alpha file content. - ---------------------------627436eaefdbc285 -Content-Disposition: form-data; name="1"; filename="b.txt" -Content-Type: text/plain - -Bravo file content. - ---------------------------627436eaefdbc285 -Content-Disposition: form-data; name="2"; filename="c.txt" -Content-Type: text/plain - -Charlie file content. - ---------------------------627436eaefdbc285-- -""" - - let stringToCompare = try formData.toTestString() - XCTAssertEqual(stringToCompare, expectedString) - } -} diff --git a/Tests/ApolloTests/MutatingResultsTests.swift b/Tests/ApolloTests/MutatingResultsTests.swift deleted file mode 100644 index 7271e0ceb1..0000000000 --- a/Tests/ApolloTests/MutatingResultsTests.swift +++ /dev/null @@ -1,18 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class MutatingResultsTests: XCTestCase { - func testSettingNewFragment() throws { - var hero = HeroNameWithFragmentAndIdQuery.Data.Hero.makeDroid(id: "2001", name: "R2-D2") - - let r2d2 = CharacterName.makeDroid(name: "Artoo") - - hero.fragments.characterName = r2d2 - - XCTAssertEqual(hero.__typename, "Droid") - XCTAssertEqual(hero.id, "2001") - XCTAssertEqual(hero.name, "Artoo") - } -} diff --git a/Tests/ApolloTests/NormalizeQueryResults.swift b/Tests/ApolloTests/NormalizeQueryResults.swift deleted file mode 100644 index 5ec07ca9ea..0000000000 --- a/Tests/ApolloTests/NormalizeQueryResults.swift +++ /dev/null @@ -1,236 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class NormalizeQueryResults: XCTestCase { - func testHeroNameQuery() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": "R2-D2"] - ] - ]) - - let (_, records) = try response.parseResult() - - XCTAssertEqual(records?["QUERY_ROOT"]?["hero"] as? CacheReference, CacheReference(key: "QUERY_ROOT.hero")) - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero"]) - XCTAssertEqual(hero["name"] as? String, "R2-D2") - } - - func testHeroNameQueryWithVariable() throws { - let query = HeroNameQuery(episode: .jedi) - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": "R2-D2"] - ] - ]) - - let (_, records) = try response.parseResult() - - XCTAssertEqual(records?["QUERY_ROOT"]?["hero(episode:JEDI)"] as? CacheReference, CacheReference(key: "QUERY_ROOT.hero(episode:JEDI)")) - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero(episode:JEDI)"]) - XCTAssertEqual(hero["name"] as? String, "R2-D2") - } - - func testHeroAppearsInQuery() throws { - let query = HeroAppearsInQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - ] - ]) - - let (_, records) = try response.parseResult() - - XCTAssertEqual(records?["QUERY_ROOT"]?["hero"] as? CacheReference, CacheReference(key: "QUERY_ROOT.hero")) - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero"]) - XCTAssertEqual(hero["appearsIn"] as? [String], ["NEWHOPE", "EMPIRE", "JEDI"]) - } - - func testHeroAndFriendsNamesQueryWithoutIDs() throws { - let query = HeroAndFriendsNamesQuery(episode: .jedi) - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "__typename": "Droid", - "name": "R2-D2", - "friends": [ - ["__typename": "Human", "name": "Luke Skywalker"], - ["__typename": "Human", "name": "Han Solo"], - ["__typename": "Human", "name": "Leia Organa"] - ] - ] - ] - ]) - - let (_, records) = try response.parseResult() - - XCTAssertEqual(records?["QUERY_ROOT"]?["hero(episode:JEDI)"] as? CacheReference, CacheReference(key: "QUERY_ROOT.hero(episode:JEDI)")) - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero(episode:JEDI)"]) - XCTAssertEqual(hero["name"] as? String, "R2-D2") - XCTAssertEqual(hero["friends"] as? [CacheReference], [CacheReference(key: "QUERY_ROOT.hero(episode:JEDI).friends.0"), CacheReference(key: "QUERY_ROOT.hero(episode:JEDI).friends.1"), CacheReference(key: "QUERY_ROOT.hero(episode:JEDI).friends.2")]) - - let luke = try XCTUnwrap(records?["QUERY_ROOT.hero(episode:JEDI).friends.0"]) - XCTAssertEqual(luke["name"] as? String, "Luke Skywalker") - } - - func testHeroAndFriendsNamesQueryWithIDs() throws { - let query = HeroAndFriendsNamesWithIDsQuery(episode: .jedi) - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "__typename": "Droid", - "id": "2001", - "name": "R2-D2", - "friends": [ - ["__typename": "Human", "id": "1000", "name": "Luke Skywalker"], - ["__typename": "Human", "id": "1002", "name": "Han Solo"], - ["__typename": "Human", "id": "1003", "name": "Leia Organa"] - ] - ] - ] - ]) - - let (_, records) = try response.parseResult(cacheKeyForObject: { $0["id"] }) - - XCTAssertEqual(records?["QUERY_ROOT"]?["hero(episode:JEDI)"] as? CacheReference, CacheReference(key: "2001")) - - let hero = try XCTUnwrap(records?["2001"]) - XCTAssertEqual(hero["name"] as? String, "R2-D2") - XCTAssertEqual(hero["friends"] as? [CacheReference], [CacheReference(key: "1000"), CacheReference(key: "1002"), CacheReference(key: "1003")]) - - let luke = try XCTUnwrap(records?["1000"]) - XCTAssertEqual(luke["name"] as? String, "Luke Skywalker") - } - - func testHeroAndFriendsNamesQueryWithIDForParentOnly() throws { - let query = HeroAndFriendsNamesWithIdForParentOnlyQuery(episode: .jedi) - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "__typename": "Droid", - "id": "2001", - "name": "R2-D2", - "friends": [ - ["__typename": "Human", "name": "Luke Skywalker"], - ["__typename": "Human", "name": "Han Solo"], - ["__typename": "Human", "name": "Leia Organa"] - ] - ] - ] - ]) - - let (_, records) = try response.parseResult(cacheKeyForObject: { $0["id"] }) - - XCTAssertEqual(records?["QUERY_ROOT"]?["hero(episode:JEDI)"] as? CacheReference, CacheReference(key: "2001")) - - let hero = try XCTUnwrap(records?["2001"]) - XCTAssertEqual(hero["name"] as? String, "R2-D2") - XCTAssertEqual(hero["friends"] as? [CacheReference], [CacheReference(key: "2001.friends.0"), CacheReference(key: "2001.friends.1"), CacheReference(key: "2001.friends.2")]) - - let luke = try XCTUnwrap(records?["2001.friends.0"]) - XCTAssertEqual(luke["name"] as? String, "Luke Skywalker") - } - - func testSameHeroTwiceQuery() throws { - let query = SameHeroTwiceQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": "R2-D2"], - "r2": ["__typename": "Droid", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - ] - ]) - - let (_, records) = try response.parseResult() - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero"]) - XCTAssertEqual(hero["__typename"] as? String, "Droid") - XCTAssertEqual(hero["name"] as? String, "R2-D2") - XCTAssertEqual(hero["appearsIn"] as? [String], ["NEWHOPE", "EMPIRE", "JEDI"]) - } - - func testHeroTypeDependentAliasedFieldQueryDroid() throws { - let query = HeroTypeDependentAliasedFieldQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "property": "Astromech"] - ] - ]) - - let (_, records) = try response.parseResult() - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero"]) - XCTAssertEqual(hero["primaryFunction"] as? String, "Astromech") - } - - func testHeroTypeDependentAliasedFieldQueryHuman() throws { - let query = HeroTypeDependentAliasedFieldQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Human", "property": "Tatooine"] - ] - ]) - - let (_, records) = try response.parseResult() - - let hero = try XCTUnwrap(records?["QUERY_ROOT.hero"]) - XCTAssertEqual(hero["homePlanet"] as? String, "Tatooine") - } - - func testHeroParentTypeDependentFieldDroid() throws { - let query = HeroParentTypeDependentFieldQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - ["__typename": "Human", "name": "Luke Skywalker", "height": 1.72], - ] - ] - ] - ]) - - let (_, records) = try response.parseResult() - - let luke = try XCTUnwrap(records?["QUERY_ROOT.hero.friends.0"]) - XCTAssertEqual(luke["height(unit:METER)"] as? Double, 1.72) - } - - func testHeroParentTypeDependentFieldHuman() throws { - let query = HeroParentTypeDependentFieldQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "name": "Luke Skywalker", - "__typename": "Human", - "friends": [ - ["__typename": "Human", "name": "Han Solo", "height": 5.905512], - ] - ] - ] - ]) - - let (_, records) = try response.parseResult() - - let han = try XCTUnwrap(records?["QUERY_ROOT.hero.friends.0"]) - XCTAssertEqual(han["height(unit:FOOT)"] as? Double, 5.905512) - } -} diff --git a/Tests/ApolloTests/OperationMessageMatchers.swift b/Tests/ApolloTests/OperationMessageMatchers.swift deleted file mode 100644 index 43b1898ed7..0000000000 --- a/Tests/ApolloTests/OperationMessageMatchers.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation -import Nimble -import Apollo -@testable import ApolloWebSocket - -public func equalMessage(payload: GraphQLMap? = nil, id: String? = nil, type: OperationMessage.Types) -> Predicate { - return Predicate.define { actualExpression in - guard let actualValue = try actualExpression.evaluate() else { - return PredicateResult( - status: .fail, - message: .fail("Message cannot be nil - type is a required parameter.") - ) - } - - let expected = OperationMessage(payload: payload, id: id, type: type) - guard actualValue == expected.rawMessage! else { - return PredicateResult( - status: .fail, - message: .expectedActualValueTo("equal \(expected)")) - } - - return PredicateResult( - status: .matches, - message: .expectedTo("be equal") - ) - } -} diff --git a/Tests/ApolloTests/ParseQueryResponseTests.swift b/Tests/ApolloTests/ParseQueryResponseTests.swift deleted file mode 100644 index d5d4e494ba..0000000000 --- a/Tests/ApolloTests/ParseQueryResponseTests.swift +++ /dev/null @@ -1,452 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class ParseQueryResponseTests: XCTestCase { - func testHeroNameQuery() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": "R2-D2"] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.name, "R2-D2") - } - - func testHeroNameQueryWithMissingValue() { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid"] - ] - ]) - - XCTAssertThrowsError(try response.parseResult()) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["hero", "name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testHeroNameQueryWithDifferentType() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": 10] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.name, "10") - } - - func testHeroNameQueryWithWrongType() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": 10.0] - ] - ]) - - XCTAssertThrowsError(try response.parseResult()) { error in - if let error = error as? GraphQLResultError, case JSONDecodingError.couldNotConvert(let value, let expectedType) = error.underlying { - XCTAssertEqual(error.path, ["hero", "name"]) - XCTAssertEqual(value as? Double, 10.0) - XCTAssertTrue(expectedType == String.self) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testHeroAppearsInQuery() throws { - let query = HeroAppearsInQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.appearsIn, [.newhope, .empire, .jedi]) - } - - func testHeroAppearsInQueryWithEmptyList() throws { - let query = HeroAppearsInQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "appearsIn": []] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.appearsIn, []) - } - - func testHeroAndFriendsNamesQuery() throws { - let query = HeroAndFriendsNamesQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - ["__typename": "Human", "name": "Luke Skywalker"], - ["__typename": "Human", "name": "Han Solo"], - ["__typename": "Human", "name": "Leia Organa"] - ] - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.name, "R2-D2") - let friendsNames = result.data?.hero?.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - - func testHeroAndFriendsNamesQueryWithEmptyList() throws { - let query = HeroAndFriendsNamesQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [] - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.name, "R2-D2") - XCTAssertEqual(result.data?.hero?.friends?.isEmpty, true) - } - - func testHeroAndFriendsNamesWithFragmentQuery() throws { - let query = HeroAndFriendsNamesWithFragmentQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": [ - "name": "R2-D2", - "__typename": "Droid", - "friends": [ - ["__typename": "Human", "name": "Luke Skywalker"], - ["__typename": "Human", "name": "Han Solo"], - ["__typename": "Human", "name": "Leia Organa"] - ] - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.name, "R2-D2") - let friendsNames = result.data?.hero?.fragments.friendsNames.friends?.compactMap { $0?.name } - XCTAssertEqual(friendsNames, ["Luke Skywalker", "Han Solo", "Leia Organa"]) - } - - func testTwoHeroesQuery() throws { - let query = TwoHeroesQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "r2": ["__typename": "Droid", "name": "R2-D2"], - "luke": ["__typename": "Human", "name": "Luke Skywalker"] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.r2?.name, "R2-D2") - XCTAssertEqual(result.data?.luke?.name, "Luke Skywalker") - } - - func testHeroDetailsQueryDroid() throws { - let query = HeroDetailsQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": "R2-D2", "primaryFunction": "Astromech"] - ] - ]) - - let (result, _) = try response.parseResult() - - let droid = try XCTUnwrap(result.data?.hero?.asDroid, - "Wrong type") - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - - func testHeroDetailsQueryHuman() throws { - let query = HeroDetailsQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Human", "name": "Luke Skywalker", "height": 1.72] - ] - ]) - - let (result, _) = try response.parseResult() - - let human = try XCTUnwrap(result.data?.hero?.asHuman, - "Wrong type") - - XCTAssertEqual(human.height, 1.72) - } - - func testHeroDetailsQueryUnknownTypename() throws { - let query = HeroDetailsQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Pokemon", "name": "Charmander"] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.hero?.name, "Charmander") - } - - func testHeroDetailsQueryMissingTypename() throws { - let query = HeroDetailsQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["name": "Luke Skywalker", "height": 1.72] - ] - ]) - - XCTAssertThrowsError(try response.parseResult()) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["hero", "__typename"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testHeroDetailsWithFragmentQueryDroid() throws { - let query = HeroDetailsWithFragmentQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Droid", "name": "R2-D2", "primaryFunction": "Astromech"] - ] - ]) - - let (result, _) = try response.parseResult() - - let droid = try XCTUnwrap(result.data?.hero?.fragments.heroDetails.asDroid, - "Wrong type") - - XCTAssertEqual(droid.primaryFunction, "Astromech") - } - - func testHeroDetailsWithFragmentQueryHuman() throws { - let query = HeroDetailsWithFragmentQuery() - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "hero": ["__typename": "Human", "name": "Luke Skywalker", "height": 1.72] - ] - ]) - - let (result, _) = try response.parseResult() - - let human = try XCTUnwrap(result.data?.hero?.fragments.heroDetails.asHuman, - "Wrong type") - - XCTAssertEqual(human.height, 1.72) - } - - func testHumanQueryWithNullResult() throws { - let query = HumanQuery(id: "9999") - - let response = GraphQLResponse(operation: query, body: [ - "data": [ - "human": NSNull() - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNil(result.data?.human) - } - - func testHumanQueryWithMissingResult() throws { - let query = HumanQuery(id: "9999") - - let response = GraphQLResponse(operation: query, body: [ - "data": [:] - ]) - - XCTAssertThrowsError(try response.parseResult()) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["human"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testExtensionsEntryNotNullWhenProvidedInResponseAccompanyingDataEntry() throws { - let query = HumanQuery(id: "9999") - - let response = GraphQLResponse(operation: query, body: [ - "data": ["human": NSNull()], - "extensions": [:] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNotNil(result.extensions) - } - - func testExtensionsValuesWhenPopulatedInResponse() throws { - let query = HumanQuery(id: "9999") - - let response = GraphQLResponse(operation: query, body: [ - "data": ["human": NSNull()], - "extensions": ["parentKey": ["childKey": "someValue"]] - ]) - - let (result, _) = try response.parseResult() - let extensionsDictionary = result.extensions - let childDictionary = extensionsDictionary?["parentKey"] as? JSONObject - - XCTAssertNotNil(extensionsDictionary) - XCTAssertNotNil(childDictionary) - XCTAssertEqual(childDictionary, ["childKey": "someValue"]) - } - - func testExtensionsEntryNullWhenNotProvidedInResponse() throws { - let query = HumanQuery(id: "9999") - - let response = GraphQLResponse(operation: query, body: [ - "data": ["human": NSNull()] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNil(result.extensions) - } - - func testExtensionsEntryNotNullWhenDataEntryNotProvidedInResponse() throws { - let query = HumanQuery(id: "9999") - - let response = GraphQLResponse(operation: query, body: [ - "extensions": [:] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNotNil(result.extensions) - } - - // MARK: Mutations - - func testCreateReviewForEpisode() throws { - let mutation = CreateReviewForEpisodeMutation(episode: .jedi, review: ReviewInput(stars: 5, commentary: "This is a great movie!")) - - let response = GraphQLResponse(operation: mutation, body: [ - "data": [ - "createReview": [ - "__typename": "Review", - "stars": 5, - "commentary": "This is a great movie!" - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertEqual(result.data?.createReview?.stars, 5) - XCTAssertEqual(result.data?.createReview?.commentary, "This is a great movie!") - } - - // MARK: - Error responses - - func testErrorResponseWithoutLocation() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "errors": [ - [ - "message": "Some error", - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNil(result.data) - XCTAssertEqual(result.errors?.first?.message, "Some error") - XCTAssertNil(result.errors?.first?.locations) - } - - func testErrorResponseWithLocation() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "errors": [ - [ - "message": "Some error", - "locations": [ - ["line": 1, "column": 2] - ] - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNil(result.data) - XCTAssertEqual(result.errors?.first?.message, "Some error") - XCTAssertEqual(result.errors?.first?.locations?.first?.line, 1) - XCTAssertEqual(result.errors?.first?.locations?.first?.column, 2) - } - - func testErrorResponseWithCustomError() throws { - let query = HeroNameQuery() - - let response = GraphQLResponse(operation: query, body: [ - "errors": [ - [ - "message": "Some error", - "userMessage": "Some message" - ] - ] - ]) - - let (result, _) = try response.parseResult() - - XCTAssertNil(result.data) - XCTAssertEqual(result.errors?.first?.message, "Some error") - XCTAssertEqual(result.errors?.first?["userMessage"] as? String, "Some message") - } -} diff --git a/Tests/ApolloTests/PossiblyDeferredTests.swift b/Tests/ApolloTests/PossiblyDeferredTests.swift deleted file mode 100644 index cd8cb40859..0000000000 --- a/Tests/ApolloTests/PossiblyDeferredTests.swift +++ /dev/null @@ -1,390 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport - -private struct TestError: Error {} -private struct OtherTestError: Error {} - -class PossiblyDeferredTests: XCTestCase { - func testImmediateSuccess() throws { - let possiblyDeferred = PossiblyDeferred.immediate(.success("foo")) - - XCTAssertEqual(try possiblyDeferred.get(), "foo") - } - - func testImmediateFailure() { - let possiblyDeferred = PossiblyDeferred.immediate(.failure(TestError())) - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - } - - func testDeferredSuccess() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { () -> String in - numberOfInvocations += 1 - return "foo" - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertEqual(try possiblyDeferred.get(), "foo") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testDeferredFailure() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { () -> String in - numberOfInvocations += 1 - throw TestError() - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 1) - } - - // MARK: - Map - - func testMapOverImmediateSuccessIsImmediate() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.immediate(.success("foo")) - .map { value -> String in - numberOfInvocations += 1 - return value + "bar" - } - - XCTAssertEqual(numberOfInvocations, 1) - XCTAssertEqual(try possiblyDeferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testMapOverDeferredSuccessIsDeferred() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { "foo" } - .map { value -> String in - numberOfInvocations += 1 - return value + "bar" - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertEqual(try possiblyDeferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testMapOverImmediateFailureIsNotInvoked() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.immediate(.failure(TestError())) - .map { value -> String in - numberOfInvocations += 1 - return value + "bar" - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } - - func testMapOverDeferredFailureIsNotInvoked() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .map { value -> String in - numberOfInvocations += 1 - return value + "bar" - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } - - func testMapPropagatesError() { - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .map { _ in "foo" } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - } - - func testErrorThrownFromMapIsPropagated() { - let possiblyDeferred = PossiblyDeferred.deferred { "foo" } - .map { _ in throw TestError() } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - } - - // MARK: - Flat map - - func testImmediateFlatMapOverImmediateSuccessIsImmediate() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.immediate(.success("foo")) - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .immediate(.success(value + "bar")) - } - - XCTAssertEqual(numberOfInvocations, 1) - XCTAssertEqual(try possiblyDeferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testImmediateFlatMapOverDeferredSuccessIsDeferred() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { "foo" } - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .immediate(.success(value + "bar")) - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertEqual(try possiblyDeferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testDeferredFlatMapOverImmediateSuccessIsDeferred() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.immediate(.success("foo")) - .flatMap { value -> PossiblyDeferred in - return .deferred { - numberOfInvocations += 1 - return value + "bar" - } - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertEqual(try possiblyDeferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testDeferredFlatMapOverDeferredSuccessIsDeferred() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { "foo" } - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .deferred { value + "bar" } - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertEqual(try possiblyDeferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testImmediateFlatMapOverImmediateFailureIsNotInvoked() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.immediate(.failure(TestError())) - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .immediate(.success(value + "bar")) - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } - - func testImmediateFlatMapOverDeferredFailureIsNotInvoked() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .immediate(.success(value + "bar")) - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } - - func testDeferredFlatMapOverImmediateFailureIsNotInvoked() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.immediate(.failure(TestError())) - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .immediate(.success(value + "bar")) - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } - - func testDeferredFlatMapOverDeferredFailureIsNotInvoked() { - var numberOfInvocations = 0 - - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .flatMap { value -> PossiblyDeferred in - numberOfInvocations += 1 - return .immediate(.success(value + "bar")) - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } - - func testFlatMapPropagatesError() { - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .flatMap { _ in .immediate(.success("foo")) } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - } - - func testErrorReturnedFromFlatMapIsPropagated() { - let possiblyDeferred = PossiblyDeferred.deferred { "foo" } - .flatMap { _ -> PossiblyDeferred in .immediate(.failure(TestError())) } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is TestError) - } - } - - // MARK: - Map error - - func testMapErrorOverImmediateFailure() { - let possiblyDeferred = PossiblyDeferred.immediate(.failure(TestError())) - .mapError { error in - XCTAssert(error is TestError) - return OtherTestError() - } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is OtherTestError) - } - } - - func testMapErrorOverDeferredFailure() { - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .mapError { error in - XCTAssert(error is TestError) - return OtherTestError() - } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is OtherTestError) - } - } - - func testMapErrorOverMapOverImmediateFailure() { - let possiblyDeferred = PossiblyDeferred.immediate(.failure(TestError())) - .map { _ in "foo" } - .mapError { error in - XCTAssert(error is TestError) - return OtherTestError() - } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is OtherTestError) - } - } - - func testMapErrorOverMapOverDeferredFailure() { - let possiblyDeferred = PossiblyDeferred.deferred { throw TestError() } - .map { _ in "foo" } - .mapError { error in - XCTAssert(error is TestError) - return OtherTestError() - } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is OtherTestError) - } - } - - func testMapErrorOverMapThrowingErrorOverImmediateSuccess() { - let possiblyDeferred = PossiblyDeferred.immediate(.success("foo")) - .map { value -> String in - throw TestError() - } - .mapError { error in - XCTAssert(error is TestError) - return OtherTestError() - } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is OtherTestError) - } - } - - func testMapErrorOverMapThrowingErrorOverDeferredSuccess() { - let possiblyDeferred = PossiblyDeferred.deferred { "foo" } - .map { value -> String in - throw TestError() - } - .mapError { error in - XCTAssert(error is TestError) - return OtherTestError() - } - - XCTAssertThrowsError(try possiblyDeferred.get()) { error in - XCTAssert(error is OtherTestError) - } - } - - // MARK: - Lazily evaluate all - - func testLazilyEvaluateAllIsDeferred() throws { - let possiblyDeferreds: [PossiblyDeferred] = [.deferred { "foo" }, .deferred { "bar" }] - - var numberOfInvocations = 0 - - let deferred = lazilyEvaluateAll(possiblyDeferreds).map { values -> String in - numberOfInvocations += 1 - XCTAssertEqual(values, ["foo", "bar"]) - return values.joined() - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertEqual(try deferred.get(), "foobar") - XCTAssertEqual(numberOfInvocations, 1) - } - - func testLazilyEvaluateAllFailsWhenAnyOfTheElementsFails() throws { - let possiblyDeferreds: [PossiblyDeferred] = [.deferred { "foo" }, .deferred { throw TestError() }] - - var numberOfInvocations = 0 - - let deferred = lazilyEvaluateAll(possiblyDeferreds).map { values -> String in - numberOfInvocations += 1 - XCTAssertEqual(values, ["foo", "bar"]) - return values.joined() - } - - XCTAssertEqual(numberOfInvocations, 0) - XCTAssertThrowsError(try deferred.get()) { error in - XCTAssert(error is TestError) - } - XCTAssertEqual(numberOfInvocations, 0) - } -} diff --git a/Tests/ApolloTests/QueryFromJSONBuildingTests.swift b/Tests/ApolloTests/QueryFromJSONBuildingTests.swift deleted file mode 100644 index cea4017fa4..0000000000 --- a/Tests/ApolloTests/QueryFromJSONBuildingTests.swift +++ /dev/null @@ -1,51 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -class QueryFromJSONBuildingTests: XCTestCase { - func testHeroDetailsWithFragmentQueryHuman() throws { - let jsonObject = [ - "hero": ["__typename": "Human", "name": "Luke Skywalker", "height": 1.72] - ] - - let data = try HeroDetailsWithFragmentQuery.Data(jsonObject: jsonObject) - - let human = try XCTUnwrap(data.hero?.fragments.heroDetails.asHuman, - "Wrong type") - - XCTAssertEqual(human.height, 1.72) - } - - func testConditionalInclusionQuery() throws { - let jsonObject = [ - "hero": [ - "__typename": "Hero", - "name": "R2-D2" - ] - ] - - let nameData = try HeroNameConditionalInclusionQuery.Data(jsonObject: jsonObject, variables: ["includeName" : true]) - XCTAssertEqual(nameData.hero?.name, "R2-D2") - - let noNameData = try HeroNameConditionalInclusionQuery.Data(jsonObject: jsonObject, variables: ["includeName" : false]) - XCTAssertNil(noNameData.hero?.name) - } - - func testConditionalInclusionQueryWithoutVariables() throws { - let jsonObject = [ - "hero": [ - "__typename": "Hero", - "name": "R2-D2" - ] - ] - - XCTAssertThrowsError(try HeroNameConditionalInclusionQuery.Data(jsonObject: jsonObject)) { error in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["hero"]) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } -} diff --git a/Tests/ApolloTests/ReadFieldValueTests.swift b/Tests/ApolloTests/ReadFieldValueTests.swift deleted file mode 100644 index 889c013100..0000000000 --- a/Tests/ApolloTests/ReadFieldValueTests.swift +++ /dev/null @@ -1,309 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import StarWarsAPI - -private struct MockSelectionSet: GraphQLSelectionSet { - public static let selections: [GraphQLSelection] = [] - - public var resultMap: ResultMap - - public init(unsafeResultMap: ResultMap) { - self.resultMap = unsafeResultMap - } -} - -class ReadFieldValueTests: XCTestCase { - - // MARK: - Helpers - - private func readFieldValue(_ field: GraphQLField, from object: JSONObject) throws -> Any? { - let executor = GraphQLExecutor { object, info in - return object[info.responseKeyForField] - } - - return try executor.execute(selections: [field], on: object, withKey: "", variables: [:], accumulator: GraphQLSelectionSetMapper()).resultMap[field.responseKey]! - } - - // MARK: - Tests - - func testGetScalar() throws { - let object: JSONObject = ["name": "Luke Skywalker"] - let field = GraphQLField("name", type: .nonNull(.scalar(String.self))) - - let value = try readFieldValue(field, from: object) as! String - - XCTAssertEqual(value, "Luke Skywalker") - } - - func testGetScalarWithMissingKey() { - let object: JSONObject = [:] - let field = GraphQLField("name", type: .nonNull(.scalar(String.self))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetScalarWithNull() throws { - let object: JSONObject = ["name": NSNull()] - let field = GraphQLField("name", type: .nonNull(.scalar(String.self))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.nullValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetScalarWithDifferentType() throws { - let object: JSONObject = ["name": 10] - let field = GraphQLField("name", type: .nonNull(.scalar(String.self))) - - let value = try XCTUnwrap(try readFieldValue(field, from: object) as? String, - "Wrong type, name should be a String!") - - XCTAssertEqual(value, "10") - } - - func testGetScalarWithWrongType() throws { - let object: JSONObject = ["name": 10.0] - let field = GraphQLField("name", type: .nonNull(.scalar(String.self))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if let error = error as? GraphQLResultError, case JSONDecodingError.couldNotConvert(let value, let expectedType) = error.underlying { - XCTAssertEqual(error.path, ["name"]) - XCTAssertEqual(value as? Double, 10.0) - XCTAssertTrue(expectedType == String.self) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetOptionalScalar() throws { - let object: JSONObject = ["name": "Luke Skywalker"] - let field = GraphQLField("name", type: .scalar(String.self)) - - let value = try readFieldValue(field, from: object) as! String? - XCTAssertEqual(value, "Luke Skywalker") - } - - func testGetOptionalScalarWithMissingKey() throws { - let object: JSONObject = [:] - let field = GraphQLField("name", type: .scalar(String.self)) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["name"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetOptionalScalarWithNull() throws { - let object: JSONObject = ["name": NSNull()] - let field = GraphQLField("name", type: .scalar(String.self)) - - let value = try readFieldValue(field, from: object) as! String? - - XCTAssertNil(value) - } - - func testGetOptionalScalarWithDifferentType() throws { - let object: JSONObject = ["name": 10] - let field = GraphQLField("name", type: .scalar(String.self)) - - let value = try XCTUnwrap(try readFieldValue(field, from: object) as? String, - "Wrong type, name should be a String!") - - XCTAssertEqual(value, "10") - } - - func testGetOptionalScalarWithWrongType() throws { - let object: JSONObject = ["name": 10.0] - let field = GraphQLField("name", type: .scalar(String.self)) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if let error = error as? GraphQLResultError, case JSONDecodingError.couldNotConvert(let value, let expectedType) = error.underlying { - XCTAssertEqual(error.path, ["name"]) - XCTAssertEqual(value as? Double, 10.0) - XCTAssertTrue(expectedType == String.self) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetScalarList() throws { - let object: JSONObject = ["appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.nonNull(.scalar(Episode.self))))) - - let value = try readFieldValue(field, from: object) as! [Episode] - - XCTAssertEqual(value, [.newhope, .empire, .jedi]) - } - - func testGetEmptyScalarList() throws { - let object: JSONObject = ["appearsIn": []] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.nonNull(.scalar(Episode.self))))) - - let value = try readFieldValue(field, from: object) as! [Episode] - - XCTAssertEqual(value, []) - } - - func testGetScalarListWithMissingKey() { - let object: JSONObject = [:] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.nonNull(.scalar(Episode.self))))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetScalarListWithNull() throws { - let object: JSONObject = ["appearsIn": NSNull()] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.nonNull(.scalar(Episode.self))))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.nullValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetScalarListWithDifferentType() throws { - let object: JSONObject = ["appearsIn": [4, 5, 6]] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.nonNull(.scalar(Episode.self))))) - - let value = try readFieldValue(field, from: object) as! [Episode] - - XCTAssertEqual(value, [.__unknown("4"), .__unknown("5"), .__unknown("6")]) - } - - func testGetScalarListWithWrongType() throws { - let object: JSONObject = ["appearsIn": [4.0, 5.0, 6.0]] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.nonNull(.scalar(Episode.self))))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if let error = error as? GraphQLResultError, case JSONDecodingError.couldNotConvert(let value, let expectedType) = error.underlying { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertEqual(value as? Double, 4.0) - XCTAssertTrue(expectedType == String.self) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetOptionalScalarList() throws { - let object: JSONObject = ["appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - let field = GraphQLField("appearsIn", type: .list(.nonNull(.scalar(Episode.self)))) - - let value = try readFieldValue(field, from: object) as! [Episode]? - - XCTAssertEqual(value!, [.newhope, .empire, .jedi]) - } - - func testGetEmptyOptionalScalarList() throws { - let object: JSONObject = ["appearsIn": []] - let field = GraphQLField("appearsIn", type: .list(.nonNull(.scalar(Episode.self)))) - - let value = try readFieldValue(field, from: object) as! [Episode] - - XCTAssertEqual(value, []) - } - - func testGetOptionalScalarListWithMissingKey() throws { - let object: JSONObject = [:] - let field = GraphQLField("appearsIn", type: .list(.nonNull(.scalar(Episode.self)))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if case let error as GraphQLResultError = error { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertMatch(error.underlying, JSONDecodingError.missingValue) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetOptionalScalarListWithNull() throws { - let object: JSONObject = ["appearsIn": NSNull()] - let field = GraphQLField("appearsIn", type: .list(.nonNull(.scalar(Episode.self)))) - - let value = try readFieldValue(field, from: object) as! [Episode]? - - XCTAssertNil(value) - } - - func testGetOptionalScalarListWithDifferentType() throws { - let object: JSONObject = ["appearsIn": [4, 5, 6]] - let field = GraphQLField("appearsIn", type: .list(.nonNull(.scalar(Episode.self)))) - - let value = try readFieldValue(field, from: object) as! [Episode] - - XCTAssertEqual(value, [.__unknown("4"), .__unknown("5"), .__unknown("6")]) - } - - func testGetOptionalScalarListWithWrongType() throws { - let object: JSONObject = ["appearsIn": [4.0, 5.0, 6.0]] - let field = GraphQLField("appearsIn", type: .list(.nonNull(.scalar(Episode.self)))) - - XCTAssertThrowsError(try readFieldValue(field, from: object)) { (error) in - if let error = error as? GraphQLResultError, case JSONDecodingError.couldNotConvert(let value, let expectedType) = error.underlying { - XCTAssertEqual(error.path, ["appearsIn"]) - XCTAssertEqual(value as? Double, 4.0) - XCTAssertTrue(expectedType == String.self) - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - func testGetScalarListWithOptionalElements() throws { - let object: JSONObject = ["appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - let field = GraphQLField("appearsIn", type: .nonNull(.list(.scalar(Episode.self)))) - - let value = try readFieldValue(field, from: object) as! [Episode?] - - XCTAssertEqual(value, [.newhope, .empire, .jedi] as [Episode?]) - } - - func testGetOptionalScalarListWithOptionalElements() throws { - let object: JSONObject = ["appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"]] - let field = GraphQLField("appearsIn", type: .list(.scalar(Episode.self))) - - let value = try readFieldValue(field, from: object) as! [Episode?]? - - XCTAssertEqual(value, [.newhope, .empire, .jedi] as [Episode?]) - } - - func testGetOptionalScalarListWithUnknownEnumCase() throws { - let object: JSONObject = ["appearsIn": ["TWOTOWERS"]] - let field = GraphQLField("appearsIn", type: .list(.scalar(Episode.self))) - - let value = try readFieldValue(field, from: object) as! [Episode?]? - - XCTAssertEqual(value, [.__unknown("TWOTOWERS")] as [Episode?]?) - } -} diff --git a/Tests/ApolloTests/RequestBodyCreatorTests.swift b/Tests/ApolloTests/RequestBodyCreatorTests.swift deleted file mode 100644 index e0deb585c0..0000000000 --- a/Tests/ApolloTests/RequestBodyCreatorTests.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// RequestBodyCreatorTests.swift -// ApolloTests -// -// Created by Kim de Vos on 16/07/2019. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import XCTest -@testable import Apollo -import StarWarsAPI -import UploadAPI - -class RequestBodyCreatorTests: XCTestCase { - private let customRequestBodyCreator = TestCustomRequestBodyCreator() - private let apolloRequestBodyCreator = ApolloRequestBodyCreator() - - func create(with creator: RequestBodyCreator, for query: Operation) -> GraphQLMap { - creator.requestBody(for: query, - sendOperationIdentifiers: false, - sendQueryDocument: true, - autoPersistQuery: false) - } - - // MARK: - Tests - - func testRequestBodyWithApolloRequestBodyCreator() { - let query = HeroNameQuery() - let req = self.create(with: apolloRequestBodyCreator, for: query) - - XCTAssertEqual(query.queryDocument, req["query"] as? String) - } - - func testRequestBodyWithCustomRequestBodyCreator() { - let query = HeroNameQuery() - let req = self.create(with: customRequestBodyCreator, for: query) - - XCTAssertEqual(query.queryDocument, req["test_query"] as? String) - } -} diff --git a/Tests/ApolloTests/RequestChainTests.swift b/Tests/ApolloTests/RequestChainTests.swift deleted file mode 100644 index 3b846f700b..0000000000 --- a/Tests/ApolloTests/RequestChainTests.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// RequestChainTests.swift -// Apollo -// -// Created by Ellen Shapiro on 7/14/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import XCTest -import Apollo -import ApolloTestSupport -import StarWarsAPI - -class RequestChainTests: XCTestCase { - - func testEmptyInterceptorArrayReturnsCorrectError() { - class TestProvider: InterceptorProvider { - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [] - } - } - - let transport = RequestChainNetworkTransport(interceptorProvider: TestProvider(), - endpointURL: TestURL.mockServer.url) - let expectation = self.expectation(description: "kickoff failed") - _ = transport.send(operation: HeroNameQuery()) { result in - defer { - expectation.fulfill() - } - - switch result { - case .success: - XCTFail("This should not have succeeded") - case .failure(let error): - switch error { - case RequestChain.ChainError.noInterceptors: - // This is what we want. - break - default: - XCTFail("Incorrect error for no interceptors: \(error)") - } - } - } - - - self.wait(for: [expectation], timeout: 1) - } - - func testCancellingChainCallsCancelOnInterceptorsWhichImplementCancellableAndNotOnOnesThatDont() { - class TestProvider: InterceptorProvider { - let cancellationInterceptor = CancellationHandlingInterceptor() - let retryInterceptor = BlindRetryingTestInterceptor() - - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - [ - self.cancellationInterceptor, - self.retryInterceptor - ] - } - } - - let provider = TestProvider() - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestURL.mockServer.url) - let expectation = self.expectation(description: "Send succeeded") - expectation.isInverted = true - let cancellable = transport.send(operation: HeroNameQuery()) { _ in - XCTFail("This should not have gone through") - expectation.fulfill() - } - - cancellable.cancel() - XCTAssertTrue(provider.cancellationInterceptor.hasBeenCancelled) - XCTAssertFalse(provider.retryInterceptor.hasBeenCancelled) - self.wait(for: [expectation], timeout: 2) - } - - func testErrorInterceptorGetsCalledAfterAnErrorIsReceived() { - class ErrorInterceptor: ApolloErrorInterceptor { - var error: Error? = nil - - func handleErrorAsync( - error: Error, - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - self.error = error - completion(.failure(error)) - } - } - - class TestProvider: InterceptorProvider { - let errorInterceptor = ErrorInterceptor() - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - return [ - // An interceptor which will error without a response - AutomaticPersistedQueryInterceptor() - ] - } - - func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? { - return self.errorInterceptor - } - } - - let provider = TestProvider() - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestURL.mockServer.url, - autoPersistQueries: true) - - let expectation = self.expectation(description: "Hero name query complete") - _ = transport.send(operation: HeroNameQuery()) { result in - defer { - expectation.fulfill() - } - switch result { - case .success: - XCTFail("This should not have succeeded") - case .failure(let error): - switch error { - case AutomaticPersistedQueryInterceptor.APQError.noParsedResponse: - // This is what we want. - break - default: - XCTFail("Unexpected error: \(error)") - } - } - } - - self.wait(for: [expectation], timeout: 1) - - switch provider.errorInterceptor.error { - case .some(let error): - switch error { - case AutomaticPersistedQueryInterceptor.APQError.noParsedResponse: - // Again, this is what we expect. - break - default: - XCTFail("Unexpected error on the interceptor: \(error)") - } - case .none: - XCTFail("Error interceptor did not receive an error!") - } - } - - func testErrorInterceptorGetsCalledInDefaultInterceptorProviderSubclass() { - class ErrorInterceptor: ApolloErrorInterceptor { - var error: Error? = nil - - func handleErrorAsync( - error: Error, - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - self.error = error - completion(.failure(error)) - } - } - - class TestProvider: DefaultInterceptorProvider { - let errorInterceptor = ErrorInterceptor() - - override func interceptors(for operation: Operation) -> [ApolloInterceptor] { - return [ - // An interceptor which will error without a response - AutomaticPersistedQueryInterceptor() - ] - } - - override func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? { - return self.errorInterceptor - } - } - - let provider = TestProvider(store: ApolloStore()) - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: TestURL.mockServer.url, - autoPersistQueries: true) - - let expectation = self.expectation(description: "Hero name query complete") - _ = transport.send(operation: HeroNameQuery()) { result in - defer { - expectation.fulfill() - } - switch result { - case .success: - XCTFail("This should not have succeeded") - case .failure(let error): - switch error { - case AutomaticPersistedQueryInterceptor.APQError.noParsedResponse: - // This is what we want. - break - default: - XCTFail("Unexpected error: \(error)") - } - } - } - - self.wait(for: [expectation], timeout: 1) - - switch provider.errorInterceptor.error { - case .some(let error): - switch error { - case AutomaticPersistedQueryInterceptor.APQError.noParsedResponse: - // Again, this is what we expect. - break - default: - XCTFail("Unexpected error on the interceptor: \(error)") - } - case .none: - XCTFail("Error interceptor did not receive an error!") - } - } -} diff --git a/Tests/ApolloTests/ResponsePathTests.swift b/Tests/ApolloTests/ResponsePathTests.swift deleted file mode 100644 index f767b0dd67..0000000000 --- a/Tests/ApolloTests/ResponsePathTests.swift +++ /dev/null @@ -1,38 +0,0 @@ -import XCTest -@testable import Apollo -import Nimble - -class ResponsePathTests: XCTestCase { - - func test__initializer__givenArray_shouldRespectKeyCasing() { - let subject: ResponsePath = ["first", "Second", "Third"] - - expect(subject.joined).to(equal("first.Second.Third")) - } - - func test__joined__givenArray_shouldReturnJoinedKeysInOrder() { - let subject: ResponsePath = ["first", "second", "third"] - - expect(subject.joined).to(equal("first.second.third")) - } - - func test__joined__whenAppendKey_shouldIncludeAppendedKeyLast() { - var subject: ResponsePath = ["first", "second", "third"] - subject.append("fourth") - - expect(subject.joined).to(equal("first.second.third.fourth")) - } - - func test__joined__whenAddKey_shouldIncludeAddedKeyLast() { - let paths: ResponsePath = ["first", "second"] - let subject = paths + "third" - - expect(subject.joined).to(equal("first.second.third")) - } - - func test__description__givenArray_shouldEqualJoined() { - let subject: ResponsePath = ["first", "second", "third"] - - expect(subject.description).to(equal(subject.joined)) - } -} diff --git a/Tests/ApolloTests/RetryToCountThenSucceedInterceptor.swift b/Tests/ApolloTests/RetryToCountThenSucceedInterceptor.swift deleted file mode 100644 index 8f31ebcae6..0000000000 --- a/Tests/ApolloTests/RetryToCountThenSucceedInterceptor.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// RetryToCountThenSucceedInterceptor.swift -// ApolloTests -// -// Created by Ellen Shapiro on 8/19/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import Foundation -import Apollo - -class RetryToCountThenSucceedInterceptor: ApolloInterceptor { - let timesToCallRetry: Int - var timesRetryHasBeenCalled = 0 - - init(timesToCallRetry: Int) { - self.timesToCallRetry = timesToCallRetry - } - - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - if self.timesRetryHasBeenCalled < self.timesToCallRetry { - self.timesRetryHasBeenCalled += 1 - chain.retry(request: request, - completion: completion) - } else { - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - } -} diff --git a/Tests/ApolloTests/SQLiteDotSwiftDatabaseBehaviorTests.swift b/Tests/ApolloTests/SQLiteDotSwiftDatabaseBehaviorTests.swift deleted file mode 100644 index 96c8a834e6..0000000000 --- a/Tests/ApolloTests/SQLiteDotSwiftDatabaseBehaviorTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import XCTest -@testable import ApolloSQLite -import ApolloTestSupport -import SQLite - -class SQLiteDotSwiftDatabaseBehaviorTests: XCTestCase { - - func testSelection_withForcedError_shouldThrow() throws { - let sqliteFileURL = SQLiteTestCacheProvider.temporarySQLiteFileURL() - let db = try! SQLiteDotSwiftDatabase(fileURL: sqliteFileURL) - - try! db.createRecordsTableIfNeeded() - try! db.addOrUpdateRecordString("record", for: "key") - - var rows = [DatabaseRow]() - XCTAssertNoThrow(rows = try db.selectRawRows(forKeys: ["key"])) - XCTAssertEqual(rows.count, 1) - - // Use SQLite directly to manipulate the database (cannot be done with SQLiteDotSwiftDatabase) - let connection = try Connection(.uri(sqliteFileURL.absoluteString), readonly: false) - let table = Table(SQLiteDotSwiftDatabase.tableName) - try! connection.run(table.drop(ifExists: false)) - - XCTAssertThrowsError(try db.selectRawRows(forKeys: ["key"])) - } -} diff --git a/Tests/ApolloTests/String+IncludesForTesting.swift b/Tests/ApolloTests/String+IncludesForTesting.swift deleted file mode 100644 index 6a1f3d63c7..0000000000 --- a/Tests/ApolloTests/String+IncludesForTesting.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// String+IncludesForTesting.swift -// ApolloTests -// -// Created by Ellen Shapiro on 9/21/20. -// Copyright © 2020 Apollo GraphQL. All rights reserved. -// - -import ApolloUtils -import Foundation -import XCTest - -extension ApolloExtension where Base == String { - - func checkIncludes(expectedString: String, - file: StaticString = #filePath, - line: UInt = #line) { - XCTAssertTrue(base.contains(expectedString), - "Expected string:\n\n\(expectedString)\n\ndid not appear in string\n\n\(base)", - file: file, - line: line) - } -} diff --git a/Tests/ApolloTests/TestCustomRequestBodyCreator.swift b/Tests/ApolloTests/TestCustomRequestBodyCreator.swift deleted file mode 100644 index 982199a6db..0000000000 --- a/Tests/ApolloTests/TestCustomRequestBodyCreator.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// TestCustomRequestBodyCreator.swift -// Apollo -// -// Created by Kim de Vos on 02/10/2019. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import Apollo - -struct TestCustomRequestBodyCreator: RequestBodyCreator { - func requestBody( - for operation: Operation, - sendOperationIdentifiers: Bool, - sendQueryDocument: Bool, autoPersistQuery: Bool) -> GraphQLMap { - - var body: GraphQLMap = [ - "test_variables": operation.variables, - "test_operationName": operation.operationName, - ] - - if sendOperationIdentifiers { - guard let operationIdentifier = operation.operationIdentifier else { - preconditionFailure("To send operation identifiers, Apollo types must be generated with operationIdentifiers") - } - - body["test_id"] = operationIdentifier - } else { - body["test_query"] = operation.queryDocument - } - - return body - } -} diff --git a/Tests/ApolloTests/URL+QueryDict.swift b/Tests/ApolloTests/URL+QueryDict.swift deleted file mode 100644 index 2fa8468e7d..0000000000 --- a/Tests/ApolloTests/URL+QueryDict.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// URL+QueryDict.swift -// ApolloTests -// -// Created by Ellen Shapiro on 10/14/19. -// Copyright © 2019 Apollo GraphQL. All rights reserved. -// - -import Foundation - -extension URL { - - /// Transforms the query items with values into an optional dictionary so it can be subscripted. - var queryItemDictionary: [String: String]? { - return URLComponents(url: self, resolvingAgainstBaseURL: false)? - .queryItems? - .reduce([String: String]()) { dict, queryItem in - guard let value = queryItem.value else { - return dict - } - - var updatedDict = dict - updatedDict[queryItem.name] = value - return updatedDict - } - } -} diff --git a/Tests/ApolloTests/UploadRequestTests.swift b/Tests/ApolloTests/UploadRequestTests.swift deleted file mode 100644 index 5889c37853..0000000000 --- a/Tests/ApolloTests/UploadRequestTests.swift +++ /dev/null @@ -1,193 +0,0 @@ -import XCTest -@testable import Apollo -import ApolloTestSupport -import UploadAPI -import StarWarsAPI - -class UploadRequestTests: XCTestCase { - - var client: ApolloClient! - - override func setUp() { - super.setUp() - - client = { - let store = ApolloStore() - let provider = DefaultInterceptorProvider(store: store) - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: URL(string: "http://www.test.com")!, - additionalHeaders: ["headerKey": "headerValue"]) - transport.clientName = "test" - transport.clientVersion = "test" - - return ApolloClient(networkTransport: transport, store: store) - }() - } - - override func tearDown() { - client = nil - - super.tearDown() - } - - func testSingleFileWithUploadRequest() throws { - let alphaFileUrl = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - - let alphaFile = try GraphQLFile(fieldName: "file", - originalName: "a.txt", - mimeType: "text/plain", - fileURL: alphaFileUrl) - let operation = UploadOneFileMutation(file: alphaFile.originalName) - - let transport = try XCTUnwrap(self.client.networkTransport as? RequestChainNetworkTransport) - - let httpRequest = transport.constructUploadRequest(for: operation, - with: [alphaFile], - manualBoundary: "TEST.BOUNDARY") - let uploadRequest = try XCTUnwrap(httpRequest as? UploadRequest) - - let urlRequest = try uploadRequest.toURLRequest() - XCTAssertEqual(urlRequest.allHTTPHeaderFields?["headerKey"], "headerValue") - - let formData = try uploadRequest.requestMultipartFormData() - let stringToCompare = try formData.toTestString() - - let expectedString = """ ---TEST.BOUNDARY -Content-Disposition: form-data; name="operations" - -{"id":"c5d5919f77d9ba16a9689b6b0ad4b781cb05dc1dc4812623bf80f7c044c09533","operationName":"UploadOneFile","query":"mutation UploadOneFile($file: Upload!) {\\n singleUpload(file: $file) {\\n __typename\\n id\\n path\\n filename\\n mimetype\\n }\\n}","variables":{"file":null}} ---TEST.BOUNDARY -Content-Disposition: form-data; name="map" - -{"0":["variables.file"]} ---TEST.BOUNDARY -Content-Disposition: form-data; name="0"; filename="a.txt" -Content-Type: text/plain - -Alpha file content. - ---TEST.BOUNDARY-- -""" - - XCTAssertEqual(stringToCompare, expectedString) - } - - func testMultipleFilesWithUploadRequest() throws { - let alphaFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - let alphaFile = try GraphQLFile(fieldName: "files", - originalName: "a.txt", - mimeType: "text/plain", - fileURL: alphaFileURL) - - let betaFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - let betaFile = try GraphQLFile(fieldName: "files", - originalName: "b.txt", - mimeType: "text/plain", - fileURL: betaFileURL) - - let files = [alphaFile, betaFile] - let operation = UploadMultipleFilesToTheSameParameterMutation(files: files.map { $0.originalName }) - let transport = try XCTUnwrap(self.client.networkTransport as? RequestChainNetworkTransport) - - let httpRequest = transport.constructUploadRequest(for: operation, - with: [alphaFile, betaFile], - manualBoundary: "TEST.BOUNDARY") - let uploadRequest = try XCTUnwrap(httpRequest as? UploadRequest) - - let urlRequest = try uploadRequest.toURLRequest() - XCTAssertEqual(urlRequest.allHTTPHeaderFields?["headerKey"], "headerValue") - - let multipartData = try uploadRequest.requestMultipartFormData() - let stringToCompare = try multipartData.toTestString() - - let expectedString = """ ---TEST.BOUNDARY -Content-Disposition: form-data; name="operations" - -{"id":"88858c283bb72f18c0049dc85b140e72a4046f469fa16a8bf4bcf01c11d8a2b7","operationName":"UploadMultipleFilesToTheSameParameter","query":"mutation UploadMultipleFilesToTheSameParameter($files: [Upload!]!) {\\n multipleUpload(files: $files) {\\n __typename\\n id\\n path\\n filename\\n mimetype\\n }\\n}","variables":{"files":[null,null]}} ---TEST.BOUNDARY -Content-Disposition: form-data; name="map" - -{"0":["variables.files.0"],"1":["variables.files.1"]} ---TEST.BOUNDARY -Content-Disposition: form-data; name="0"; filename="a.txt" -Content-Type: text/plain - -Alpha file content. - ---TEST.BOUNDARY -Content-Disposition: form-data; name="1"; filename="b.txt" -Content-Type: text/plain - -Bravo file content. - ---TEST.BOUNDARY-- -""" - XCTAssertEqual(stringToCompare, expectedString) - } - - func testMultipleFilesWithMultipleFieldsWithUploadRequest() throws { - let alphaFileURL = TestFileHelper.fileURLForFile(named: "a", extension: "txt") - let alphaFile = try GraphQLFile(fieldName: "uploads", - originalName: "a.txt", - mimeType: "text/plain", - fileURL: alphaFileURL) - - let betaFileURL = TestFileHelper.fileURLForFile(named: "b", extension: "txt") - let betaFile = try GraphQLFile(fieldName: "uploads", - originalName: "b.txt", - mimeType: "text/plain", - fileURL: betaFileURL) - - let charlieFileUrl = TestFileHelper.fileURLForFile(named: "c", extension: "txt") - let charlieFile = try GraphQLFile(fieldName: "secondField", - originalName: "c.txt", - mimeType: "text/plain", - fileURL: charlieFileUrl) - - let transport = try XCTUnwrap(self.client.networkTransport as? RequestChainNetworkTransport) - - let httpRequest = transport.constructUploadRequest(for: HeroNameQuery(), - with: [alphaFile, betaFile, charlieFile], - manualBoundary: "TEST.BOUNDARY") - let uploadRequest = try XCTUnwrap(httpRequest as? UploadRequest) - - let urlRequest = try uploadRequest.toURLRequest() - XCTAssertEqual(urlRequest.allHTTPHeaderFields?["headerKey"], "headerValue") - - let multipartData = try uploadRequest.requestMultipartFormData() - let stringToCompare = try multipartData.toTestString() - - let expectedString = """ ---TEST.BOUNDARY -Content-Disposition: form-data; name="operations" - -{"id":"f6e76545cd03aa21368d9969cb39447f6e836a16717823281803778e7805d671","operationName":"HeroName","query":"query HeroName($episode: Episode) {\\n hero(episode: $episode) {\\n __typename\\n name\\n }\\n}","variables":{"episode":null,\"secondField\":null,\"uploads\":null}} ---TEST.BOUNDARY -Content-Disposition: form-data; name="map" - -{"0":["variables.secondField"],"1":["variables.uploads.0"],"2":["variables.uploads.1"]} ---TEST.BOUNDARY -Content-Disposition: form-data; name="0"; filename="c.txt" -Content-Type: text/plain - -Charlie file content. - ---TEST.BOUNDARY -Content-Disposition: form-data; name="1"; filename="a.txt" -Content-Type: text/plain - -Alpha file content. - ---TEST.BOUNDARY -Content-Disposition: form-data; name="2"; filename="b.txt" -Content-Type: text/plain - -Bravo file content. - ---TEST.BOUNDARY-- -""" - XCTAssertEqual(stringToCompare, expectedString) - } -} diff --git a/Tests/ApolloTests/VersionNumberTests.swift b/Tests/ApolloTests/VersionNumberTests.swift deleted file mode 100644 index 12872567d7..0000000000 --- a/Tests/ApolloTests/VersionNumberTests.swift +++ /dev/null @@ -1,9 +0,0 @@ -import XCTest -@testable import Apollo - -class VersionNumberTests: XCTestCase { - func testVersionNumberExists() { - // It would be the first 2 digits of version number like `0.19`. - XCTAssertGreaterThanOrEqual(ApolloVersionNumber, 0) - } -} diff --git a/Tests/ApolloTests/WebSocket/CompressionTests.swift b/Tests/ApolloTests/WebSocket/CompressionTests.swift deleted file mode 100644 index fc774a3d5b..0000000000 --- a/Tests/ApolloTests/WebSocket/CompressionTests.swift +++ /dev/null @@ -1,48 +0,0 @@ -// Created by Joseph Ross on 7/16/14. -// Copyright © 2017 Joseph Ross. -// Modified by Anthony Miller & Apollo GraphQL on 8/12/21 -// -// This is a derived work derived from -// Starscream(https://github.com/daltoniam/Starscream) -// -// Original Work License: http://www.apache.org/licenses/LICENSE-2.0 -// Derived Work License: https://github.com/apollographql/apollo-ios/blob/main/LICENSE -// -// Compression implementation is implemented in conformance with RFC 7692 Compression Extensions -// for WebSocket: https://tools.ietf.org/html/rfc7692 - -import XCTest -@testable import ApolloWebSocket - -class CompressionTests: XCTestCase { - - func testBasic() { - let compressor = Compressor(windowBits: 15)! - let decompressor = Decompressor(windowBits: 15)! - - let rawData = "Hello, World! Hello, World! Hello, World! Hello, World! Hello, World!".data(using: .utf8)! - - let compressed = try! compressor.compress(rawData) - let uncompressed = try! decompressor.decompress(compressed, finish: true) - - XCTAssertEqual(rawData, uncompressed) - } - - func testHugeData() { - let compressor = Compressor(windowBits: 15)! - let decompressor = Decompressor(windowBits: 15)! - - // 2 Gigs! - var rawData = Data(repeating: 0, count: 0x80000) - let rawDataLen = rawData.count - rawData.withUnsafeMutableBytes { ptr -> Void in - arc4random_buf(ptr.baseAddress, rawDataLen) - } - - let compressed = try! compressor.compress(rawData) - let uncompressed = try! decompressor.decompress(compressed, finish: true) - - XCTAssertEqual(rawData, uncompressed) - } - -} diff --git a/Tests/ApolloTests/WebSocket/GraphqlTransportWsProtocolTests.swift b/Tests/ApolloTests/WebSocket/GraphqlTransportWsProtocolTests.swift deleted file mode 100644 index 7381c5c99d..0000000000 --- a/Tests/ApolloTests/WebSocket/GraphqlTransportWsProtocolTests.swift +++ /dev/null @@ -1,223 +0,0 @@ -import XCTest -@testable import ApolloWebSocket -import ApolloTestSupport -import Nimble -import Apollo -import SubscriptionAPI - -class GraphqlTransportWsProtocolTests: WSProtocolTestsBase { - - let `protocol` = "graphql-transport-ws" - - override var urlRequest: URLRequest { - var request = URLRequest(url: TestURL.mockServer.url) - request.setValue(`protocol`, forHTTPHeaderField: "Sec-WebSocket-Protocol") - - return request - } - - private func buildWebSocket() { - buildWebSocket(protocol: .graphql_transport_ws) - } - - // MARK: Initializer Tests - - func test__designatedInitializer__shouldSetRequestProtocolHeader() { - expect( - WebSocket( - request: URLRequest(url: TestURL.mockServer.url), - protocol: .graphql_transport_ws - ).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol") - ).to(equal(`protocol`)) - } - - func test__convenienceInitializers__shouldSetRequestProtocolHeader() { - expect( - WebSocket( - url: TestURL.mockServer.url, - protocol: .graphql_transport_ws - ).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol") - ).to(equal(`protocol`)) - - expect( - WebSocket( - url: TestURL.mockServer.url, - writeQueueQOS: .default, - protocol: .graphql_transport_ws - ).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol") - ).to(equal(`protocol`)) - } - - // MARK: Protocol Tests - - func test__messaging__givenDefaultConnectingPayload_whenWebSocketConnected_shouldSendConnectionInit() throws { - // given - buildWebSocket() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(payload: [:], type: .connectionInit)) - done() - } - - // when - self.websocketTransport.websocketDidConnect(socket: self.mockWebSocket) - } - } - - func test__messaging__givenNilConnectingPayload_whenWebSocketConnected_shouldSendConnectionInit() throws { - buildWebSocket() - - // given - websocketTransport = WebSocketTransport(websocket: mockWebSocket, connectingPayload: nil) - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(type: .connectionInit)) - done() - } - - // when - self.websocketTransport.websocketDidConnect(socket: self.mockWebSocket) - } - } - - func test__messaging__givenConnectingPayload_whenWebSocketConnected_shouldSendConnectionInit() throws { - buildWebSocket() - - // given - websocketTransport = WebSocketTransport( - websocket: mockWebSocket, - connectingPayload: ["sample": "data"] - ) - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(payload: ["sample": "data"], type: .connectionInit)) - done() - } - - // when - self.websocketTransport.websocketDidConnect(socket: self.mockWebSocket) - } - } - - func test__messaging__givenSubscriptionSubscribe_shouldSendSubscribe() { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - let operation = IncrementingSubscription() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(payload: operation.requestBody, id: "1", type: .subscribe)) - done() - } - - // when - self.client.subscribe(subscription: operation) { _ in } - } - } - - func test__messaging__givenSubscriptionCancel_shouldSendComplete() { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - let subject = client.subscribe(subscription: IncrementingSubscription()) { _ in } - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - let expected = OperationMessage(id: "1", type: .complete).rawMessage! - if message == expected { - done() - } - } - - // when - subject.cancel() - } - } - - func test__messaging__whenWebSocketClosed_shouldSendConnectionTerminate() throws { - // given - buildWebSocket() - - connectWebSocket() - ackConnection() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(type: .connectionTerminate)) - done() - } - - // when - self.websocketTransport.closeConnection() - } - } - - func test__messaging__whenReceivesNext_shouldParseMessage() throws { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - let operation = IncrementingSubscription() - - waitUntil { done in - // when - self.client.subscribe(subscription: operation) { result in - switch result { - case let .failure(error): - fail("Expected .success, got error: \(error.localizedDescription)") - - case let .success(graphqlResult): - expect(graphqlResult.data?.numberIncremented).to(equal(42)) - done() - } - } - - self.sendAsync(message: OperationMessage( - payload: ["data": ["numberIncremented": 42]], - id: "1", - type: .next - )) - } - } - - func test__messaging__whenReceivesPing_shouldSendPong() throws { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(type: .pong)) - done() - } - - // when - self.sendAsync(message: OperationMessage(payload: ["sample": "data"], type: .ping)) - } - } -} diff --git a/Tests/ApolloTests/WebSocket/GraphqlWsProtocolTests.swift b/Tests/ApolloTests/WebSocket/GraphqlWsProtocolTests.swift deleted file mode 100644 index 54bb62510e..0000000000 --- a/Tests/ApolloTests/WebSocket/GraphqlWsProtocolTests.swift +++ /dev/null @@ -1,203 +0,0 @@ -import XCTest -@testable import ApolloWebSocket -import ApolloTestSupport -import Nimble -import Apollo -import SubscriptionAPI - -class GraphqlWsProtocolTests: WSProtocolTestsBase { - - let `protocol` = "graphql-ws" - - override var urlRequest: URLRequest { - var request = URLRequest(url: TestURL.mockServer.url) - request.setValue(`protocol`, forHTTPHeaderField: "Sec-WebSocket-Protocol") - - return request - } - - private func buildWebSocket() { - buildWebSocket(protocol: .graphql_ws) - } - - // MARK: Initializer Tests - - func test__designatedInitializer__shouldSetRequestProtocolHeader() { - expect( - WebSocket( - request: URLRequest(url: TestURL.mockServer.url), - protocol: .graphql_ws - ).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol") - ).to(equal(`protocol`)) - } - - func test__convenienceInitializers__shouldSetRequestProtocolHeader() { - expect( - WebSocket( - url: TestURL.mockServer.url, - protocol: .graphql_ws - ).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol") - ).to(equal(`protocol`)) - - expect( - WebSocket( - url: TestURL.mockServer.url, - writeQueueQOS: .default, - protocol: .graphql_ws - ).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol") - ).to(equal(`protocol`)) - } - - // MARK: Protocol Tests - - func test__messaging__givenDefaultConnectingPayload_whenWebSocketConnected_shouldSendConnectionInit() throws { - // given - buildWebSocket() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(payload: [:], type: .connectionInit)) - done() - } - - // when - self.websocketTransport.websocketDidConnect(socket: self.mockWebSocket) - } - } - - func test__messaging__givenNilConnectingPayload_whenWebSocketConnected_shouldSendConnectionInit() throws { - buildWebSocket() - - // given - websocketTransport = WebSocketTransport(websocket: mockWebSocket, connectingPayload: nil) - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(type: .connectionInit)) - done() - } - - // when - self.websocketTransport.websocketDidConnect(socket: self.mockWebSocket) - } - } - - func test__messaging__givenConnectingPayload_whenWebSocketConnected_shouldSendConnectionInit() throws { - buildWebSocket() - - // given - websocketTransport = WebSocketTransport( - websocket: mockWebSocket, - connectingPayload: ["sample": "data"] - ) - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(payload: ["sample": "data"], type: .connectionInit)) - done() - } - - // when - self.websocketTransport.websocketDidConnect(socket: self.mockWebSocket) - } - } - - func test__messaging__givenSubscriptionSubscribe_shouldSendStart() { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - let operation = IncrementingSubscription() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(payload: operation.requestBody, id: "1", type: .start)) - done() - } - - // when - self.client.subscribe(subscription: operation) { _ in } - } - } - - func test__messaging__givenSubscriptionCancel_shouldSendStop() { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - let subject = client.subscribe(subscription: IncrementingSubscription()) { _ in } - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - let expected = OperationMessage(id: "1", type: .stop).rawMessage! - if message == expected { - done() - } - } - - // when - subject.cancel() - } - } - - func test__messaging__whenWebSocketClosed_shouldSendConnectionTerminate() throws { - // given - buildWebSocket() - - connectWebSocket() - ackConnection() - - waitUntil { done in - self.mockWebSocketDelegate.didReceiveMessage = { message in - // then - expect(message).to(equalMessage(type: .connectionTerminate)) - done() - } - - // when - self.websocketTransport.closeConnection() - } - } - - func test__messaging__whenReceivesData_shouldParseMessage() throws { - // given - buildWebSocket() - buildClient() - - connectWebSocket() - ackConnection() - - let operation = IncrementingSubscription() - - waitUntil { done in - // when - self.client.subscribe(subscription: operation) { result in - switch result { - case let .failure(error): - fail("Expected .success, got error: \(error.localizedDescription)") - - case let .success(graphqlResult): - expect(graphqlResult.data?.numberIncremented).to(equal(42)) - done() - } - } - - self.sendAsync(message: OperationMessage( - payload: ["data": ["numberIncremented": 42]], - id: "1", - type: .data - )) - } - } -} diff --git a/Tests/ApolloTests/WebSocket/OperationMessageIdCreatorTests.swift b/Tests/ApolloTests/WebSocket/OperationMessageIdCreatorTests.swift deleted file mode 100644 index 6c4381eaeb..0000000000 --- a/Tests/ApolloTests/WebSocket/OperationMessageIdCreatorTests.swift +++ /dev/null @@ -1,31 +0,0 @@ -import XCTest -@testable import ApolloWebSocket -import UploadAPI - -class OperationMessageIdCreatorTests: XCTestCase { - struct CustomOperationMessageIdCreator: OperationMessageIdCreator { - func requestId() -> String { - return "12345678" - } - } - - // MARK: - Tests - - func testOperationMessageIdCreatorWithApolloOperationMessageIdCreator() { - let apolloOperationMessageIdCreator = ApolloSequencedOperationMessageIdCreator(startAt: 5) - - let firstId = apolloOperationMessageIdCreator.requestId() - let secondId = apolloOperationMessageIdCreator.requestId() - - XCTAssertEqual(firstId, "5") - XCTAssertEqual(secondId, "6") - } - - func testOperationMessageIdCreatorWithCustomOperationMessageIdCreator() { - let customOperationMessageIdCreator = CustomOperationMessageIdCreator() - - let id = customOperationMessageIdCreator.requestId() - - XCTAssertEqual(id, "12345678") - } -} diff --git a/Tests/ApolloTests/WebSocket/SplitNetworkTransportTests.swift b/Tests/ApolloTests/WebSocket/SplitNetworkTransportTests.swift deleted file mode 100644 index 3d2afbae7e..0000000000 --- a/Tests/ApolloTests/WebSocket/SplitNetworkTransportTests.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// SplitNetworkTransportTests.swift -// ApolloWebSocketTests -// -// Created by Ellen Shapiro on 10/23/19. -// - -import Foundation -import XCTest -import Apollo -import ApolloTestSupport -@testable import ApolloWebSocket - -class SplitNetworkTransportTests: XCTestCase { - - private static let mockTransportName = "TestMockNetworkTransport" - private static let mockTransportVersion = "TestMockNetworkTransportVersion" - private static let webSocketName = "TestWebSocketTransport" - private static let webSocketVersion = "TestWebSocketTransportVersion" - - private var mockTransport: MockNetworkTransport! - private var webSocketTransport: MockWebSocketTransport! - private var splitTransport: SplitNetworkTransport! - - override func setUp() { - super.setUp() - - mockTransport = { - let transport = MockNetworkTransport(server: MockGraphQLServer(), store: ApolloStore()) - - transport.clientName = Self.mockTransportName - transport.clientVersion = Self.mockTransportVersion - return transport - }() - - webSocketTransport = MockWebSocketTransport( - clientName: Self.webSocketName, - clientVersion: Self.webSocketVersion - ) - - splitTransport = SplitNetworkTransport( - uploadingNetworkTransport: mockTransport, - webSocketNetworkTransport: webSocketTransport - ) - } - - override func tearDown() { - mockTransport = nil - webSocketTransport = nil - splitTransport = nil - - super.tearDown() - } - - func testGettingSplitClientNameWithDifferentNames() { - let splitName = self.splitTransport.clientName - XCTAssertTrue(splitName.hasPrefix("SPLIT_")) - XCTAssertTrue(splitName.contains(Self.mockTransportName)) - XCTAssertTrue(splitName.contains(Self.webSocketName)) - } - - func testGettingSplitClientVersionWithDifferentVersions() { - let splitVersion = self.splitTransport.clientVersion - XCTAssertTrue(splitVersion.hasPrefix("SPLIT_")) - XCTAssertTrue(splitVersion.contains(Self.mockTransportVersion)) - XCTAssertTrue(splitVersion.contains(Self.webSocketVersion)) - } - - func testGettingSplitClientNameWithTheSameNames() { - let splitName = "TestSplitClientName" - - self.webSocketTransport.clientName = splitName - self.mockTransport.clientName = splitName - - XCTAssertEqual(self.splitTransport.clientName, splitName) - } - - func testGettingSplitClientVersionWithTheSameVersions() { - let splitVersion = "TestSplitClientVersion" - - self.webSocketTransport.clientVersion = splitVersion - self.mockTransport.clientVersion = splitVersion - - XCTAssertEqual(self.splitTransport.clientVersion, splitVersion) - } -} diff --git a/Tests/ApolloTests/WebSocket/WSProtocolTestsBase.swift b/Tests/ApolloTests/WebSocket/WSProtocolTestsBase.swift deleted file mode 100644 index 5e224654df..0000000000 --- a/Tests/ApolloTests/WebSocket/WSProtocolTestsBase.swift +++ /dev/null @@ -1,81 +0,0 @@ -import XCTest -@testable import ApolloWebSocket -import ApolloTestSupport -import Nimble -import Apollo -import SubscriptionAPI - -class WSProtocolTestsBase: XCTestCase { - private var store: ApolloStore! - var mockWebSocket: MockWebSocket! - var websocketTransport: WebSocketTransport! { - didSet { - if let websocketTransport = websocketTransport { // caters for tearDown setting nil value - websocketTransport.websocket.delegate = mockWebSocketDelegate - } - } - } - var mockWebSocketDelegate: MockWebSocketDelegate! - var client: ApolloClient! - - override func setUp() { - super.setUp() - - store = ApolloStore() - } - - override func tearDown() { - client = nil - websocketTransport = nil - mockWebSocket = nil - mockWebSocketDelegate = nil - store = nil - - super.tearDown() - } - - // MARK: Helpers - - var urlRequest: URLRequest { - fatalError("Subclasses must override this property!") - } - - func buildWebSocket(protocol: WebSocket.WSProtocol) { - mockWebSocketDelegate = MockWebSocketDelegate() - mockWebSocket = MockWebSocket(request: urlRequest, protocol: `protocol`) - websocketTransport = WebSocketTransport(websocket: mockWebSocket, store: store) - } - - func buildClient() { - client = ApolloClient(networkTransport: websocketTransport, store: store) - } - - func connectWebSocket() { - websocketTransport.socketConnectionState.mutate { $0 = .connected } - } - - func ackConnection() { - let ackMessage = OperationMessage(type: .connectionAck).rawMessage! - websocketTransport.websocketDidReceiveMessage(socket: mockWebSocket, text: ackMessage) - } - - func sendAsync(message: OperationMessage) { - websocketTransport.processingQueue.async { - self.websocketTransport.websocketDidReceiveMessage( - socket: self.mockWebSocket, - text: message.rawMessage! - ) - } - } -} - -extension GraphQLOperation { - var requestBody: GraphQLMap { - ApolloRequestBodyCreator().requestBody( - for: self, - sendOperationIdentifiers: false, - sendQueryDocument: true, - autoPersistQuery: false - ) - } -} diff --git a/Tests/ApolloTests/WebSocket/WebSocketTests.swift b/Tests/ApolloTests/WebSocket/WebSocketTests.swift deleted file mode 100644 index e7f264fa53..0000000000 --- a/Tests/ApolloTests/WebSocket/WebSocketTests.swift +++ /dev/null @@ -1,175 +0,0 @@ -import XCTest -import Apollo -import ApolloTestSupport -@testable import ApolloWebSocket -import StarWarsAPI - -extension WebSocketTransport { - func write(message: GraphQLMap) { - let serialized = try! JSONSerializationFormat.serialize(value: message) - if let str = String(data: serialized, encoding: .utf8) { - self.websocket.write(string: str) - } - } -} - -class WebSocketTests: XCTestCase { - var networkTransport: WebSocketTransport! - var client: ApolloClient! - var websocket: MockWebSocket! - - struct CustomOperationMessageIdCreator: OperationMessageIdCreator { - func requestId() -> String { - return "12345678" - } - } - - override func setUp() { - super.setUp() - - let store = ApolloStore() - let websocket = MockWebSocket( - request:URLRequest(url: TestURL.mockServer.url), - protocol: .graphql_ws - ) - networkTransport = WebSocketTransport(websocket: websocket, store: store) - client = ApolloClient(networkTransport: networkTransport!, store: store) - } - - override func tearDown() { - networkTransport = nil - client = nil - websocket = nil - - super.tearDown() - } - - func testLocalSingleSubscription() throws { - let expectation = self.expectation(description: "Single subscription") - - client.subscribe(subscription: ReviewAddedSubscription()) { result in - defer { expectation.fulfill() } - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.reviewAdded?.stars, 5) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - let message : GraphQLMap = [ - "type": "data", - "id": "1", - "payload": [ - "data": [ - "reviewAdded": [ - "__typename": "ReviewAdded", - "episode": "JEDI", - "stars": 5, - "commentary": "A great movie" - ] - ] - ] - ] - - networkTransport.write(message: message) - - waitForExpectations(timeout: 5, handler: nil) - } - - func testLocalMissingSubscription() throws { - let expectation = self.expectation(description: "Missing subscription") - expectation.isInverted = true - - client.subscribe(subscription: ReviewAddedSubscription()) { _ in - expectation.fulfill() - } - - waitForExpectations(timeout: 2, handler: nil) - } - - func testLocalErrorUnknownId() throws { - let expectation = self.expectation(description: "Unknown id for subscription") - - client.subscribe(subscription: ReviewAddedSubscription()) { result in - defer { expectation.fulfill() } - - switch result { - case .success: - XCTFail("This should have caused an error!") - case .failure(let error): - if let webSocketError = error as? WebSocketError { - switch webSocketError.kind { - case .unprocessedMessage: - // Correct! - break - default: - XCTFail("Unexpected websocket error: \(error)") - } - } else { - XCTFail("Unexpected error: \(error)") - } - } - } - - let message : GraphQLMap = [ - "type": "data", - "id": "2", // subscribing on id = 1, i.e. expecting error when receiving id = 2 - "payload": [ - "data": [ - "reviewAdded": [ - "__typename": "ReviewAdded", - "episode": "JEDI", - "stars": 5, - "commentary": "A great movie" - ] - ] - ] - ] - - networkTransport.write(message: message) - - waitForExpectations(timeout: 2, handler: nil) - } - - func testSingleSubscriptionWithCustomOperationMessageIdCreator() throws { - let expectation = self.expectation(description: "Single Subscription with Custom Operation Message Id Creator") - - let store = ApolloStore() - let websocket = MockWebSocket( - request:URLRequest(url: TestURL.mockServer.url), - protocol: .graphql_ws - ) - networkTransport = WebSocketTransport(websocket: websocket, store: store, operationMessageIdCreator: CustomOperationMessageIdCreator()) - client = ApolloClient(networkTransport: networkTransport!, store: store) - - client.subscribe(subscription: ReviewAddedSubscription()) { result in - defer { expectation.fulfill() } - switch result { - case .success(let graphQLResult): - XCTAssertEqual(graphQLResult.data?.reviewAdded?.stars, 5) - case .failure(let error): - XCTFail("Unexpected error: \(error)") - } - } - - let message : GraphQLMap = [ - "type": "data", - "id": "12345678", // subscribing on id = 12345678 from custom operation id - "payload": [ - "data": [ - "reviewAdded": [ - "__typename": "ReviewAdded", - "episode": "JEDI", - "stars": 5, - "commentary": "A great movie" - ] - ] - ] - ] - - networkTransport.write(message: message) - - waitForExpectations(timeout: 2, handler: nil) - } -} diff --git a/Tests/ApolloTests/WebSocket/WebSocketTransportTests.swift b/Tests/ApolloTests/WebSocket/WebSocketTransportTests.swift deleted file mode 100644 index caa4d9440f..0000000000 --- a/Tests/ApolloTests/WebSocket/WebSocketTransportTests.swift +++ /dev/null @@ -1,82 +0,0 @@ -import XCTest -import Apollo -import ApolloTestSupport -@testable import ApolloWebSocket - -class WebSocketTransportTests: XCTestCase { - - private var webSocketTransport: WebSocketTransport! - - override func tearDown() { - webSocketTransport = nil - - super.tearDown() - } - - func testUpdateHeaderValues() { - var request = URLRequest(url: TestURL.mockServer.url) - request.addValue("OldToken", forHTTPHeaderField: "Authorization") - - self.webSocketTransport = WebSocketTransport( - websocket: MockWebSocket(request: request, protocol: .graphql_ws), - store: ApolloStore() - ) - - self.webSocketTransport.updateHeaderValues(["Authorization": "UpdatedToken"]) - - XCTAssertEqual(self.webSocketTransport.websocket.request.allHTTPHeaderFields?["Authorization"], "UpdatedToken") - } - - func testUpdateConnectingPayload() { - let request = URLRequest(url: TestURL.mockServer.url) - - self.webSocketTransport = WebSocketTransport( - websocket: MockWebSocket(request: request, protocol: .graphql_ws), - store: ApolloStore(), - connectingPayload: ["Authorization": "OldToken"] - ) - - let mockWebSocketDelegate = MockWebSocketDelegate() - - let mockWebSocket = self.webSocketTransport.websocket as? MockWebSocket - self.webSocketTransport.socketConnectionState.mutate { $0 = .connected } - mockWebSocket?.delegate = mockWebSocketDelegate - - let exp = expectation(description: "Waiting for reconnect") - - mockWebSocketDelegate.didReceiveMessage = { message in - let json = try? JSONSerializationFormat.deserialize(data: message.data(using: .utf8)!) as? JSONObject - guard let payload = json?["payload"] as? JSONObject, (json?["type"] as? String) == "connection_init" else { - return - } - - XCTAssertEqual(payload["Authorization"] as? String, "UpdatedToken") - exp.fulfill() - } - - self.webSocketTransport.updateConnectingPayload(["Authorization": "UpdatedToken"]) - self.webSocketTransport.initServer() - - waitForExpectations(timeout: 3, handler: nil) - } - - func testCloseConnectionAndInit() { - let request = URLRequest(url: TestURL.mockServer.url) - - self.webSocketTransport = WebSocketTransport( - websocket: MockWebSocket(request: request, protocol: .graphql_ws), - store: ApolloStore(), - connectingPayload: ["Authorization": "OldToken"] - ) - self.webSocketTransport.closeConnection() - self.webSocketTransport.updateConnectingPayload(["Authorization": "UpdatedToken"]) - self.webSocketTransport.initServer() - - let exp = expectation(description: "Wait") - let result = XCTWaiter.wait(for: [exp], timeout: 1.0) - if result == XCTWaiter.Result.timedOut { - } else { - XCTFail("Delay interrupted") - } - } -} diff --git a/Tests/README.md b/Tests/README.md new file mode 100644 index 0000000000..5d40cf5f79 --- /dev/null +++ b/Tests/README.md @@ -0,0 +1 @@ +All tests for the Apollo iOS code are located in the [Apollo iOS Dev](https://github.com/apollographql/apollo-ios-dev/tree/main/Tests) repo. \ No newline at end of file diff --git a/Tests/TestPlans/Apollo-CITestPlan.xctestplan b/Tests/TestPlans/Apollo-CITestPlan.xctestplan deleted file mode 100644 index 613d383f3d..0000000000 --- a/Tests/TestPlans/Apollo-CITestPlan.xctestplan +++ /dev/null @@ -1,31 +0,0 @@ -{ - "configurations" : [ - { - "id" : "8B27E3A2-3A52-417E-9598-1FF14D3F8C84", - "name" : "Configuration 1", - "options" : { - - } - } - ], - "defaultOptions" : { - - }, - "testTargets" : [ - { - "target" : { - "containerPath" : "container:Apollo.xcodeproj", - "identifier" : "9FC7504D1D2A532D00458D91", - "name" : "ApolloTests" - } - }, - { - "target" : { - "containerPath" : "container:Apollo.xcodeproj", - "identifier" : "9F54C8B3255D760B0065AFD6", - "name" : "ApolloPerformanceTests" - } - } - ], - "version" : 1 -} diff --git a/Tests/TestPlans/Apollo-CodegenTestPlan.xctestplan b/Tests/TestPlans/Apollo-CodegenTestPlan.xctestplan deleted file mode 100644 index 2a117aa0f2..0000000000 --- a/Tests/TestPlans/Apollo-CodegenTestPlan.xctestplan +++ /dev/null @@ -1,24 +0,0 @@ -{ - "configurations" : [ - { - "id" : "7BBE4BEB-2608-4818-AB40-1149E12C6785", - "name" : "Configuration 1", - "options" : { - - } - } - ], - "defaultOptions" : { - - }, - "testTargets" : [ - { - "target" : { - "containerPath" : "container:Apollo.xcodeproj", - "identifier" : "9BAEEBFB234BB8FD00808306", - "name" : "ApolloCodegenTests" - } - } - ], - "version" : 1 -} diff --git a/Tests/TestPlans/Apollo-IntegrationTestPlan.xctestplan b/Tests/TestPlans/Apollo-IntegrationTestPlan.xctestplan deleted file mode 100644 index 948aa88572..0000000000 --- a/Tests/TestPlans/Apollo-IntegrationTestPlan.xctestplan +++ /dev/null @@ -1,29 +0,0 @@ -{ - "configurations" : [ - { - "id" : "8F157DCD-D977-4EAA-80AD-D947EF785D9D", - "name" : "Configuration 1", - "options" : { - "environmentVariableEntries" : [ - - ] - } - } - ], - "defaultOptions" : { - - }, - "testTargets" : [ - { - "skippedTests" : [ - "StarWarsSubscriptionTests\/testConcurrentSubscribing()" - ], - "target" : { - "containerPath" : "container:Apollo.xcodeproj", - "identifier" : "DE6B15AB26152BE10068D642", - "name" : "ApolloServerIntegrationTests" - } - } - ], - "version" : 1 -} diff --git a/Tests/TestPlans/Apollo-PerformanceTestPlan.xctestplan b/Tests/TestPlans/Apollo-PerformanceTestPlan.xctestplan deleted file mode 100644 index f2b1b7a04e..0000000000 --- a/Tests/TestPlans/Apollo-PerformanceTestPlan.xctestplan +++ /dev/null @@ -1,24 +0,0 @@ -{ - "configurations" : [ - { - "id" : "72DF6CB1-DEC6-49C8-91E1-2EE002E10612", - "name" : "Configuration 1", - "options" : { - - } - } - ], - "defaultOptions" : { - - }, - "testTargets" : [ - { - "target" : { - "containerPath" : "container:Apollo.xcodeproj", - "identifier" : "9F54C8B3255D760B0065AFD6", - "name" : "ApolloPerformanceTests" - } - } - ], - "version" : 1 -} diff --git a/Tests/TestPlans/Apollo-UnitTestPlan.xctestplan b/Tests/TestPlans/Apollo-UnitTestPlan.xctestplan deleted file mode 100644 index 2314709c07..0000000000 --- a/Tests/TestPlans/Apollo-UnitTestPlan.xctestplan +++ /dev/null @@ -1,24 +0,0 @@ -{ - "configurations" : [ - { - "id" : "36C7A583-06D6-4733-AF67-CC38D6FB14FF", - "name" : "Configuration 1", - "options" : { - - } - } - ], - "defaultOptions" : { - - }, - "testTargets" : [ - { - "target" : { - "containerPath" : "container:Apollo.xcodeproj", - "identifier" : "9FC7504D1D2A532D00458D91", - "name" : "ApolloTests" - } - } - ], - "version" : 1 -} diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index b71f0da53c..0000000000 --- a/docs/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Documentation - -This is the documentation **source** for this repository. - -The **deployed** version of the documentation for this repository is available at: - -* https://www.apollographql.com/docs/ios/ - -See the [docs site README](https://github.com/apollographql/docs) for local installation and development. diff --git a/docs/shared/carthage-installation-panel.mdx b/docs/shared/carthage-installation-panel.mdx deleted file mode 100644 index dfc6af49a8..0000000000 --- a/docs/shared/carthage-installation-panel.mdx +++ /dev/null @@ -1,57 +0,0 @@ - - - - - -#### Set up your `Cartfile` - -Add `github "apollographql/apollo-ios"` to your Cartfile. - - - - -#### Check out and build dependencies - -Run `carthage update --use-xcframeworks --platform ios` (or `--platform ios,macos` to build both Mac and iOS). - -> **Note:** There's an issue with the way Carthage uses Lipo in the Xcode 12 GM. Please `cd` into `[YourProject]/Carthage/Checkouts/apollo-ios/scripts` and then run `./carthage-build-workaround.sh` to resolve this build issue. - - - - -#### Add built frameworks to your project - -Drag and drop `Apollo.framework` from the appropriate `Carthage/Build/iOS` or `Carthage/Build/Mac` folder to the **Embedded Binaries** section of your application target's **General** settings tab. This should also cause them to appear in the **Linked Frameworks And Libraries** section automatically. - - To include the `ApolloSQLite` library, also drag `ApolloSQLite.framework` and `SQLite.framework` to this area. - - To include the `ApolloWebSocket` library, also drag `ApolloWebSocket.framework` and `Starscream.framework` to this area. - - - - -#### Work around Carthage submission bug - -On your application target's **Build Phases** settings tab, click the **+** icon and choose **New Run Script Phase**. Create a Run Script in which you specify your shell (e.g., `bin/sh`) and add the following contents to the script area below the shell: - - ```sh - /usr/local/bin/carthage copy-frameworks - ``` - -Then, add the paths to the frameworks you want to use under **Input Files**, e.g.: - - ``` - $(SRCROOT)/Carthage/Build/iOS/Apollo.framework - ``` - -Again, if you're adding `ApolloSQLite` or `ApolloWebSocket`, please make sure to add the other frameworks you added as Input Files. - -This script works around an [App Store submission bug](http://www.openradar.me/radar?id=6409498411401216) triggered by universal binaries and ensures that necessary bitcode-related files and dSYMs are copied when archiving. - - - - -You're done! - - - - - diff --git a/docs/shared/carthage-run-script-panel.mdx b/docs/shared/carthage-run-script-panel.mdx deleted file mode 100644 index bf592a7c73..0000000000 --- a/docs/shared/carthage-run-script-panel.mdx +++ /dev/null @@ -1,16 +0,0 @@ - - -The scripts and binaries that you need to generate code are included in the `Carthage/Checkouts` folder. If this folder is not checked into version control, all developers on a team (and your CI machine) need to run `carthage checkout` when changes are made to the version to ensure they have the correct underlying binaries and scripts. - -Team members can then use this build script: - -```bash -# Don't run this during index builds -if [ $ACTION = "indexbuild" ]; then exit 0; fi - -SCRIPT_PATH="${SRCROOT}/Carthage/Checkouts/apollo-ios/scripts" -cd "${SRCROOT}/${TARGET_NAME}" -"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" API.swift -``` - - diff --git a/docs/shared/pods-installation-panel.mdx b/docs/shared/pods-installation-panel.mdx deleted file mode 100644 index 7dfd4160a3..0000000000 --- a/docs/shared/pods-installation-panel.mdx +++ /dev/null @@ -1,42 +0,0 @@ - - - - - -#### Install or update CocoaPods - -Because Apollo iOS uses Swift 5, you need to use CocoaPods version `1.7.0` or later. You can install CocoaPods with the following command: - - ```sh - gem install cocoapods - ``` - - - - -#### Add dependencies - -Add `pod "Apollo"` to your Podfile. - - - To include the `ApolloSQLite` framework, also add `pod "Apollo/SQLite"` - - To include the `ApolloWebSocket` framework, also add `pod "Apollo/WebSocket"` - - - - -Run `pod install`. - - - - -Use the `.xcworkspace` file generated by CocoaPods to work on your project. - - - - -You're done! - - - - - diff --git a/docs/shared/pods-run-script-panel.mdx b/docs/shared/pods-run-script-panel.mdx deleted file mode 100644 index 96225966fd..0000000000 --- a/docs/shared/pods-run-script-panel.mdx +++ /dev/null @@ -1,14 +0,0 @@ - - -Our CocoaPods install includes the code-generation scripts and binaries of the `apollo` CLI client as files which will not be added to the framework, but which you can still call from a Run Script Build Phase. Add the following to the Run Script: - -```bash -# Don't run this during index builds -if [ $ACTION = "indexbuild" ]; then exit 0; fi - -SCRIPT_PATH="${PODS_ROOT}/Apollo/scripts" -cd "${SRCROOT}/${TARGET_NAME}" -"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" API.swift -``` - - diff --git a/docs/shared/spm-installation-panel.mdx b/docs/shared/spm-installation-panel.mdx deleted file mode 100644 index 0d84f6eea5..0000000000 --- a/docs/shared/spm-installation-panel.mdx +++ /dev/null @@ -1,45 +0,0 @@ - - -> **Note:** These instructions use the Xcode 13 UI. Xcode 11 is the first version of Xcode that integrates Swift Package manager, whereas older versions require using the command line. If you're using an older version of Xcode, we recommend using CocoaPods instead. - - - - -Go to **File > Add Packages...** - -Adding an SPM package - - - - -In the dialog that appears, paste the URL of the Apollo iOS GitHub repo (`https://github.com/apollographql/apollo-ios.git`) into the search bar, then select the `apollo-ios` package that appears: - -Pasting the Apollo iOS GitHub URL - - - - -Select which version you want to use ([see version history](https://github.com/apollographql/apollo-ios/releases)), then click **Add Package**. Note that Xcode might not automatically select the latest version number! - -> Xcode automatically suggests the dependency rule `Up to Next Major`. We **strongly** suggest that until the release of Apollo iOS `1.x`, you select `Up To Next Minor` instead, because we might release breaking changes in a minor version. - - - - -Select which packages you want to use. If you're getting started, we recommend selecting just the main `Apollo` library for now. You can always add other packages later if you need them. - -Selecting Apollo iOS packages - -> **Note:** Do **not** select the `Apollo-Dynamic` target. This target is only for projects that link to Apollo iOS. Most projects do not need to do this. - -Then, click **Add Package**. - - - - -You're done! - - - - - diff --git a/docs/shared/spm-run-script-panel.mdx b/docs/shared/spm-run-script-panel.mdx deleted file mode 100644 index f57fb75e38..0000000000 --- a/docs/shared/spm-run-script-panel.mdx +++ /dev/null @@ -1,37 +0,0 @@ - - -> **Note:** If your Derived Data is in a custom location, go back and use the [Swift Scripting](./swift-scripting) method instead. This script relies on Derived Data being in the default location. Swift Scripting doesn't rely on Derived Data at all. - -If you're using Xcode 11 or higher, SPM checks out the appropriate build script along with the rest of the files when it checks out the repo. Add the following to your Run Script build phase: - -```bash -# Don't run this during index builds -if [ $ACTION = "indexbuild" ]; then exit 0; fi - -# Go to the build root and search up the chain to find the Derived Data Path where the source packages are checked out. -DERIVED_DATA_CANDIDATE="${BUILD_ROOT}" - -while ! [ -d "${DERIVED_DATA_CANDIDATE}/SourcePackages" ]; do - if [ "${DERIVED_DATA_CANDIDATE}" = / ]; then - echo >&2 "error: Unable to locate SourcePackages directory from BUILD_ROOT: '${BUILD_ROOT}'" - exit 1 - fi - - DERIVED_DATA_CANDIDATE="$(dirname "${DERIVED_DATA_CANDIDATE}")" -done - -# Grab a reference to the directory where scripts are checked out -SCRIPT_PATH="${DERIVED_DATA_CANDIDATE}/SourcePackages/checkouts/apollo-ios/scripts" - -if [ -z "${SCRIPT_PATH}" ]; then - echo >&2 "error: Couldn't find the CLI script in your checked out SPM packages; make sure to add the framework to your project." - exit 1 -fi - -cd "${SRCROOT}/${TARGET_NAME}" -"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" API.swift -``` - -> **Note:** If you try to use this with command line SPM, when you regenerate your `xcodeproj` this build script will get wiped out. We strongly recommend using Xcode 11's built-in SPM handling instead of the command line because of this. - - diff --git a/docs/shared/sqlite-carthage-panel.mdx b/docs/shared/sqlite-carthage-panel.mdx deleted file mode 100644 index fffde233e1..0000000000 --- a/docs/shared/sqlite-carthage-panel.mdx +++ /dev/null @@ -1,5 +0,0 @@ - - -You will need to add the `ApolloSQLite` framework to your target. This should be one of the libraries that gets built automatically on checkout, and should include the dependent libraries necessary to run it. - - diff --git a/docs/shared/sqlite-cocoapods-panel.mdx b/docs/shared/sqlite-cocoapods-panel.mdx deleted file mode 100644 index 8669eee26d..0000000000 --- a/docs/shared/sqlite-cocoapods-panel.mdx +++ /dev/null @@ -1,12 +0,0 @@ - - -Add the following to your `Podfile`: - -```ruby -pod 'Apollo' -pod 'Apollo/SQLite' -``` - -Note that if you're specifying a version for `Apollo`, you need to specify the same version for `Apollo/SQLite`. - - \ No newline at end of file diff --git a/docs/shared/sqlite-spm-panel.mdx b/docs/shared/sqlite-spm-panel.mdx deleted file mode 100644 index 8ff04d0532..0000000000 --- a/docs/shared/sqlite-spm-panel.mdx +++ /dev/null @@ -1,13 +0,0 @@ - - -Add the following to your `Package.swift`: - -```swift -.target( - name: "MyApplication", - dependencies: [ - .product(name: "ApolloSQLite", package: "Apollo"), - ]) -``` - - \ No newline at end of file diff --git a/docs/source/_redirects b/docs/source/_redirects deleted file mode 100644 index 77fb1c308a..0000000000 --- a/docs/source/_redirects +++ /dev/null @@ -1,2 +0,0 @@ -/tutorial /docs/ios/tutorial/tutorial-introduction -/tutorial/tutorial-create-project /docs/ios/tutorial/tutorial-add-sdk diff --git a/docs/source/api-reference.md b/docs/source/api-reference.md deleted file mode 100644 index d18ba8859f..0000000000 --- a/docs/source/api-reference.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: API Reference ---- - -* [Apollo.framework](./api/Apollo/README/) -* [ApolloAPI.framework](./api/ApolloAPI/README/) -* [ApolloUtils.framework](./api/ApolloUtils/README/) -* [ApolloCodegenLib.framework](./api/ApolloCodegenLib/README/) -* [ApolloSQLite.framework](./api/ApolloSQLite/README/) -* [ApolloWebSocket.framework](./api/ApolloWebSocket/README/) - -Our API reference is automatically generated directly from the inline comments in our code, so if you're adding something new, all you have to do is actually add doc comments and they'll show up here. - -See something missing documentation? Add docu-comments to the code, and open a pull request! - -We're using [SourceDocs](https://github.com/eneko/SourceDocs) via our `SwiftScripts` package. - -To run the generator, `cd` into the `SwiftScripts` folder and run - -``` -swift run DocumentationGenerator -``` diff --git a/docs/source/api/Apollo/README.md b/docs/source/api/Apollo/README.md deleted file mode 100644 index c58cef810c..0000000000 --- a/docs/source/api/Apollo/README.md +++ /dev/null @@ -1,147 +0,0 @@ -# Reference Documentation - -## Protocols - -- [ApolloClientProtocol](protocols/ApolloClientProtocol/) -- [ApolloErrorInterceptor](protocols/ApolloErrorInterceptor/) -- [ApolloInterceptor](protocols/ApolloInterceptor/) -- [Cancellable](protocols/Cancellable/) -- [GraphQLFragment](protocols/GraphQLFragment/) -- [GraphQLMapConvertible](protocols/GraphQLMapConvertible/) -- [GraphQLMutation](protocols/GraphQLMutation/) -- [GraphQLOperation](protocols/GraphQLOperation/) -- [GraphQLQuery](protocols/GraphQLQuery/) -- [GraphQLSelection](protocols/GraphQLSelection/) -- [GraphQLSelectionSet](protocols/GraphQLSelectionSet/) -- [GraphQLSubscription](protocols/GraphQLSubscription/) -- [InterceptorProvider](protocols/InterceptorProvider/) -- [JSONDecodable](protocols/JSONDecodable/) -- [JSONEncodable](protocols/JSONEncodable/) -- [NetworkTransport](protocols/NetworkTransport/) -- [NormalizedCache](protocols/NormalizedCache/) -- [RequestBodyCreator](protocols/RequestBodyCreator/) -- [UploadingNetworkTransport](protocols/UploadingNetworkTransport/) - -## Structs - -- [ApolloRequestBodyCreator](structs/ApolloRequestBodyCreator/) -- [AutomaticPersistedQueryInterceptor](structs/AutomaticPersistedQueryInterceptor/) -- [CacheReadInterceptor](structs/CacheReadInterceptor/) -- [CacheReference](structs/CacheReference/) -- [CacheWriteInterceptor](structs/CacheWriteInterceptor/) -- [FieldArguments](structs/FieldArguments/) -- [GraphQLBooleanCondition](structs/GraphQLBooleanCondition/) -- [GraphQLError](structs/GraphQLError/) -- [GraphQLError.Location](structs/GraphQLError.Location/) -- [GraphQLField](structs/GraphQLField/) -- [GraphQLFile](structs/GraphQLFile/) -- [GraphQLFragmentSpread](structs/GraphQLFragmentSpread/) -- [GraphQLGETTransformer](structs/GraphQLGETTransformer/) -- [GraphQLResult](structs/GraphQLResult/) -- [GraphQLResultError](structs/GraphQLResultError/) -- [GraphQLTypeCase](structs/GraphQLTypeCase/) -- [GraphQLTypeCondition](structs/GraphQLTypeCondition/) -- [JSONResponseParsingInterceptor](structs/JSONResponseParsingInterceptor/) -- [JSONValueMatcher](structs/JSONValueMatcher/) -- [Record](structs/Record/) -- [RecordSet](structs/RecordSet/) -- [ResponseCodeInterceptor](structs/ResponseCodeInterceptor/) - -## Classes - -- [ApolloClient](classes/ApolloClient/) -- [ApolloStore](classes/ApolloStore/) -- [ApolloStore.ReadTransaction](classes/ApolloStore.ReadTransaction/) -- [ApolloStore.ReadWriteTransaction](classes/ApolloStore.ReadWriteTransaction/) -- [DefaultInterceptorProvider](classes/DefaultInterceptorProvider/) -- [EmptyCancellable](classes/EmptyCancellable/) -- [GraphQLQueryWatcher](classes/GraphQLQueryWatcher/) -- [GraphQLResponse](classes/GraphQLResponse/) -- [HTTPRequest](classes/HTTPRequest/) -- [HTTPResponse](classes/HTTPResponse/) -- [InMemoryNormalizedCache](classes/InMemoryNormalizedCache/) -- [JSONRequest](classes/JSONRequest/) -- [JSONSerializationFormat](classes/JSONSerializationFormat/) -- [MaxRetryInterceptor](classes/MaxRetryInterceptor/) -- [MultipartFormData](classes/MultipartFormData/) -- [NetworkFetchInterceptor](classes/NetworkFetchInterceptor/) -- [RequestChain](classes/RequestChain/) -- [RequestChainNetworkTransport](classes/RequestChainNetworkTransport/) -- [TaskData](classes/TaskData/) -- [URLSessionClient](classes/URLSessionClient/) -- [UploadRequest](classes/UploadRequest/) - -## Enums - -- [ApolloClient.ApolloClientError](enums/ApolloClient.ApolloClientError/) -- [AutomaticPersistedQueryInterceptor.APQError](enums/AutomaticPersistedQueryInterceptor.APQError/) -- [CachePolicy](enums/CachePolicy/) -- [CacheWriteInterceptor.CacheWriteError](enums/CacheWriteInterceptor.CacheWriteError/) -- [GraphQLFile.GraphQLFileError](enums/GraphQLFile.GraphQLFileError/) -- [GraphQLHTTPRequestError](enums/GraphQLHTTPRequestError/) -- [GraphQLOperationType](enums/GraphQLOperationType/) -- [GraphQLOutputType](enums/GraphQLOutputType/) -- [GraphQLResult.Source](enums/GraphQLResult.Source/) -- [JSONDecodingError](enums/JSONDecodingError/) -- [JSONResponseParsingInterceptor.JSONResponseParsingError](enums/JSONResponseParsingInterceptor.JSONResponseParsingError/) -- [MaxRetryInterceptor.RetryError](enums/MaxRetryInterceptor.RetryError/) -- [RequestChain.ChainError](enums/RequestChain.ChainError/) -- [ResponseCodeInterceptor.ResponseCodeError](enums/ResponseCodeInterceptor.ResponseCodeError/) -- [URLSessionClient.URLSessionClientError](enums/URLSessionClient.URLSessionClientError/) - -## Extensions - -- [ApolloClient](extensions/ApolloClient/) -- [ApolloExtension](extensions/ApolloExtension/) -- [Array](extensions/Array/) -- [Bool](extensions/Bool/) -- [CacheReference](extensions/CacheReference/) -- [Dictionary](extensions/Dictionary/) -- [Double](extensions/Double/) -- [Float](extensions/Float/) -- [GraphQLError](extensions/GraphQLError/) -- [GraphQLMapConvertible](extensions/GraphQLMapConvertible/) -- [GraphQLMutation](extensions/GraphQLMutation/) -- [GraphQLOperation](extensions/GraphQLOperation/) -- [GraphQLQuery](extensions/GraphQLQuery/) -- [GraphQLSelectionSet](extensions/GraphQLSelectionSet/) -- [GraphQLSubscription](extensions/GraphQLSubscription/) -- [HTTPRequest](extensions/HTTPRequest/) -- [Int](extensions/Int/) -- [InterceptorProvider](extensions/InterceptorProvider/) -- [NSDictionary](extensions/NSDictionary/) -- [NSNull](extensions/NSNull/) -- [NetworkTransport](extensions/NetworkTransport/) -- [Optional](extensions/Optional/) -- [RawRepresentable](extensions/RawRepresentable/) -- [Record](extensions/Record/) -- [RecordSet](extensions/RecordSet/) -- [RequestBodyCreator](extensions/RequestBodyCreator/) -- [RequestChainNetworkTransport](extensions/RequestChainNetworkTransport/) -- [String](extensions/String/) -- [URL](extensions/URL/) - -## Typealiases - -- [CacheKey](typealiases/CacheKey/) -- [CacheKeyForObject](typealiases/CacheKeyForObject/) -- [DataLoader.BatchLoad](typealiases/DataLoader.BatchLoad/) -- [DidChangeKeysFunc](typealiases/DidChangeKeysFunc/) -- [GraphQLID](typealiases/GraphQLID/) -- [GraphQLMap](typealiases/GraphQLMap/) -- [GraphQLResultHandler](typealiases/GraphQLResultHandler/) -- [JSONObject](typealiases/JSONObject/) -- [JSONValue](typealiases/JSONValue/) -- [Record.Fields](typealiases/Record.Fields/) -- [Record.Value](typealiases/Record.Value/) -- [ResultMap](typealiases/ResultMap/) -- [URLSessionClient.Completion](typealiases/URLSessionClient.Completion/) -- [URLSessionClient.RawCompletion](typealiases/URLSessionClient.RawCompletion/) - -## Methods - -- [GraphQLVariable(__)](methods/GraphQLVariable(__)/) -- [unzip(__)](methods/unzip(__)/) -- [unzip(__)](methods/unzip(__)/) - -This file was generated by [SourceDocs](https://github.com/eneko/SourceDocs) \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/ApolloClient.md b/docs/source/api/Apollo/classes/ApolloClient.md deleted file mode 100644 index 854872f61f..0000000000 --- a/docs/source/api/Apollo/classes/ApolloClient.md +++ /dev/null @@ -1,52 +0,0 @@ -**CLASS** - -# `ApolloClient` - -```swift -public class ApolloClient -``` - -The `ApolloClient` class implements the core API for Apollo by conforming to `ApolloClientProtocol`. - -## Properties -### `store` - -```swift -public let store: ApolloStore -``` - -## Methods -### `init(networkTransport:store:)` - -```swift -public init(networkTransport: NetworkTransport, store: ApolloStore) -``` - -Creates a client with the specified network transport and store. - -- Parameters: - - networkTransport: A network transport used to send operations to a server. - - store: A store used as a local cache. Note that if the `NetworkTransport` or any of its dependencies takes a store, you should make sure the same store is passed here so that it can be cleared properly. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| networkTransport | A network transport used to send operations to a server. | -| store | A store used as a local cache. Note that if the `NetworkTransport` or any of its dependencies takes a store, you should make sure the same store is passed here so that it can be cleared properly. | - -### `init(url:)` - -```swift -public convenience init(url: URL) -``` - -Creates a client with a `RequestChainNetworkTransport` connecting to the specified URL. - -- Parameter url: The URL of a GraphQL server to connect to. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The URL of a GraphQL server to connect to. | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/ApolloStore.ReadTransaction.md b/docs/source/api/Apollo/classes/ApolloStore.ReadTransaction.md deleted file mode 100644 index 392e7aa282..0000000000 --- a/docs/source/api/Apollo/classes/ApolloStore.ReadTransaction.md +++ /dev/null @@ -1,22 +0,0 @@ -**CLASS** - -# `ApolloStore.ReadTransaction` - -```swift -public class ReadTransaction -``` - -## Methods -### `read(query:)` - -```swift -public func read(query: Query) throws -> Query.Data -``` - -### `readObject(ofType:withKey:variables:)` - -```swift -public func readObject(ofType type: SelectionSet.Type, - withKey key: CacheKey, - variables: GraphQLMap? = nil) throws -> SelectionSet -``` diff --git a/docs/source/api/Apollo/classes/ApolloStore.ReadWriteTransaction.md b/docs/source/api/Apollo/classes/ApolloStore.ReadWriteTransaction.md deleted file mode 100644 index b1640ed888..0000000000 --- a/docs/source/api/Apollo/classes/ApolloStore.ReadWriteTransaction.md +++ /dev/null @@ -1,82 +0,0 @@ -**CLASS** - -# `ApolloStore.ReadWriteTransaction` - -```swift -public final class ReadWriteTransaction: ReadTransaction -``` - -## Methods -### `update(query:_:)` - -```swift -public func update(query: Query, _ body: (inout Query.Data) throws -> Void) throws -``` - -### `updateObject(ofType:withKey:variables:_:)` - -```swift -public func updateObject(ofType type: SelectionSet.Type, - withKey key: CacheKey, - variables: GraphQLMap? = nil, - _ body: (inout SelectionSet) throws -> Void) throws -``` - -### `removeObject(for:)` - -```swift -public func removeObject(for key: CacheKey) throws -``` - -Removes the object for the specified cache key. Does not cascade -or allow removal of only certain fields. Does nothing if an object -does not exist for the given key. - -- Parameters: - - key: The cache key to remove the object for - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache key to remove the object for | - -### `removeObjects(matching:)` - -```swift -public func removeObjects(matching pattern: CacheKey) throws -``` - -Removes records with keys that match the specified pattern. This method will only -remove whole records, it does not perform cascading deletes. This means only the -records with matched keys will be removed, and not any references to them. Key -matching is case-insensitive. - -If you attempt to pass a cache path for a single field, this method will do nothing -since it won't be able to locate a record to remove based on that path. - -- Note: This method can be very slow depending on the number of records in the cache. -It is recommended that this method be called in a background queue. - -- Parameters: - - pattern: The pattern that will be applied to find matching keys. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pattern | The pattern that will be applied to find matching keys. | - -### `write(data:forQuery:)` - -```swift -public func write(data: Query.Data, forQuery query: Query) throws -``` - -### `write(object:withKey:variables:)` - -```swift -public func write(object: GraphQLSelectionSet, - withKey key: CacheKey, - variables: GraphQLMap? = nil) throws -``` diff --git a/docs/source/api/Apollo/classes/ApolloStore.md b/docs/source/api/Apollo/classes/ApolloStore.md deleted file mode 100644 index f09e165cfd..0000000000 --- a/docs/source/api/Apollo/classes/ApolloStore.md +++ /dev/null @@ -1,140 +0,0 @@ -**CLASS** - -# `ApolloStore` - -```swift -public final class ApolloStore -``` - -The `ApolloStore` class acts as a local cache for normalized GraphQL results. - -## Properties -### `cacheKeyForObject` - -```swift -public var cacheKeyForObject: CacheKeyForObject? -``` - -## Methods -### `init(cache:)` - -```swift -public init(cache: NormalizedCache = InMemoryNormalizedCache()) -``` - -Designated initializer - -- Parameter cache: An instance of `normalizedCache` to use to cache results. Defaults to an `InMemoryNormalizedCache`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| cache | An instance of `normalizedCache` to use to cache results. Defaults to an `InMemoryNormalizedCache`. | - -### `clearCache(callbackQueue:completion:)` - -```swift -public func clearCache(callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) -``` - -Clears the instance of the cache. Note that a cache can be shared across multiple `ApolloClient` objects, so clearing that underlying cache will clear it for all clients. - -- Parameters: - - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. - - completion: [optional] A completion block to be called after records are merged into the cache. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| callbackQueue | The queue to call the completion block on. Defaults to `DispatchQueue.main`. | -| completion | [optional] A completion block to be called after records are merged into the cache. | - -### `publish(records:identifier:callbackQueue:completion:)` - -```swift -public func publish(records: RecordSet, identifier: UUID? = nil, callbackQueue: DispatchQueue = .main, completion: ((Result) -> Void)? = nil) -``` - -Merges a `RecordSet` into the normalized cache. -- Parameters: - - records: The records to be merged into the cache. - - identifier: [optional] A unique identifier for the request that kicked off this change, - to assist in de-duping cache hits for watchers. - - callbackQueue: The queue to call the completion block on. Defaults to `DispatchQueue.main`. - - completion: [optional] A completion block to be called after records are merged into the cache. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| records | The records to be merged into the cache. | -| identifier | [optional] A unique identifier for the request that kicked off this change, to assist in de-duping cache hits for watchers. | -| callbackQueue | The queue to call the completion block on. Defaults to `DispatchQueue.main`. | -| completion | [optional] A completion block to be called after records are merged into the cache. | - -### `withinReadTransaction(_:callbackQueue:completion:)` - -```swift -public func withinReadTransaction(_ body: @escaping (ReadTransaction) throws -> T, - callbackQueue: DispatchQueue? = nil, - completion: ((Result) -> Void)? = nil) -``` - -Performs an operation within a read transaction - -- Parameters: - - body: The body of the operation to perform. - - callbackQueue: [optional] The callback queue to use to perform the completion block on. Will perform on the current queue if not provided. Defaults to nil. - - completion: [optional] The completion block to perform when the read transaction completes. Defaults to nil. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| body | The body of the operation to perform. | -| callbackQueue | [optional] The callback queue to use to perform the completion block on. Will perform on the current queue if not provided. Defaults to nil. | -| completion | [optional] The completion block to perform when the read transaction completes. Defaults to nil. | - -### `withinReadWriteTransaction(_:callbackQueue:completion:)` - -```swift -public func withinReadWriteTransaction(_ body: @escaping (ReadWriteTransaction) throws -> T, - callbackQueue: DispatchQueue? = nil, - completion: ((Result) -> Void)? = nil) -``` - -Performs an operation within a read-write transaction - -- Parameters: - - body: The body of the operation to perform - - callbackQueue: [optional] a callback queue to perform the action on. Will perform on the current queue if not provided. Defaults to nil. - - completion: [optional] a completion block to fire when the read-write transaction completes. Defaults to nil. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| body | The body of the operation to perform | -| callbackQueue | [optional] a callback queue to perform the action on. Will perform on the current queue if not provided. Defaults to nil. | -| completion | [optional] a completion block to fire when the read-write transaction completes. Defaults to nil. | - -### `load(query:callbackQueue:resultHandler:)` - -```swift -public func load(query: Operation, callbackQueue: DispatchQueue? = nil, resultHandler: @escaping GraphQLResultHandler) -``` - -Loads the results for the given query from the cache. - -- Parameters: - - query: The query to load results for - - resultHandler: The completion handler to execute on success or error - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| query | The query to load results for | -| resultHandler | The completion handler to execute on success or error | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/DefaultInterceptorProvider.md b/docs/source/api/Apollo/classes/DefaultInterceptorProvider.md deleted file mode 100644 index 4567088371..0000000000 --- a/docs/source/api/Apollo/classes/DefaultInterceptorProvider.md +++ /dev/null @@ -1,63 +0,0 @@ -**CLASS** - -# `DefaultInterceptorProvider` - -```swift -open class DefaultInterceptorProvider: InterceptorProvider -``` - -The default interceptor provider for typescript-generated code - -## Methods -### `init(client:shouldInvalidateClientOnDeinit:store:)` - -```swift -public init(client: URLSessionClient = URLSessionClient(), - shouldInvalidateClientOnDeinit: Bool = true, - store: ApolloStore) -``` - -Designated initializer - -- Parameters: - - client: The `URLSessionClient` to use. Defaults to the default setup. - - shouldInvalidateClientOnDeinit: If the passed-in client should be invalidated when this interceptor provider is deinitialized. If you are recreating the `URLSessionClient` every time you create a new provider, you should do this to prevent memory leaks. Defaults to true, since by default we provide a `URLSessionClient` to new instances. - - store: The `ApolloStore` to use when reading from or writing to the cache. Make sure you pass the same store to the `ApolloClient` instance you're planning to use. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| client | The `URLSessionClient` to use. Defaults to the default setup. | -| shouldInvalidateClientOnDeinit | If the passed-in client should be invalidated when this interceptor provider is deinitialized. If you are recreating the `URLSessionClient` every time you create a new provider, you should do this to prevent memory leaks. Defaults to true, since by default we provide a `URLSessionClient` to new instances. | -| store | The `ApolloStore` to use when reading from or writing to the cache. Make sure you pass the same store to the `ApolloClient` instance you’re planning to use. | - -### `deinit` - -```swift -deinit -``` - -### `interceptors(for:)` - -```swift -open func interceptors(for operation: Operation) -> [ApolloInterceptor] -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to provide interceptors for | - -### `additionalErrorInterceptor(for:)` - -```swift -open func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to provide an additional error interceptor for | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/EmptyCancellable.md b/docs/source/api/Apollo/classes/EmptyCancellable.md deleted file mode 100644 index 0e24e5d808..0000000000 --- a/docs/source/api/Apollo/classes/EmptyCancellable.md +++ /dev/null @@ -1,22 +0,0 @@ -**CLASS** - -# `EmptyCancellable` - -```swift -public final class EmptyCancellable: Cancellable -``` - -A class to return when we need to bail out of something which still needs to return `Cancellable`. - -## Methods -### `init()` - -```swift -public init() -``` - -### `cancel()` - -```swift -public func cancel() -``` diff --git a/docs/source/api/Apollo/classes/GraphQLQueryWatcher.md b/docs/source/api/Apollo/classes/GraphQLQueryWatcher.md deleted file mode 100644 index c1d68f0812..0000000000 --- a/docs/source/api/Apollo/classes/GraphQLQueryWatcher.md +++ /dev/null @@ -1,61 +0,0 @@ -**CLASS** - -# `GraphQLQueryWatcher` - -```swift -public final class GraphQLQueryWatcher: Cancellable, ApolloStoreSubscriber -``` - -A `GraphQLQueryWatcher` is responsible for watching the store, and calling the result handler with a new result whenever any of the data the previous result depends on changes. - -NOTE: The store retains the watcher while subscribed. You must call `cancel()` on your query watcher when you no longer need results. Failure to call `cancel()` before releasing your reference to the returned watcher will result in a memory leak. - -## Properties -### `query` - -```swift -public let query: Query -``` - -## Methods -### `init(client:query:callbackQueue:resultHandler:)` - -```swift -public init(client: ApolloClientProtocol, - query: Query, - callbackQueue: DispatchQueue = .main, - resultHandler: @escaping GraphQLResultHandler) -``` - -Designated initializer - -- Parameters: - - client: The client protocol to pass in. - - query: The query to watch. - - callbackQueue: The queue for the result handler. Defaults to the main queue. - - resultHandler: The result handler to call with changes. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| client | The client protocol to pass in. | -| query | The query to watch. | -| callbackQueue | The queue for the result handler. Defaults to the main queue. | -| resultHandler | The result handler to call with changes. | - -### `refetch(cachePolicy:)` - -```swift -public func refetch(cachePolicy: CachePolicy = .fetchIgnoringCacheData) -``` - -Refetch a query from the server. - -### `cancel()` - -```swift -public func cancel() -``` - -Cancel any in progress fetching operations and unsubscribe from the store. diff --git a/docs/source/api/Apollo/classes/GraphQLResponse.md b/docs/source/api/Apollo/classes/GraphQLResponse.md deleted file mode 100644 index 596c492be7..0000000000 --- a/docs/source/api/Apollo/classes/GraphQLResponse.md +++ /dev/null @@ -1,53 +0,0 @@ -**CLASS** - -# `GraphQLResponse` - -```swift -public final class GraphQLResponse -``` - -Represents a GraphQL response received from a server. - -## Properties -### `body` - -```swift -public let body: JSONObject -``` - -## Methods -### `init(operation:body:)` - -```swift -public init(operation: Operation, body: JSONObject) where Operation.Data == Data -``` - -### `parseResult(cacheKeyForObject:)` - -```swift -public func parseResult(cacheKeyForObject: CacheKeyForObject? = nil) throws -> (GraphQLResult, RecordSet?) -``` - -Parses a response into a `GraphQLResult` and a `RecordSet`. -The result can be sent to a completion block for a request. -The `RecordSet` can be merged into a local cache. -- Parameter cacheKeyForObject: See `CacheKeyForObject` -- Returns: A `GraphQLResult` and a `RecordSet`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| cacheKeyForObject | See `CacheKeyForObject` | - -### `parseErrorsOnlyFast()` - -```swift -public func parseErrorsOnlyFast() -> [GraphQLError]? -``` - -### `parseResultFast()` - -```swift -public func parseResultFast() throws -> GraphQLResult -``` diff --git a/docs/source/api/Apollo/classes/HTTPRequest.md b/docs/source/api/Apollo/classes/HTTPRequest.md deleted file mode 100644 index 0245dbb880..0000000000 --- a/docs/source/api/Apollo/classes/HTTPRequest.md +++ /dev/null @@ -1,112 +0,0 @@ -**CLASS** - -# `HTTPRequest` - -```swift -open class HTTPRequest -``` - -Encapsulation of all information about a request before it hits the network - -## Properties -### `graphQLEndpoint` - -```swift -open var graphQLEndpoint: URL -``` - -The endpoint to make a GraphQL request to - -### `operation` - -```swift -open var operation: Operation -``` - -The GraphQL Operation to execute - -### `additionalHeaders` - -```swift -open var additionalHeaders: [String: String] -``` - -Any additional headers you wish to add by default to this request - -### `cachePolicy` - -```swift -open var cachePolicy: CachePolicy -``` - -The `CachePolicy` to use for this request. - -### `contextIdentifier` - -```swift -public let contextIdentifier: UUID? -``` - -[optional] A unique identifier for this request, to help with deduping cache hits for watchers. - -## Methods -### `init(graphQLEndpoint:operation:contextIdentifier:contentType:clientName:clientVersion:additionalHeaders:cachePolicy:)` - -```swift -public init(graphQLEndpoint: URL, - operation: Operation, - contextIdentifier: UUID? = nil, - contentType: String, - clientName: String, - clientVersion: String, - additionalHeaders: [String: String], - cachePolicy: CachePolicy = .default) -``` - -Designated Initializer - -- Parameters: - - graphQLEndpoint: The endpoint to make a GraphQL request to - - operation: The GraphQL Operation to execute - - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. - - contentType: The `Content-Type` header's value. Should usually be set for you by a subclass. - - clientName: The name of the client to send with the `"apollographql-client-name"` header - - clientVersion: The version of the client to send with the `"apollographql-client-version"` header - - additionalHeaders: Any additional headers you wish to add by default to this request. - - cachePolicy: The `CachePolicy` to use for this request. Defaults to the `.default` policy - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| graphQLEndpoint | The endpoint to make a GraphQL request to | -| operation | The GraphQL Operation to execute | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. | -| contentType | The `Content-Type` header’s value. Should usually be set for you by a subclass. | -| clientName | The name of the client to send with the `"apollographql-client-name"` header | -| clientVersion | The version of the client to send with the `"apollographql-client-version"` header | -| additionalHeaders | Any additional headers you wish to add by default to this request. | -| cachePolicy | The `CachePolicy` to use for this request. Defaults to the `.default` policy | - -### `addHeader(name:value:)` - -```swift -open func addHeader(name: String, value: String) -``` - -### `updateContentType(to:)` - -```swift -open func updateContentType(to contentType: String) -``` - -### `toURLRequest()` - -```swift -open func toURLRequest() throws -> URLRequest -``` - -Converts this object to a fully fleshed-out `URLRequest` - -- Throws: Any error in creating the request -- Returns: The URL request, ready to send to your server. diff --git a/docs/source/api/Apollo/classes/HTTPResponse.md b/docs/source/api/Apollo/classes/HTTPResponse.md deleted file mode 100644 index fcf0600de6..0000000000 --- a/docs/source/api/Apollo/classes/HTTPResponse.md +++ /dev/null @@ -1,67 +0,0 @@ -**CLASS** - -# `HTTPResponse` - -```swift -public class HTTPResponse -``` - -Data about a response received by an HTTP request. - -## Properties -### `httpResponse` - -```swift -public var httpResponse: HTTPURLResponse -``` - -The `HTTPURLResponse` received from the URL loading system - -### `rawData` - -```swift -public var rawData: Data -``` - -The raw data received from the URL loading system - -### `parsedResponse` - -```swift -public var parsedResponse: GraphQLResult? -``` - -[optional] The data as parsed into a `GraphQLResult`, which can eventually be returned to the UI. Will be nil if not yet parsed. - -### `legacyResponse` - -```swift -public var legacyResponse: GraphQLResponse? = nil -``` - -[optional] The data as parsed into a `GraphQLResponse` for legacy caching purposes. If you're not using the `JSONResponseParsingInterceptor`, you probably shouldn't be using this property. -**NOTE:** This property will be removed when the transition to the Swift Codegen is complete. - -## Methods -### `init(response:rawData:parsedResponse:)` - -```swift -public init(response: HTTPURLResponse, - rawData: Data, - parsedResponse: GraphQLResult?) -``` - -Designated initializer - -- Parameters: - - response: The `HTTPURLResponse` received from the server. - - rawData: The raw, unparsed data received from the server. - - parsedResponse: [optional] The response parsed into the `ParsedValue` type. Will be nil if not yet parsed, or if parsing failed. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| response | The `HTTPURLResponse` received from the server. | -| rawData | The raw, unparsed data received from the server. | -| parsedResponse | [optional] The response parsed into the `ParsedValue` type. Will be nil if not yet parsed, or if parsing failed. | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/InMemoryNormalizedCache.md b/docs/source/api/Apollo/classes/InMemoryNormalizedCache.md deleted file mode 100644 index d815fe5d02..0000000000 --- a/docs/source/api/Apollo/classes/InMemoryNormalizedCache.md +++ /dev/null @@ -1,68 +0,0 @@ -**CLASS** - -# `InMemoryNormalizedCache` - -```swift -public final class InMemoryNormalizedCache: NormalizedCache -``` - -## Methods -### `init(records:)` - -```swift -public init(records: RecordSet = RecordSet()) -``` - -### `loadRecords(forKeys:)` - -```swift -public func loadRecords(forKeys keys: Set) throws -> [CacheKey: Record] -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache keys to load data for | - -### `removeRecord(for:)` - -```swift -public func removeRecord(for key: CacheKey) throws -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache key to remove the record for | - -### `merge(records:)` - -```swift -public func merge(records newRecords: RecordSet) throws -> Set -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| records | The set of records to merge. | - -### `removeRecords(matching:)` - -```swift -public func removeRecords(matching pattern: CacheKey) throws -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pattern | The pattern that will be applied to find matching keys. | - -### `clear()` - -```swift -public func clear() -``` diff --git a/docs/source/api/Apollo/classes/JSONRequest.md b/docs/source/api/Apollo/classes/JSONRequest.md deleted file mode 100644 index f6a5a1c5e4..0000000000 --- a/docs/source/api/Apollo/classes/JSONRequest.md +++ /dev/null @@ -1,112 +0,0 @@ -**CLASS** - -# `JSONRequest` - -```swift -open class JSONRequest: HTTPRequest -``` - -A request which sends JSON related to a GraphQL operation. - -## Properties -### `requestBodyCreator` - -```swift -public let requestBodyCreator: RequestBodyCreator -``` - -### `autoPersistQueries` - -```swift -public let autoPersistQueries: Bool -``` - -### `useGETForQueries` - -```swift -public let useGETForQueries: Bool -``` - -### `useGETForPersistedQueryRetry` - -```swift -public let useGETForPersistedQueryRetry: Bool -``` - -### `isPersistedQueryRetry` - -```swift -public var isPersistedQueryRetry = false -``` - -### `body` - -```swift -public var body: GraphQLMap -``` - -### `serializationFormat` - -```swift -public let serializationFormat = JSONSerializationFormat.self -``` - -### `sendOperationIdentifier` - -```swift -open var sendOperationIdentifier: Bool -``` - -## Methods -### `init(operation:graphQLEndpoint:contextIdentifier:clientName:clientVersion:additionalHeaders:cachePolicy:autoPersistQueries:useGETForQueries:useGETForPersistedQueryRetry:requestBodyCreator:)` - -```swift -public init(operation: Operation, - graphQLEndpoint: URL, - contextIdentifier: UUID? = nil, - clientName: String, - clientVersion: String, - additionalHeaders: [String: String] = [:], - cachePolicy: CachePolicy = .default, - autoPersistQueries: Bool = false, - useGETForQueries: Bool = false, - useGETForPersistedQueryRetry: Bool = false, - requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator()) -``` - -Designated initializer - -- Parameters: - - operation: The GraphQL Operation to execute - - graphQLEndpoint: The endpoint to make a GraphQL request to - - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. - - clientName: The name of the client to send with the `"apollographql-client-name"` header - - clientVersion: The version of the client to send with the `"apollographql-client-version"` header - - additionalHeaders: Any additional headers you wish to add by default to this request - - cachePolicy: The `CachePolicy` to use for this request. - - autoPersistQueries: `true` if Auto-Persisted Queries should be used. Defaults to `false`. - - useGETForQueries: `true` if Queries should use `GET` instead of `POST` for HTTP requests. Defaults to `false`. - - useGETForPersistedQueryRetry: `true` if when an Auto-Persisted query is retried, it should use `GET` instead of `POST` to send the query. Defaults to `false`. - - requestBodyCreator: An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The GraphQL Operation to execute | -| graphQLEndpoint | The endpoint to make a GraphQL request to | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. | -| clientName | The name of the client to send with the `"apollographql-client-name"` header | -| clientVersion | The version of the client to send with the `"apollographql-client-version"` header | -| additionalHeaders | Any additional headers you wish to add by default to this request | -| cachePolicy | The `CachePolicy` to use for this request. | -| autoPersistQueries | `true` if Auto-Persisted Queries should be used. Defaults to `false`. | -| useGETForQueries | `true` if Queries should use `GET` instead of `POST` for HTTP requests. Defaults to `false`. | -| useGETForPersistedQueryRetry | `true` if when an Auto-Persisted query is retried, it should use `GET` instead of `POST` to send the query. Defaults to `false`. | -| requestBodyCreator | An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation. | - -### `toURLRequest()` - -```swift -open override func toURLRequest() throws -> URLRequest -``` diff --git a/docs/source/api/Apollo/classes/JSONSerializationFormat.md b/docs/source/api/Apollo/classes/JSONSerializationFormat.md deleted file mode 100644 index 1061a39a81..0000000000 --- a/docs/source/api/Apollo/classes/JSONSerializationFormat.md +++ /dev/null @@ -1,20 +0,0 @@ -**CLASS** - -# `JSONSerializationFormat` - -```swift -public final class JSONSerializationFormat -``` - -## Methods -### `serialize(value:)` - -```swift -public class func serialize(value: JSONEncodable) throws -> Data -``` - -### `deserialize(data:)` - -```swift -public class func deserialize(data: Data) throws -> JSONValue -``` diff --git a/docs/source/api/Apollo/classes/MaxRetryInterceptor.md b/docs/source/api/Apollo/classes/MaxRetryInterceptor.md deleted file mode 100644 index e023436313..0000000000 --- a/docs/source/api/Apollo/classes/MaxRetryInterceptor.md +++ /dev/null @@ -1,45 +0,0 @@ -**CLASS** - -# `MaxRetryInterceptor` - -```swift -public class MaxRetryInterceptor: ApolloInterceptor -``` - -An interceptor to enforce a maximum number of retries of any `HTTPRequest` - -## Methods -### `init(maxRetriesAllowed:)` - -```swift -public init(maxRetriesAllowed: Int = 3) -``` - -Designated initializer. - -- Parameter maxRetriesAllowed: How many times a query can be retried, in addition to the initial attempt before - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| maxRetriesAllowed | How many times a query can be retried, in addition to the initial attempt before | - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/MultipartFormData.md b/docs/source/api/Apollo/classes/MultipartFormData.md deleted file mode 100644 index b98bbb1c5c..0000000000 --- a/docs/source/api/Apollo/classes/MultipartFormData.md +++ /dev/null @@ -1,125 +0,0 @@ -**CLASS** - -# `MultipartFormData` - -```swift -public class MultipartFormData -``` - -A helper for building out multi-part form data for upload - -## Properties -### `boundary` - -```swift -public let boundary: String -``` - -## Methods -### `init(boundary:)` - -```swift -public init(boundary: String) -``` - -Designated initializer - -- Parameter boundary: The boundary to use between parts of the form. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| boundary | The boundary to use between parts of the form. | - -### `init()` - -```swift -public convenience init() -``` - -Convenience initializer which uses a pre-defined boundary - -### `appendPart(string:name:)` - -```swift -public func appendPart(string: String, name: String) throws -``` - -Appends the passed-in string as a part of the body. - -- Parameters: - - string: The string to append - - name: The name of the part to pass along to the server - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| string | The string to append | -| name | The name of the part to pass along to the server | - -### `appendPart(data:name:contentType:filename:)` - -```swift -public func appendPart(data: Data, - name: String, - contentType: String? = nil, - filename: String? = nil) -``` - -Appends the passed-in data as a part of the body. - -- Parameters: - - data: The data to append - - name: The name of the part to pass along to the server - - contentType: [optional] The content type of this part. Defaults to nil. - - filename: [optional] The name of the file for this part. Defaults to nil. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| data | The data to append | -| name | The name of the part to pass along to the server | -| contentType | [optional] The content type of this part. Defaults to nil. | -| filename | [optional] The name of the file for this part. Defaults to nil. | - -### `appendPart(inputStream:contentLength:name:contentType:filename:)` - -```swift -public func appendPart(inputStream: InputStream, - contentLength: UInt64, - name: String, - contentType: String? = nil, - filename: String? = nil) -``` - -Appends the passed-in input stream as a part of the body. - -- Parameters: - - inputStream: The input stream to append. - - contentLength: Length of the input stream data. - - name: The name of the part to pass along to the server - - contentType: [optional] The content type of this part. Defaults to nil. - - filename: [optional] The name of the file for this part. Defaults to nil. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| inputStream | The input stream to append. | -| contentLength | Length of the input stream data. | -| name | The name of the part to pass along to the server | -| contentType | [optional] The content type of this part. Defaults to nil. | -| filename | [optional] The name of the file for this part. Defaults to nil. | - -### `encode()` - -```swift -public func encode() throws -> Data -``` - -Encodes everything into the final form data to send to a server. - -- Returns: The final form data to send to a server. diff --git a/docs/source/api/Apollo/classes/NetworkFetchInterceptor.md b/docs/source/api/Apollo/classes/NetworkFetchInterceptor.md deleted file mode 100644 index a4fda369ae..0000000000 --- a/docs/source/api/Apollo/classes/NetworkFetchInterceptor.md +++ /dev/null @@ -1,51 +0,0 @@ -**CLASS** - -# `NetworkFetchInterceptor` - -```swift -public class NetworkFetchInterceptor: ApolloInterceptor, Cancellable -``` - -An interceptor which actually fetches data from the network. - -## Methods -### `init(client:)` - -```swift -public init(client: URLSessionClient) -``` - -Designated initializer. - -- Parameter client: The `URLSessionClient` to use to fetch data - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| client | The `URLSessionClient` to use to fetch data | - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | - -### `cancel()` - -```swift -public func cancel() -``` diff --git a/docs/source/api/Apollo/classes/RequestChain.md b/docs/source/api/Apollo/classes/RequestChain.md deleted file mode 100644 index 26e9ea1e82..0000000000 --- a/docs/source/api/Apollo/classes/RequestChain.md +++ /dev/null @@ -1,172 +0,0 @@ -**CLASS** - -# `RequestChain` - -```swift -public class RequestChain: Cancellable -``` - -A chain that allows a single network request to be created and executed. - -## Properties -### `isNotCancelled` - -```swift -public var isNotCancelled: Bool -``` - -Checks the underlying value of `isCancelled`. Set up like this for better readability in `guard` statements - -### `additionalErrorHandler` - -```swift -public var additionalErrorHandler: ApolloErrorInterceptor? -``` - -Something which allows additional error handling to occur when some kind of error has happened. - -## Methods -### `init(interceptors:callbackQueue:)` - -```swift -public init(interceptors: [ApolloInterceptor], - callbackQueue: DispatchQueue = .main) -``` - -Creates a chain with the given interceptor array. - -- Parameters: - - interceptors: The array of interceptors to use. - - callbackQueue: The `DispatchQueue` to call back on when an error or result occurs. Defaults to `.main`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| interceptors | The array of interceptors to use. | -| callbackQueue | The `DispatchQueue` to call back on when an error or result occurs. Defaults to `.main`. | - -### `kickoff(request:completion:)` - -```swift -public func kickoff( - request: HTTPRequest, - completion: @escaping (Result, Error>) -> Void) -``` - -Kicks off the request from the beginning of the interceptor array. - -- Parameters: - - request: The request to send. - - completion: The completion closure to call when the request has completed. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | The request to send. | -| completion | The completion closure to call when the request has completed. | - -### `proceedAsync(request:response:completion:)` - -```swift -public func proceedAsync( - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -Proceeds to the next interceptor in the array. - -- Parameters: - - request: The in-progress request object - - response: [optional] The in-progress response object, if received yet - - completion: The completion closure to call when data has been processed and should be returned to the UI. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | The in-progress request object | -| response | [optional] The in-progress response object, if received yet | -| completion | The completion closure to call when data has been processed and should be returned to the UI. | - -### `cancel()` - -```swift -public func cancel() -``` - -Cancels the entire chain of interceptors. - -### `retry(request:completion:)` - -```swift -public func retry( - request: HTTPRequest, - completion: @escaping (Result, Error>) -> Void) -``` - -Restarts the request starting from the first interceptor. - -- Parameters: - - request: The request to retry - - completion: The completion closure to call when the request has completed. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | The request to retry | -| completion | The completion closure to call when the request has completed. | - -### `handleErrorAsync(_:request:response:completion:)` - -```swift -public func handleErrorAsync( - _ error: Error, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -Handles the error by returning it on the appropriate queue, or by applying an additional error interceptor if one has been provided. - -- Parameters: - - error: The error to handle - - request: The request, as far as it has been constructed. - - response: The response, as far as it has been constructed. - - completion: The completion closure to call when work is complete. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| error | The error to handle | -| request | The request, as far as it has been constructed. | -| response | The response, as far as it has been constructed. | -| completion | The completion closure to call when work is complete. | - -### `returnValueAsync(for:value:completion:)` - -```swift -public func returnValueAsync( - for request: HTTPRequest, - value: GraphQLResult, - completion: @escaping (Result, Error>) -> Void) -``` - -Handles a resulting value by returning it on the appropriate queue. - -- Parameters: - - request: The request, as far as it has been constructed. - - value: The value to be returned - - completion: The completion closure to call when work is complete. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | The request, as far as it has been constructed. | -| value | The value to be returned | -| completion | The completion closure to call when work is complete. | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/RequestChainNetworkTransport.md b/docs/source/api/Apollo/classes/RequestChainNetworkTransport.md deleted file mode 100644 index 9a608d2ab6..0000000000 --- a/docs/source/api/Apollo/classes/RequestChainNetworkTransport.md +++ /dev/null @@ -1,155 +0,0 @@ -**CLASS** - -# `RequestChainNetworkTransport` - -```swift -open class RequestChainNetworkTransport: NetworkTransport -``` - -An implementation of `NetworkTransport` which creates a `RequestChain` object -for each item sent through it. - -## Properties -### `endpointURL` - -```swift -public let endpointURL: URL -``` - -The GraphQL endpoint URL to use. - -### `additionalHeaders` - -```swift -public private(set) var additionalHeaders: [String: String] -``` - -Any additional headers that should be automatically added to every request. - -### `autoPersistQueries` - -```swift -public let autoPersistQueries: Bool -``` - -Set to `true` if Automatic Persisted Queries should be used to send a query hash instead of the full query body by default. - -### `useGETForQueries` - -```swift -public let useGETForQueries: Bool -``` - -Set to `true` if you want to use `GET` instead of `POST` for queries, for example to take advantage of a CDN. - -### `useGETForPersistedQueryRetry` - -```swift -public let useGETForPersistedQueryRetry: Bool -``` - -Set to `true` to use `GET` instead of `POST` for a retry of a persisted query. - -### `requestBodyCreator` - -```swift -public var requestBodyCreator: RequestBodyCreator -``` - -The `RequestBodyCreator` object to use to build your `URLRequest`. - -### `clientName` - -```swift -public var clientName = RequestChainNetworkTransport.defaultClientName -``` - -### `clientVersion` - -```swift -public var clientVersion = RequestChainNetworkTransport.defaultClientVersion -``` - -## Methods -### `init(interceptorProvider:endpointURL:additionalHeaders:autoPersistQueries:requestBodyCreator:useGETForQueries:useGETForPersistedQueryRetry:)` - -```swift -public init(interceptorProvider: InterceptorProvider, - endpointURL: URL, - additionalHeaders: [String: String] = [:], - autoPersistQueries: Bool = false, - requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator(), - useGETForQueries: Bool = false, - useGETForPersistedQueryRetry: Bool = false) -``` - -Designated initializer - -- Parameters: - - interceptorProvider: The interceptor provider to use when constructing chains for a request - - endpointURL: The GraphQL endpoint URL to use. - - additionalHeaders: Any additional headers that should be automatically added to every request. Defaults to an empty dictionary. - - autoPersistQueries: Pass `true` if Automatic Persisted Queries should be used to send a query hash instead of the full query body by default. Defaults to `false`. - - requestBodyCreator: The `RequestBodyCreator` object to use to build your `URLRequest`. Defaults to the provided `ApolloRequestBodyCreator` implementation. - - useGETForQueries: Pass `true` if you want to use `GET` instead of `POST` for queries, for example to take advantage of a CDN. Defaults to `false`. - - useGETForPersistedQueryRetry: Pass `true` to use `GET` instead of `POST` for a retry of a persisted query. Defaults to `false`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| interceptorProvider | The interceptor provider to use when constructing chains for a request | -| endpointURL | The GraphQL endpoint URL to use. | -| additionalHeaders | Any additional headers that should be automatically added to every request. Defaults to an empty dictionary. | -| autoPersistQueries | Pass `true` if Automatic Persisted Queries should be used to send a query hash instead of the full query body by default. Defaults to `false`. | -| requestBodyCreator | The `RequestBodyCreator` object to use to build your `URLRequest`. Defaults to the provided `ApolloRequestBodyCreator` implementation. | -| useGETForQueries | Pass `true` if you want to use `GET` instead of `POST` for queries, for example to take advantage of a CDN. Defaults to `false`. | -| useGETForPersistedQueryRetry | Pass `true` to use `GET` instead of `POST` for a retry of a persisted query. Defaults to `false`. | - -### `constructRequest(for:cachePolicy:contextIdentifier:)` - -```swift -open func constructRequest( - for operation: Operation, - cachePolicy: CachePolicy, - contextIdentifier: UUID? = nil) -> HTTPRequest -``` - -Constructs a default (ie, non-multipart) GraphQL request. - -Override this method if you need to use a custom subclass of `HTTPRequest`. - -- Parameters: - - operation: The operation to create the request for - - cachePolicy: The `CachePolicy` to use when creating the request - - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. -- Returns: The constructed request. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to create the request for | -| cachePolicy | The `CachePolicy` to use when creating the request | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. | - -### `send(operation:cachePolicy:contextIdentifier:callbackQueue:completionHandler:)` - -```swift -public func send( - operation: Operation, - cachePolicy: CachePolicy = .default, - contextIdentifier: UUID? = nil, - callbackQueue: DispatchQueue = .main, - completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send. | -| cachePolicy | The `CachePolicy` to use making this request. | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | A closure to call when a request completes. On `success` will contain the response received from the server. On `failure` will contain the error which occurred. | \ No newline at end of file diff --git a/docs/source/api/Apollo/classes/TaskData.md b/docs/source/api/Apollo/classes/TaskData.md deleted file mode 100644 index 606e221627..0000000000 --- a/docs/source/api/Apollo/classes/TaskData.md +++ /dev/null @@ -1,22 +0,0 @@ -**CLASS** - -# `TaskData` - -```swift -public class TaskData -``` - -A wrapper for data about a particular task handled by `URLSessionClient` - -## Properties -### `rawCompletion` - -```swift -public let rawCompletion: URLSessionClient.RawCompletion? -``` - -### `completionBlock` - -```swift -public let completionBlock: URLSessionClient.Completion -``` diff --git a/docs/source/api/Apollo/classes/URLSessionClient.md b/docs/source/api/Apollo/classes/URLSessionClient.md deleted file mode 100644 index 94b6a55712..0000000000 --- a/docs/source/api/Apollo/classes/URLSessionClient.md +++ /dev/null @@ -1,252 +0,0 @@ -**CLASS** - -# `URLSessionClient` - -```swift -open class URLSessionClient: NSObject, URLSessionDelegate, URLSessionTaskDelegate, URLSessionDataDelegate -``` - -A class to handle URL Session calls that will support background execution, -but still (mostly) use callbacks for its primary method of communication. - -**NOTE:** Delegate methods implemented here are not documented inline because -Apple has their own documentation for them. Please consult Apple's -documentation for how the delegate methods work and what needs to be overridden -and handled within your app, particularly in regards to what needs to be called -when for background sessions. - -## Properties -### `session` - -```swift -open private(set) var session: URLSession! -``` - -The raw URLSession being used for this client - -## Methods -### `init(sessionConfiguration:callbackQueue:)` - -```swift -public init(sessionConfiguration: URLSessionConfiguration = .default, - callbackQueue: OperationQueue? = .main) -``` - -Designated initializer. - -- Parameters: - - sessionConfiguration: The `URLSessionConfiguration` to use to set up the URL session. - - callbackQueue: [optional] The `OperationQueue` to tell the URL session to call back to this class on, which will in turn call back to your class. Defaults to `.main`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| sessionConfiguration | The `URLSessionConfiguration` to use to set up the URL session. | -| callbackQueue | [optional] The `OperationQueue` to tell the URL session to call back to this class on, which will in turn call back to your class. Defaults to `.main`. | - -### `invalidate()` - -```swift -public func invalidate() -``` - -Cleans up and invalidates everything related to this session client. - -NOTE: This must be called from the `deinit` of anything holding onto this client in order to break a retain cycle with the delegate. - -### `clear(task:)` - -```swift -open func clear(task identifier: Int) -``` - -Clears underlying dictionaries of any data related to a particular task identifier. - -- Parameter identifier: The identifier of the task to clear. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| identifier | The identifier of the task to clear. | - -### `clearAllTasks()` - -```swift -open func clearAllTasks() -``` - -Clears underlying dictionaries of any data related to all tasks. - -Mostly useful for cleanup and/or after invalidation of the `URLSession`. - -### `sendRequest(_:rawTaskCompletionHandler:completion:)` - -```swift -open func sendRequest(_ request: URLRequest, - rawTaskCompletionHandler: RawCompletion? = nil, - completion: @escaping Completion) -> URLSessionTask -``` - -The main method to perform a request. - -- Parameters: - - request: The request to perform. - - rawTaskCompletionHandler: [optional] A completion handler to call once the raw task is done, so if an Error requires access to the headers, the user can still access these. - - completion: A completion handler to call when the task has either completed successfully or failed. - -- Returns: The created URLSession task, already resumed, because nobody ever remembers to call `resume()`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | The request to perform. | -| rawTaskCompletionHandler | [optional] A completion handler to call once the raw task is done, so if an Error requires access to the headers, the user can still access these. | -| completion | A completion handler to call when the task has either completed successfully or failed. | - -### `cancel(task:)` - -```swift -open func cancel(task: URLSessionTask) -``` - -Cancels a given task and clears out its underlying data. - -NOTE: You will not receive any kind of "This was cancelled" error when this is called. - -- Parameter task: The task you wish to cancel. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| task | The task you wish to cancel. | - -### `urlSession(_:didBecomeInvalidWithError:)` - -```swift -open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) -``` - -### `urlSession(_:task:didFinishCollecting:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - didFinishCollecting metrics: URLSessionTaskMetrics) -``` - -### `urlSession(_:didReceive:completionHandler:)` - -```swift -open func urlSession(_ session: URLSession, - didReceive challenge: URLAuthenticationChallenge, - completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -``` - -### `urlSessionDidFinishEvents(forBackgroundURLSession:)` - -### `urlSession(_:task:didReceive:completionHandler:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - didReceive challenge: URLAuthenticationChallenge, - completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -``` - -### `urlSession(_:taskIsWaitingForConnectivity:)` - -```swift -open func urlSession(_ session: URLSession, - taskIsWaitingForConnectivity task: URLSessionTask) -``` - -### `urlSession(_:task:didCompleteWithError:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - didCompleteWithError error: Error?) -``` - -### `urlSession(_:task:needNewBodyStream:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) -``` - -### `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - didSendBodyData bytesSent: Int64, - totalBytesSent: Int64, - totalBytesExpectedToSend: Int64) -``` - -### `urlSession(_:task:willBeginDelayedRequest:completionHandler:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - willBeginDelayedRequest request: URLRequest, - completionHandler: @escaping (URLSession.DelayedRequestDisposition, URLRequest?) -> Void) -``` - -### `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` - -```swift -open func urlSession(_ session: URLSession, - task: URLSessionTask, - willPerformHTTPRedirection response: HTTPURLResponse, - newRequest request: URLRequest, - completionHandler: @escaping (URLRequest?) -> Void) -``` - -### `urlSession(_:dataTask:didReceive:)` - -```swift -open func urlSession(_ session: URLSession, - dataTask: URLSessionDataTask, - didReceive data: Data) -``` - -### `urlSession(_:dataTask:didBecome:)` - -```swift -open func urlSession(_ session: URLSession, - dataTask: URLSessionDataTask, - didBecome streamTask: URLSessionStreamTask) -``` - -### `urlSession(_:dataTask:didBecome:)` - -```swift -open func urlSession(_ session: URLSession, - dataTask: URLSessionDataTask, - didBecome downloadTask: URLSessionDownloadTask) -``` - -### `urlSession(_:dataTask:willCacheResponse:completionHandler:)` - -```swift -open func urlSession(_ session: URLSession, - dataTask: URLSessionDataTask, - willCacheResponse proposedResponse: CachedURLResponse, - completionHandler: @escaping (CachedURLResponse?) -> Void) -``` - -### `urlSession(_:dataTask:didReceive:completionHandler:)` - -```swift -open func urlSession(_ session: URLSession, - dataTask: URLSessionDataTask, - didReceive response: URLResponse, - completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) -``` diff --git a/docs/source/api/Apollo/classes/UploadRequest.md b/docs/source/api/Apollo/classes/UploadRequest.md deleted file mode 100644 index 26ceddca6c..0000000000 --- a/docs/source/api/Apollo/classes/UploadRequest.md +++ /dev/null @@ -1,92 +0,0 @@ -**CLASS** - -# `UploadRequest` - -```swift -open class UploadRequest: HTTPRequest -``` - -A request class allowing for a multipart-upload request. - -## Properties -### `requestBodyCreator` - -```swift -public let requestBodyCreator: RequestBodyCreator -``` - -### `files` - -```swift -public let files: [GraphQLFile] -``` - -### `manualBoundary` - -```swift -public let manualBoundary: String? -``` - -### `serializationFormat` - -```swift -public let serializationFormat = JSONSerializationFormat.self -``` - -## Methods -### `init(graphQLEndpoint:operation:clientName:clientVersion:additionalHeaders:files:manualBoundary:requestBodyCreator:)` - -```swift -public init(graphQLEndpoint: URL, - operation: Operation, - clientName: String, - clientVersion: String, - additionalHeaders: [String: String] = [:], - files: [GraphQLFile], - manualBoundary: String? = nil, - requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator()) -``` - -Designated Initializer - -- Parameters: - - graphQLEndpoint: The endpoint to make a GraphQL request to - - operation: The GraphQL Operation to execute - - clientName: The name of the client to send with the `"apollographql-client-name"` header - - clientVersion: The version of the client to send with the `"apollographql-client-version"` header - - additionalHeaders: Any additional headers you wish to add by default to this request. Defaults to an empty dictionary. - - files: The array of files to upload for all `Upload` parameters in the mutation. - - manualBoundary: [optional] A manual boundary to pass in. A default boundary will be used otherwise. Defaults to nil. - - requestBodyCreator: An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| graphQLEndpoint | The endpoint to make a GraphQL request to | -| operation | The GraphQL Operation to execute | -| clientName | The name of the client to send with the `"apollographql-client-name"` header | -| clientVersion | The version of the client to send with the `"apollographql-client-version"` header | -| additionalHeaders | Any additional headers you wish to add by default to this request. Defaults to an empty dictionary. | -| files | The array of files to upload for all `Upload` parameters in the mutation. | -| manualBoundary | [optional] A manual boundary to pass in. A default boundary will be used otherwise. Defaults to nil. | -| requestBodyCreator | An object conforming to the `RequestBodyCreator` protocol to assist with creating the request body. Defaults to the provided `ApolloRequestBodyCreator` implementation. | - -### `toURLRequest()` - -```swift -public override func toURLRequest() throws -> URLRequest -``` - -### `requestMultipartFormData()` - -```swift -open func requestMultipartFormData() throws -> MultipartFormData -``` - -Creates the `MultipartFormData` object to use when creating the URL Request. - -This method follows the [GraphQL Multipart Request Spec](https://github.com/jaydenseric/graphql-multipart-request-spec) Override this method to use a different upload spec. - -- Throws: Any error arising from creating the form data -- Returns: The created form data diff --git a/docs/source/api/Apollo/enums/ApolloClient.ApolloClientError.md b/docs/source/api/Apollo/enums/ApolloClient.ApolloClientError.md deleted file mode 100644 index 480571b363..0000000000 --- a/docs/source/api/Apollo/enums/ApolloClient.ApolloClientError.md +++ /dev/null @@ -1,21 +0,0 @@ -**ENUM** - -# `ApolloClient.ApolloClientError` - -```swift -public enum ApolloClientError: Error, LocalizedError -``` - -## Cases -### `noUploadTransport` - -```swift -case noUploadTransport -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/AutomaticPersistedQueryInterceptor.APQError.md b/docs/source/api/Apollo/enums/AutomaticPersistedQueryInterceptor.APQError.md deleted file mode 100644 index c2b3acbb61..0000000000 --- a/docs/source/api/Apollo/enums/AutomaticPersistedQueryInterceptor.APQError.md +++ /dev/null @@ -1,27 +0,0 @@ -**ENUM** - -# `AutomaticPersistedQueryInterceptor.APQError` - -```swift -public enum APQError: LocalizedError -``` - -## Cases -### `noParsedResponse` - -```swift -case noParsedResponse -``` - -### `persistedQueryRetryFailed(operationName:)` - -```swift -case persistedQueryRetryFailed(operationName: String) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/CachePolicy.md b/docs/source/api/Apollo/enums/CachePolicy.md deleted file mode 100644 index 059a6458ff..0000000000 --- a/docs/source/api/Apollo/enums/CachePolicy.md +++ /dev/null @@ -1,59 +0,0 @@ -**ENUM** - -# `CachePolicy` - -```swift -public enum CachePolicy -``` - -A cache policy that specifies whether results should be fetched from the server or loaded from the local cache. - -## Cases -### `returnCacheDataElseFetch` - -```swift -case returnCacheDataElseFetch -``` - -Return data from the cache if available, else fetch results from the server. - -### `fetchIgnoringCacheData` - -```swift -case fetchIgnoringCacheData -``` - -Always fetch results from the server. - -### `fetchIgnoringCacheCompletely` - -```swift -case fetchIgnoringCacheCompletely -``` - -Always fetch results from the server, and don't store these in the cache. - -### `returnCacheDataDontFetch` - -```swift -case returnCacheDataDontFetch -``` - -Return data from the cache if available, else return nil. - -### `returnCacheDataAndFetch` - -```swift -case returnCacheDataAndFetch -``` - -Return data from the cache if available, and always fetch results from the server. - -## Properties -### `default` - -```swift -public static var `default`: CachePolicy = .returnCacheDataElseFetch -``` - -The current default cache policy. diff --git a/docs/source/api/Apollo/enums/CacheWriteInterceptor.CacheWriteError.md b/docs/source/api/Apollo/enums/CacheWriteInterceptor.CacheWriteError.md deleted file mode 100644 index e8336f366a..0000000000 --- a/docs/source/api/Apollo/enums/CacheWriteInterceptor.CacheWriteError.md +++ /dev/null @@ -1,21 +0,0 @@ -**ENUM** - -# `CacheWriteInterceptor.CacheWriteError` - -```swift -public enum CacheWriteError: Error, LocalizedError -``` - -## Cases -### `noResponseToParse` - -```swift -case noResponseToParse -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/GraphQLFile.GraphQLFileError.md b/docs/source/api/Apollo/enums/GraphQLFile.GraphQLFileError.md deleted file mode 100644 index b0dc790811..0000000000 --- a/docs/source/api/Apollo/enums/GraphQLFile.GraphQLFileError.md +++ /dev/null @@ -1,27 +0,0 @@ -**ENUM** - -# `GraphQLFile.GraphQLFileError` - -```swift -public enum GraphQLFileError: Error, LocalizedError -``` - -## Cases -### `couldNotCreateInputStream` - -```swift -case couldNotCreateInputStream -``` - -### `couldNotGetFileSize(fileURL:)` - -```swift -case couldNotGetFileSize(fileURL: URL) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/GraphQLHTTPRequestError.md b/docs/source/api/Apollo/enums/GraphQLHTTPRequestError.md deleted file mode 100644 index 58db40e3bf..0000000000 --- a/docs/source/api/Apollo/enums/GraphQLHTTPRequestError.md +++ /dev/null @@ -1,29 +0,0 @@ -**ENUM** - -# `GraphQLHTTPRequestError` - -```swift -public enum GraphQLHTTPRequestError: Error, LocalizedError -``` - -An error which has occurred during the serialization of a request. - -## Cases -### `serializedBodyMessageError` - -```swift -case serializedBodyMessageError -``` - -### `serializedQueryParamsMessageError` - -```swift -case serializedQueryParamsMessageError -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/GraphQLOperationType.md b/docs/source/api/Apollo/enums/GraphQLOperationType.md deleted file mode 100644 index 637d91da76..0000000000 --- a/docs/source/api/Apollo/enums/GraphQLOperationType.md +++ /dev/null @@ -1,26 +0,0 @@ -**ENUM** - -# `GraphQLOperationType` - -```swift -public enum GraphQLOperationType -``` - -## Cases -### `query` - -```swift -case query -``` - -### `mutation` - -```swift -case mutation -``` - -### `subscription` - -```swift -case subscription -``` diff --git a/docs/source/api/Apollo/enums/GraphQLOutputType.md b/docs/source/api/Apollo/enums/GraphQLOutputType.md deleted file mode 100644 index 86d8f66a84..0000000000 --- a/docs/source/api/Apollo/enums/GraphQLOutputType.md +++ /dev/null @@ -1,32 +0,0 @@ -**ENUM** - -# `GraphQLOutputType` - -```swift -public indirect enum GraphQLOutputType -``` - -## Cases -### `scalar(_:)` - -```swift -case scalar(JSONDecodable.Type) -``` - -### `object(_:)` - -```swift -case object([GraphQLSelection]) -``` - -### `nonNull(_:)` - -```swift -case nonNull(GraphQLOutputType) -``` - -### `list(_:)` - -```swift -case list(GraphQLOutputType) -``` diff --git a/docs/source/api/Apollo/enums/GraphQLResult.Source.md b/docs/source/api/Apollo/enums/GraphQLResult.Source.md deleted file mode 100644 index a2909fc5be..0000000000 --- a/docs/source/api/Apollo/enums/GraphQLResult.Source.md +++ /dev/null @@ -1,22 +0,0 @@ -**ENUM** - -# `GraphQLResult.Source` - -```swift -public enum Source -``` - -Represents source of data - -## Cases -### `cache` - -```swift -case cache -``` - -### `server` - -```swift -case server -``` diff --git a/docs/source/api/Apollo/enums/JSONDecodingError.md b/docs/source/api/Apollo/enums/JSONDecodingError.md deleted file mode 100644 index 373894adab..0000000000 --- a/docs/source/api/Apollo/enums/JSONDecodingError.md +++ /dev/null @@ -1,39 +0,0 @@ -**ENUM** - -# `JSONDecodingError` - -```swift -public enum JSONDecodingError: Error, LocalizedError -``` - -## Cases -### `missingValue` - -```swift -case missingValue -``` - -### `nullValue` - -```swift -case nullValue -``` - -### `wrongType` - -```swift -case wrongType -``` - -### `couldNotConvert(value:to:)` - -```swift -case couldNotConvert(value: Any, to: Any.Type) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/JSONResponseParsingInterceptor.JSONResponseParsingError.md b/docs/source/api/Apollo/enums/JSONResponseParsingInterceptor.JSONResponseParsingError.md deleted file mode 100644 index a27dc57179..0000000000 --- a/docs/source/api/Apollo/enums/JSONResponseParsingInterceptor.JSONResponseParsingError.md +++ /dev/null @@ -1,27 +0,0 @@ -**ENUM** - -# `JSONResponseParsingInterceptor.JSONResponseParsingError` - -```swift -public enum JSONResponseParsingError: Error, LocalizedError -``` - -## Cases -### `noResponseToParse` - -```swift -case noResponseToParse -``` - -### `couldNotParseToJSON(data:)` - -```swift -case couldNotParseToJSON(data: Data) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/MaxRetryInterceptor.RetryError.md b/docs/source/api/Apollo/enums/MaxRetryInterceptor.RetryError.md deleted file mode 100644 index 471d63e234..0000000000 --- a/docs/source/api/Apollo/enums/MaxRetryInterceptor.RetryError.md +++ /dev/null @@ -1,21 +0,0 @@ -**ENUM** - -# `MaxRetryInterceptor.RetryError` - -```swift -public enum RetryError: Error, LocalizedError -``` - -## Cases -### `hitMaxRetryCount(count:operationName:)` - -```swift -case hitMaxRetryCount(count: Int, operationName: String) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/RequestChain.ChainError.md b/docs/source/api/Apollo/enums/RequestChain.ChainError.md deleted file mode 100644 index 70d501464f..0000000000 --- a/docs/source/api/Apollo/enums/RequestChain.ChainError.md +++ /dev/null @@ -1,27 +0,0 @@ -**ENUM** - -# `RequestChain.ChainError` - -```swift -public enum ChainError: Error, LocalizedError -``` - -## Cases -### `invalidIndex(chain:index:)` - -```swift -case invalidIndex(chain: RequestChain, index: Int) -``` - -### `noInterceptors` - -```swift -case noInterceptors -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/ResponseCodeInterceptor.ResponseCodeError.md b/docs/source/api/Apollo/enums/ResponseCodeInterceptor.ResponseCodeError.md deleted file mode 100644 index aae6ca7d1a..0000000000 --- a/docs/source/api/Apollo/enums/ResponseCodeInterceptor.ResponseCodeError.md +++ /dev/null @@ -1,21 +0,0 @@ -**ENUM** - -# `ResponseCodeInterceptor.ResponseCodeError` - -```swift -public enum ResponseCodeError: Error, LocalizedError -``` - -## Cases -### `invalidResponseCode(response:rawData:)` - -```swift -case invalidResponseCode(response: HTTPURLResponse?, rawData: Data?) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/enums/URLSessionClient.URLSessionClientError.md b/docs/source/api/Apollo/enums/URLSessionClient.URLSessionClientError.md deleted file mode 100644 index ed476531ec..0000000000 --- a/docs/source/api/Apollo/enums/URLSessionClient.URLSessionClientError.md +++ /dev/null @@ -1,45 +0,0 @@ -**ENUM** - -# `URLSessionClient.URLSessionClientError` - -```swift -public enum URLSessionClientError: Error, LocalizedError -``` - -## Cases -### `noHTTPResponse(request:)` - -```swift -case noHTTPResponse(request: URLRequest?) -``` - -### `sessionBecameInvalidWithoutUnderlyingError` - -```swift -case sessionBecameInvalidWithoutUnderlyingError -``` - -### `dataForRequestNotFound(request:)` - -```swift -case dataForRequestNotFound(request: URLRequest?) -``` - -### `networkError(data:response:underlying:)` - -```swift -case networkError(data: Data, response: HTTPURLResponse?, underlying: Error) -``` - -### `sessionInvalidated` - -```swift -case sessionInvalidated -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/extensions/ApolloClient.md b/docs/source/api/Apollo/extensions/ApolloClient.md deleted file mode 100644 index 56d2b6dad3..0000000000 --- a/docs/source/api/Apollo/extensions/ApolloClient.md +++ /dev/null @@ -1,119 +0,0 @@ -**EXTENSION** - -# `ApolloClient` -```swift -extension ApolloClient: ApolloClientProtocol -``` - -## Properties -### `cacheKeyForObject` - -```swift -public var cacheKeyForObject: CacheKeyForObject? -``` - -## Methods -### `clearCache(callbackQueue:completion:)` - -```swift -public func clearCache(callbackQueue: DispatchQueue = .main, - completion: ((Result) -> Void)? = nil) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| callbackQueue | The queue to fall back on. Should default to the main queue. | -| completion | [optional] A completion closure to execute when clearing has completed. Should default to nil. | - -### `fetch(query:cachePolicy:contextIdentifier:queue:resultHandler:)` - -```swift -@discardableResult public func fetch(query: Query, - cachePolicy: CachePolicy = .default, - contextIdentifier: UUID? = nil, - queue: DispatchQueue = .main, - resultHandler: GraphQLResultHandler? = nil) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| query | The query to fetch. | -| cachePolicy | A cache policy that specifies when results should be fetched from the server and when data should be loaded from the local cache. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. | -| resultHandler | [optional] A closure that is called when query results are available or when an error occurs. | - -### `watch(query:cachePolicy:callbackQueue:resultHandler:)` - -```swift -public func watch(query: Query, - cachePolicy: CachePolicy = .default, - callbackQueue: DispatchQueue = .main, - resultHandler: @escaping GraphQLResultHandler) -> GraphQLQueryWatcher -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| query | The query to fetch. | -| cachePolicy | A cache policy that specifies when results should be fetched from the server or from the local cache. | -| callbackQueue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| resultHandler | [optional] A closure that is called when query results are available or when an error occurs. | - -### `perform(mutation:publishResultToStore:queue:resultHandler:)` - -```swift -public func perform(mutation: Mutation, - publishResultToStore: Bool = true, - queue: DispatchQueue = .main, - resultHandler: GraphQLResultHandler? = nil) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| mutation | The mutation to perform. | -| publishResultToStore | If `true`, this will publish the result returned from the operation to the cache store. Default is `true`. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| resultHandler | An optional closure that is called when mutation results are available or when an error occurs. | - -### `upload(operation:files:queue:resultHandler:)` - -```swift -public func upload(operation: Operation, - files: [GraphQLFile], - queue: DispatchQueue = .main, - resultHandler: GraphQLResultHandler? = nil) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send | -| files | An array of `GraphQLFile` objects to send. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| completionHandler | The completion handler to execute when the request completes or errors. Note that an error will be returned If your `networkTransport` does not also conform to `UploadingNetworkTransport`. | - -### `subscribe(subscription:queue:resultHandler:)` - -```swift -public func subscribe(subscription: Subscription, - queue: DispatchQueue = .main, - resultHandler: @escaping GraphQLResultHandler) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| subscription | The subscription to subscribe to. | -| fetchHTTPMethod | The HTTP Method to be used. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| resultHandler | An optional closure that is called when mutation results are available or when an error occurs. | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/ApolloExtension.md b/docs/source/api/Apollo/extensions/ApolloExtension.md deleted file mode 100644 index 50cbbf1798..0000000000 --- a/docs/source/api/Apollo/extensions/ApolloExtension.md +++ /dev/null @@ -1,21 +0,0 @@ -**EXTENSION** - -# `ApolloExtension` -```swift -public extension ApolloExtension where Base == DispatchQueue -``` - -## Methods -### `performAsyncIfNeeded(on:action:)` - -```swift -static func performAsyncIfNeeded(on callbackQueue: DispatchQueue?, action: @escaping () -> Void) -``` - -### `returnResultAsyncIfNeeded(on:action:result:)` - -```swift -static func returnResultAsyncIfNeeded(on callbackQueue: DispatchQueue?, - action: ((Result) -> Void)?, - result: Result) -``` diff --git a/docs/source/api/Apollo/extensions/Array.md b/docs/source/api/Apollo/extensions/Array.md deleted file mode 100644 index b24e61cf22..0000000000 --- a/docs/source/api/Apollo/extensions/Array.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `Array` -```swift -extension Array: JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` diff --git a/docs/source/api/Apollo/extensions/Bool.md b/docs/source/api/Apollo/extensions/Bool.md deleted file mode 100644 index 5b9988a7c4..0000000000 --- a/docs/source/api/Apollo/extensions/Bool.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `Bool` -```swift -extension Bool: JSONDecodable, JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/CacheReference.md b/docs/source/api/Apollo/extensions/CacheReference.md deleted file mode 100644 index 9eaa774f2a..0000000000 --- a/docs/source/api/Apollo/extensions/CacheReference.md +++ /dev/null @@ -1,27 +0,0 @@ -**EXTENSION** - -# `CacheReference` -```swift -extension CacheReference: Equatable -``` - -## Properties -### `description` - -```swift -public var description: String -``` - -## Methods -### `==(_:_:)` - -```swift -public static func ==(lhs: CacheReference, rhs: CacheReference) -> Bool -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| lhs | A value to compare. | -| rhs | Another value to compare. | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/Dictionary.md b/docs/source/api/Apollo/extensions/Dictionary.md deleted file mode 100644 index 9a2cc8edbf..0000000000 --- a/docs/source/api/Apollo/extensions/Dictionary.md +++ /dev/null @@ -1,32 +0,0 @@ -**EXTENSION** - -# `Dictionary` -```swift -public extension Dictionary -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -### `jsonObject` - -```swift -public var jsonObject: JSONObject -``` - -## Methods -### `+=(_:_:)` - -```swift -static func += (lhs: inout Dictionary, rhs: Dictionary) -``` - -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/Double.md b/docs/source/api/Apollo/extensions/Double.md deleted file mode 100644 index be40ab0fc7..0000000000 --- a/docs/source/api/Apollo/extensions/Double.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `Double` -```swift -extension Double: JSONDecodable, JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/Float.md b/docs/source/api/Apollo/extensions/Float.md deleted file mode 100644 index 3a28aa7cb1..0000000000 --- a/docs/source/api/Apollo/extensions/Float.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `Float` -```swift -extension Float: JSONDecodable, JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLError.md b/docs/source/api/Apollo/extensions/GraphQLError.md deleted file mode 100644 index 16cc148fb5..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLError.md +++ /dev/null @@ -1,19 +0,0 @@ -**EXTENSION** - -# `GraphQLError` -```swift -extension GraphQLError: CustomStringConvertible -``` - -## Properties -### `description` - -```swift -public var description: String -``` - -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLMapConvertible.md b/docs/source/api/Apollo/extensions/GraphQLMapConvertible.md deleted file mode 100644 index 149f8ceb83..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLMapConvertible.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `GraphQLMapConvertible` -```swift -public extension GraphQLMapConvertible -``` - -## Properties -### `jsonValue` - -```swift -var jsonValue: JSONValue -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLMutation.md b/docs/source/api/Apollo/extensions/GraphQLMutation.md deleted file mode 100644 index 8e918a6803..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLMutation.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `GraphQLMutation` -```swift -public extension GraphQLMutation -``` - -## Properties -### `operationType` - -```swift -var operationType: GraphQLOperationType -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLOperation.md b/docs/source/api/Apollo/extensions/GraphQLOperation.md deleted file mode 100644 index 084ea96f75..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLOperation.md +++ /dev/null @@ -1,25 +0,0 @@ -**EXTENSION** - -# `GraphQLOperation` -```swift -public extension GraphQLOperation -``` - -## Properties -### `queryDocument` - -```swift -var queryDocument: String -``` - -### `operationIdentifier` - -```swift -var operationIdentifier: String? -``` - -### `variables` - -```swift -var variables: GraphQLMap? -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLQuery.md b/docs/source/api/Apollo/extensions/GraphQLQuery.md deleted file mode 100644 index a857360cd1..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLQuery.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `GraphQLQuery` -```swift -public extension GraphQLQuery -``` - -## Properties -### `operationType` - -```swift -var operationType: GraphQLOperationType -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLSelectionSet.md b/docs/source/api/Apollo/extensions/GraphQLSelectionSet.md deleted file mode 100644 index 5edbb9feb8..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLSelectionSet.md +++ /dev/null @@ -1,26 +0,0 @@ -**EXTENSION** - -# `GraphQLSelectionSet` -```swift -public extension GraphQLSelectionSet -``` - -## Properties -### `jsonObject` - -```swift -var jsonObject: JSONObject -``` - -## Methods -### `init(jsonObject:variables:)` - -```swift -init(jsonObject: JSONObject, variables: GraphQLMap? = nil) throws -``` - -### `init(_:)` - -```swift -public init(_ selectionSet: GraphQLSelectionSet) throws -``` diff --git a/docs/source/api/Apollo/extensions/GraphQLSubscription.md b/docs/source/api/Apollo/extensions/GraphQLSubscription.md deleted file mode 100644 index 3e238dc00e..0000000000 --- a/docs/source/api/Apollo/extensions/GraphQLSubscription.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `GraphQLSubscription` -```swift -public extension GraphQLSubscription -``` - -## Properties -### `operationType` - -```swift -var operationType: GraphQLOperationType -``` diff --git a/docs/source/api/Apollo/extensions/HTTPRequest.md b/docs/source/api/Apollo/extensions/HTTPRequest.md deleted file mode 100644 index 0322684185..0000000000 --- a/docs/source/api/Apollo/extensions/HTTPRequest.md +++ /dev/null @@ -1,27 +0,0 @@ -**EXTENSION** - -# `HTTPRequest` -```swift -extension HTTPRequest: Equatable -``` - -## Properties -### `debugDescription` - -```swift -public var debugDescription: String -``` - -## Methods -### `==(_:_:)` - -```swift -public static func == (lhs: HTTPRequest, rhs: HTTPRequest) -> Bool -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| lhs | A value to compare. | -| rhs | Another value to compare. | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/Int.md b/docs/source/api/Apollo/extensions/Int.md deleted file mode 100644 index d351088413..0000000000 --- a/docs/source/api/Apollo/extensions/Int.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `Int` -```swift -extension Int: JSONDecodable, JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/InterceptorProvider.md b/docs/source/api/Apollo/extensions/InterceptorProvider.md deleted file mode 100644 index 2ce9788197..0000000000 --- a/docs/source/api/Apollo/extensions/InterceptorProvider.md +++ /dev/null @@ -1,19 +0,0 @@ -**EXTENSION** - -# `InterceptorProvider` -```swift -public extension InterceptorProvider -``` - -## Methods -### `additionalErrorInterceptor(for:)` - -```swift -func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to provide an additional error interceptor for | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/NSDictionary.md b/docs/source/api/Apollo/extensions/NSDictionary.md deleted file mode 100644 index c5e98262ee..0000000000 --- a/docs/source/api/Apollo/extensions/NSDictionary.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `NSDictionary` -```swift -extension NSDictionary: JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` diff --git a/docs/source/api/Apollo/extensions/NSNull.md b/docs/source/api/Apollo/extensions/NSNull.md deleted file mode 100644 index 3b66a337e7..0000000000 --- a/docs/source/api/Apollo/extensions/NSNull.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `NSNull` -```swift -extension NSNull: JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` diff --git a/docs/source/api/Apollo/extensions/NetworkTransport.md b/docs/source/api/Apollo/extensions/NetworkTransport.md deleted file mode 100644 index 9f1cdfbb36..0000000000 --- a/docs/source/api/Apollo/extensions/NetworkTransport.md +++ /dev/null @@ -1,67 +0,0 @@ -**EXTENSION** - -# `NetworkTransport` -```swift -public extension NetworkTransport -``` - -## Properties -### `headerFieldNameApolloClientName` - -```swift -static var headerFieldNameApolloClientName: String -``` - -The field name for the Apollo Client Name header - -### `headerFieldNameApolloClientVersion` - -```swift -static var headerFieldNameApolloClientVersion: String -``` - -The field name for the Apollo Client Version header - -### `defaultClientName` - -```swift -static var defaultClientName: String -``` - -The default client name to use when setting up the `clientName` property - -### `clientName` - -```swift -var clientName: String -``` - -### `defaultClientVersion` - -```swift -static var defaultClientVersion: String -``` - -The default client version to use when setting up the `clientVersion` property. - -### `clientVersion` - -```swift -var clientVersion: String -``` - -## Methods -### `addApolloClientHeaders(to:)` - -```swift -func addApolloClientHeaders(to request: inout URLRequest) -``` - -Adds the Apollo client headers for this instance of `NetworkTransport` to the given request -- Parameter request: A mutable URLRequest to add the headers to. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | A mutable URLRequest to add the headers to. | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/Optional.md b/docs/source/api/Apollo/extensions/Optional.md deleted file mode 100644 index 2faa950b5b..0000000000 --- a/docs/source/api/Apollo/extensions/Optional.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `Optional` -```swift -extension Optional where Wrapped: JSONDecodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/RawRepresentable.md b/docs/source/api/Apollo/extensions/RawRepresentable.md deleted file mode 100644 index bb2462e02f..0000000000 --- a/docs/source/api/Apollo/extensions/RawRepresentable.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `RawRepresentable` -```swift -extension RawRepresentable where RawValue: JSONDecodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/Record.md b/docs/source/api/Apollo/extensions/Record.md deleted file mode 100644 index b4d6770f08..0000000000 --- a/docs/source/api/Apollo/extensions/Record.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `Record` -```swift -extension Record: CustomStringConvertible -``` - -## Properties -### `description` - -```swift -public var description: String -``` diff --git a/docs/source/api/Apollo/extensions/RecordSet.md b/docs/source/api/Apollo/extensions/RecordSet.md deleted file mode 100644 index cbe620ddcb..0000000000 --- a/docs/source/api/Apollo/extensions/RecordSet.md +++ /dev/null @@ -1,26 +0,0 @@ -**EXTENSION** - -# `RecordSet` -```swift -extension RecordSet: ExpressibleByDictionaryLiteral -``` - -## Properties -### `description` - -```swift -public var description: String -``` - -### `playgroundDescription` - -```swift -public var playgroundDescription: Any -``` - -## Methods -### `init(dictionaryLiteral:)` - -```swift -public init(dictionaryLiteral elements: (CacheKey, Record.Fields)...) -``` diff --git a/docs/source/api/Apollo/extensions/RequestBodyCreator.md b/docs/source/api/Apollo/extensions/RequestBodyCreator.md deleted file mode 100644 index 674a6b4fe7..0000000000 --- a/docs/source/api/Apollo/extensions/RequestBodyCreator.md +++ /dev/null @@ -1,25 +0,0 @@ -**EXTENSION** - -# `RequestBodyCreator` -```swift -extension RequestBodyCreator -``` - -## Methods -### `requestBody(for:sendOperationIdentifiers:sendQueryDocument:autoPersistQuery:)` - -```swift -public func requestBody(for operation: Operation, - sendOperationIdentifiers: Bool, - sendQueryDocument: Bool, - autoPersistQuery: Bool) -> GraphQLMap -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to use | -| sendOperationIdentifiers | Whether or not to send operation identifiers. Should default to `false`. | -| sendQueryDocument | Whether or not to send the full query document. Should default to `true`. | -| autoPersistQuery | Whether to use auto-persisted query information. Should default to `false`. | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/RequestChainNetworkTransport.md b/docs/source/api/Apollo/extensions/RequestChainNetworkTransport.md deleted file mode 100644 index 748283911c..0000000000 --- a/docs/source/api/Apollo/extensions/RequestChainNetworkTransport.md +++ /dev/null @@ -1,53 +0,0 @@ -**EXTENSION** - -# `RequestChainNetworkTransport` -```swift -extension RequestChainNetworkTransport: UploadingNetworkTransport -``` - -## Methods -### `constructUploadRequest(for:with:manualBoundary:)` - -```swift -open func constructUploadRequest( - for operation: Operation, - with files: [GraphQLFile], - manualBoundary: String? = nil) -> HTTPRequest -``` - -Constructs an uploading (ie, multipart) GraphQL request - -Override this method if you need to use a custom subclass of `HTTPRequest`. - -- Parameters: - - operation: The operation to create a request for - - files: The files you wish to upload - - manualBoundary: [optional] A manually set boundary for your upload request. Defaults to nil. -- Returns: The created request. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to create a request for | -| files | The files you wish to upload | -| manualBoundary | [optional] A manually set boundary for your upload request. Defaults to nil. | - -### `upload(operation:files:callbackQueue:completionHandler:)` - -```swift -public func upload( - operation: Operation, - files: [GraphQLFile], - callbackQueue: DispatchQueue = .main, - completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send | -| files | An array of `GraphQLFile` objects to send. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | The completion handler to execute when the request completes or errors | \ No newline at end of file diff --git a/docs/source/api/Apollo/extensions/String.md b/docs/source/api/Apollo/extensions/String.md deleted file mode 100644 index f95753aeda..0000000000 --- a/docs/source/api/Apollo/extensions/String.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `String` -```swift -extension String: JSONDecodable, JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/extensions/URL.md b/docs/source/api/Apollo/extensions/URL.md deleted file mode 100644 index 03eba75b00..0000000000 --- a/docs/source/api/Apollo/extensions/URL.md +++ /dev/null @@ -1,20 +0,0 @@ -**EXTENSION** - -# `URL` -```swift -extension URL: JSONDecodable, JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -public var jsonValue: JSONValue -``` - -## Methods -### `init(jsonValue:)` - -```swift -public init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/methods/GraphQLVariable(__).md b/docs/source/api/Apollo/methods/GraphQLVariable(__).md deleted file mode 100644 index aa8a62cda0..0000000000 --- a/docs/source/api/Apollo/methods/GraphQLVariable(__).md +++ /dev/null @@ -1,8 +0,0 @@ -### `GraphQLVariable(_:)` - -```swift -public func GraphQLVariable(_ name: String) -> InputValue -``` - -For backwards compatibility with legacy codegen. -The `GraphQLVariable` class has been replaced by `InputValue.variable` diff --git a/docs/source/api/Apollo/methods/unzip(__).md b/docs/source/api/Apollo/methods/unzip(__).md deleted file mode 100644 index e64793bcfa..0000000000 --- a/docs/source/api/Apollo/methods/unzip(__).md +++ /dev/null @@ -1,5 +0,0 @@ -### `unzip(_:)` - -```swift -public func unzip(_ array: [(Element1, Element2, Element3)]) -> ([Element1], [Element2], [Element3]) -``` diff --git a/docs/source/api/Apollo/protocols/ApolloClientProtocol.md b/docs/source/api/Apollo/protocols/ApolloClientProtocol.md deleted file mode 100644 index 283b530fdd..0000000000 --- a/docs/source/api/Apollo/protocols/ApolloClientProtocol.md +++ /dev/null @@ -1,184 +0,0 @@ -**PROTOCOL** - -# `ApolloClientProtocol` - -```swift -public protocol ApolloClientProtocol: AnyObject -``` - -The `ApolloClientProtocol` provides the core API for Apollo. This API provides methods to fetch and watch queries, and to perform mutations. - -## Properties -### `store` - -```swift -var store: ApolloStore -``` - -A store used as a local cache. - -### `cacheKeyForObject` - -```swift -var cacheKeyForObject: CacheKeyForObject? -``` - -A function that returns a cache key for a particular result object. If it returns `nil`, a default cache key based on the field path will be used. - -## Methods -### `clearCache(callbackQueue:completion:)` - -```swift -func clearCache(callbackQueue: DispatchQueue, completion: ((Result) -> Void)?) -``` - -Clears the underlying cache. -Be aware: In more complex setups, the same underlying cache can be used across multiple instances, so if you call this on one instance, it'll clear that cache across all instances which share that cache. - -- Parameters: - - callbackQueue: The queue to fall back on. Should default to the main queue. - - completion: [optional] A completion closure to execute when clearing has completed. Should default to nil. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| callbackQueue | The queue to fall back on. Should default to the main queue. | -| completion | [optional] A completion closure to execute when clearing has completed. Should default to nil. | - -### `fetch(query:cachePolicy:contextIdentifier:queue:resultHandler:)` - -```swift -func fetch(query: Query, - cachePolicy: CachePolicy, - contextIdentifier: UUID?, - queue: DispatchQueue, - resultHandler: GraphQLResultHandler?) -> Cancellable -``` - -Fetches a query from the server or from the local cache, depending on the current contents of the cache and the specified cache policy. - -- Parameters: - - query: The query to fetch. - - cachePolicy: A cache policy that specifies when results should be fetched from the server and when data should be loaded from the local cache. - - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. - - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. - - resultHandler: [optional] A closure that is called when query results are available or when an error occurs. -- Returns: An object that can be used to cancel an in progress fetch. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| query | The query to fetch. | -| cachePolicy | A cache policy that specifies when results should be fetched from the server and when data should be loaded from the local cache. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Should default to `nil`. | -| resultHandler | [optional] A closure that is called when query results are available or when an error occurs. | - -### `watch(query:cachePolicy:callbackQueue:resultHandler:)` - -```swift -func watch(query: Query, - cachePolicy: CachePolicy, - callbackQueue: DispatchQueue, - resultHandler: @escaping GraphQLResultHandler) -> GraphQLQueryWatcher -``` - -Watches a query by first fetching an initial result from the server or from the local cache, depending on the current contents of the cache and the specified cache policy. After the initial fetch, the returned query watcher object will get notified whenever any of the data the query result depends on changes in the local cache, and calls the result handler again with the new result. - -- Parameters: - - query: The query to fetch. - - cachePolicy: A cache policy that specifies when results should be fetched from the server or from the local cache. - - callbackQueue: A dispatch queue on which the result handler will be called. Should default to the main queue. - - resultHandler: [optional] A closure that is called when query results are available or when an error occurs. -- Returns: A query watcher object that can be used to control the watching behavior. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| query | The query to fetch. | -| cachePolicy | A cache policy that specifies when results should be fetched from the server or from the local cache. | -| callbackQueue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| resultHandler | [optional] A closure that is called when query results are available or when an error occurs. | - -### `perform(mutation:publishResultToStore:queue:resultHandler:)` - -```swift -func perform(mutation: Mutation, - publishResultToStore: Bool, - queue: DispatchQueue, - resultHandler: GraphQLResultHandler?) -> Cancellable -``` - -Performs a mutation by sending it to the server. - -- Parameters: - - mutation: The mutation to perform. - - publishResultToStore: If `true`, this will publish the result returned from the operation to the cache store. Default is `true`. - - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. - - resultHandler: An optional closure that is called when mutation results are available or when an error occurs. -- Returns: An object that can be used to cancel an in progress mutation. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| mutation | The mutation to perform. | -| publishResultToStore | If `true`, this will publish the result returned from the operation to the cache store. Default is `true`. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| resultHandler | An optional closure that is called when mutation results are available or when an error occurs. | - -### `upload(operation:files:queue:resultHandler:)` - -```swift -func upload(operation: Operation, - files: [GraphQLFile], - queue: DispatchQueue, - resultHandler: GraphQLResultHandler?) -> Cancellable -``` - -Uploads the given files with the given operation. - -- Parameters: - - operation: The operation to send - - files: An array of `GraphQLFile` objects to send. - - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. - - completionHandler: The completion handler to execute when the request completes or errors. Note that an error will be returned If your `networkTransport` does not also conform to `UploadingNetworkTransport`. -- Returns: An object that can be used to cancel an in progress request. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send | -| files | An array of `GraphQLFile` objects to send. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| completionHandler | The completion handler to execute when the request completes or errors. Note that an error will be returned If your `networkTransport` does not also conform to `UploadingNetworkTransport`. | - -### `subscribe(subscription:queue:resultHandler:)` - -```swift -func subscribe(subscription: Subscription, - queue: DispatchQueue, - resultHandler: @escaping GraphQLResultHandler) -> Cancellable -``` - -Subscribe to a subscription - -- Parameters: - - subscription: The subscription to subscribe to. - - fetchHTTPMethod: The HTTP Method to be used. - - queue: A dispatch queue on which the result handler will be called. Should default to the main queue. - - resultHandler: An optional closure that is called when mutation results are available or when an error occurs. -- Returns: An object that can be used to cancel an in progress subscription. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| subscription | The subscription to subscribe to. | -| fetchHTTPMethod | The HTTP Method to be used. | -| queue | A dispatch queue on which the result handler will be called. Should default to the main queue. | -| resultHandler | An optional closure that is called when mutation results are available or when an error occurs. | \ No newline at end of file diff --git a/docs/source/api/Apollo/protocols/ApolloErrorInterceptor.md b/docs/source/api/Apollo/protocols/ApolloErrorInterceptor.md deleted file mode 100644 index 9acd22fc0d..0000000000 --- a/docs/source/api/Apollo/protocols/ApolloErrorInterceptor.md +++ /dev/null @@ -1,40 +0,0 @@ -**PROTOCOL** - -# `ApolloErrorInterceptor` - -```swift -public protocol ApolloErrorInterceptor -``` - -An error interceptor called to allow further examination of error data when an error occurs in the chain. - -## Methods -### `handleErrorAsync(error:chain:request:response:completion:)` - -```swift -func handleErrorAsync( - error: Error, - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -Asynchronously handles the receipt of an error at any point in the chain. - -- Parameters: - - error: The received error - - chain: The chain the error was received on - - request: The request, as far as it was constructed - - response: [optional] The response, if one was received - - completion: The completion closure to fire when the operation has completed. Note that if you call `retry` on the chain, you will not want to call the completion block in this method. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| error | The received error | -| chain | The chain the error was received on | -| request | The request, as far as it was constructed | -| response | [optional] The response, if one was received | -| completion | The completion closure to fire when the operation has completed. Note that if you call `retry` on the chain, you will not want to call the completion block in this method. | \ No newline at end of file diff --git a/docs/source/api/Apollo/protocols/ApolloInterceptor.md b/docs/source/api/Apollo/protocols/ApolloInterceptor.md deleted file mode 100644 index 02025e3d11..0000000000 --- a/docs/source/api/Apollo/protocols/ApolloInterceptor.md +++ /dev/null @@ -1,37 +0,0 @@ -**PROTOCOL** - -# `ApolloInterceptor` - -```swift -public protocol ApolloInterceptor -``` - -A protocol to set up a chainable unit of networking work. - -## Methods -### `interceptAsync(chain:request:response:completion:)` - -```swift -func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -Called when this interceptor should do its work. - -- Parameters: - - chain: The chain the interceptor is a part of. - - request: The request, as far as it has been constructed - - response: [optional] The response, if received - - completion: The completion block to fire when data needs to be returned to the UI. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/protocols/Cancellable.md b/docs/source/api/Apollo/protocols/Cancellable.md deleted file mode 100644 index 8406f07e3b..0000000000 --- a/docs/source/api/Apollo/protocols/Cancellable.md +++ /dev/null @@ -1,18 +0,0 @@ -**PROTOCOL** - -# `Cancellable` - -```swift -public protocol Cancellable: AnyObject -``` - -An object that can be used to cancel an in progress action. - -## Methods -### `cancel()` - -```swift -func cancel() -``` - -Cancel an in progress action. diff --git a/docs/source/api/Apollo/protocols/GraphQLFragment.md b/docs/source/api/Apollo/protocols/GraphQLFragment.md deleted file mode 100644 index 605bcf746c..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLFragment.md +++ /dev/null @@ -1,20 +0,0 @@ -**PROTOCOL** - -# `GraphQLFragment` - -```swift -public protocol GraphQLFragment: GraphQLSelectionSet -``` - -## Properties -### `fragmentDefinition` - -```swift -static var fragmentDefinition: String -``` - -### `possibleTypes` - -```swift -static var possibleTypes: [String] -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLMapConvertible.md b/docs/source/api/Apollo/protocols/GraphQLMapConvertible.md deleted file mode 100644 index ee1f2dc4f6..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLMapConvertible.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `GraphQLMapConvertible` - -```swift -public protocol GraphQLMapConvertible: JSONEncodable -``` - -## Properties -### `graphQLMap` - -```swift -var graphQLMap: GraphQLMap -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLMutation.md b/docs/source/api/Apollo/protocols/GraphQLMutation.md deleted file mode 100644 index f08bfe5d54..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLMutation.md +++ /dev/null @@ -1,7 +0,0 @@ -**PROTOCOL** - -# `GraphQLMutation` - -```swift -public protocol GraphQLMutation: GraphQLOperation -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLOperation.md b/docs/source/api/Apollo/protocols/GraphQLOperation.md deleted file mode 100644 index 211521dfe8..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLOperation.md +++ /dev/null @@ -1,44 +0,0 @@ -**PROTOCOL** - -# `GraphQLOperation` - -```swift -public protocol GraphQLOperation: AnyObject -``` - -## Properties -### `operationType` - -```swift -var operationType: GraphQLOperationType -``` - -### `operationDefinition` - -```swift -var operationDefinition: String -``` - -### `operationIdentifier` - -```swift -var operationIdentifier: String? -``` - -### `operationName` - -```swift -var operationName: String -``` - -### `queryDocument` - -```swift -var queryDocument: String -``` - -### `variables` - -```swift -var variables: GraphQLMap? -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLQuery.md b/docs/source/api/Apollo/protocols/GraphQLQuery.md deleted file mode 100644 index c838f06b36..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLQuery.md +++ /dev/null @@ -1,7 +0,0 @@ -**PROTOCOL** - -# `GraphQLQuery` - -```swift -public protocol GraphQLQuery: GraphQLOperation -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLSelection.md b/docs/source/api/Apollo/protocols/GraphQLSelection.md deleted file mode 100644 index a53dfe66d1..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLSelection.md +++ /dev/null @@ -1,7 +0,0 @@ -**PROTOCOL** - -# `GraphQLSelection` - -```swift -public protocol GraphQLSelection -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLSelectionSet.md b/docs/source/api/Apollo/protocols/GraphQLSelectionSet.md deleted file mode 100644 index 49e3c93753..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLSelectionSet.md +++ /dev/null @@ -1,27 +0,0 @@ -**PROTOCOL** - -# `GraphQLSelectionSet` - -```swift -public protocol GraphQLSelectionSet -``` - -## Properties -### `selections` - -```swift -static var selections: [GraphQLSelection] -``` - -### `resultMap` - -```swift -var resultMap: ResultMap -``` - -## Methods -### `init(unsafeResultMap:)` - -```swift -init(unsafeResultMap: ResultMap) -``` diff --git a/docs/source/api/Apollo/protocols/GraphQLSubscription.md b/docs/source/api/Apollo/protocols/GraphQLSubscription.md deleted file mode 100644 index 8bc7806ae2..0000000000 --- a/docs/source/api/Apollo/protocols/GraphQLSubscription.md +++ /dev/null @@ -1,7 +0,0 @@ -**PROTOCOL** - -# `GraphQLSubscription` - -```swift -public protocol GraphQLSubscription: GraphQLOperation -``` diff --git a/docs/source/api/Apollo/protocols/InterceptorProvider.md b/docs/source/api/Apollo/protocols/InterceptorProvider.md deleted file mode 100644 index 6d62e023f2..0000000000 --- a/docs/source/api/Apollo/protocols/InterceptorProvider.md +++ /dev/null @@ -1,42 +0,0 @@ -**PROTOCOL** - -# `InterceptorProvider` - -```swift -public protocol InterceptorProvider -``` - -A protocol to allow easy creation of an array of interceptors for a given operation. - -## Methods -### `interceptors(for:)` - -```swift -func interceptors(for operation: Operation) -> [ApolloInterceptor] -``` - -Creates a new array of interceptors when called - -- Parameter operation: The operation to provide interceptors for - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to provide interceptors for | - -### `additionalErrorInterceptor(for:)` - -```swift -func additionalErrorInterceptor(for operation: Operation) -> ApolloErrorInterceptor? -``` - -Provides an additional error interceptor for any additional handling of errors -before returning to the UI, such as logging. -- Parameter operation: The operation to provide an additional error interceptor for - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to provide an additional error interceptor for | \ No newline at end of file diff --git a/docs/source/api/Apollo/protocols/JSONDecodable.md b/docs/source/api/Apollo/protocols/JSONDecodable.md deleted file mode 100644 index a030edd3d3..0000000000 --- a/docs/source/api/Apollo/protocols/JSONDecodable.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `JSONDecodable` - -```swift -public protocol JSONDecodable -``` - -## Methods -### `init(jsonValue:)` - -```swift -init(jsonValue value: JSONValue) throws -``` diff --git a/docs/source/api/Apollo/protocols/JSONEncodable.md b/docs/source/api/Apollo/protocols/JSONEncodable.md deleted file mode 100644 index 6fb7ef518c..0000000000 --- a/docs/source/api/Apollo/protocols/JSONEncodable.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `JSONEncodable` - -```swift -public protocol JSONEncodable -``` - -## Properties -### `jsonValue` - -```swift -var jsonValue: JSONValue -``` diff --git a/docs/source/api/Apollo/protocols/NetworkTransport.md b/docs/source/api/Apollo/protocols/NetworkTransport.md deleted file mode 100644 index 8ef2fe3cc7..0000000000 --- a/docs/source/api/Apollo/protocols/NetworkTransport.md +++ /dev/null @@ -1,59 +0,0 @@ -**PROTOCOL** - -# `NetworkTransport` - -```swift -public protocol NetworkTransport: AnyObject -``` - -A network transport is responsible for sending GraphQL operations to a server. - -## Properties -### `clientName` - -```swift -var clientName: String -``` - -The name of the client to send as a header value. - -### `clientVersion` - -```swift -var clientVersion: String -``` - -The version of the client to send as a header value. - -## Methods -### `send(operation:cachePolicy:contextIdentifier:callbackQueue:completionHandler:)` - -```swift -func send(operation: Operation, - cachePolicy: CachePolicy, - contextIdentifier: UUID?, - callbackQueue: DispatchQueue, - completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable -``` - -Send a GraphQL operation to a server and return a response. - -Note if you're implementing this yourself rather than using one of the batteries-included versions of `NetworkTransport` (which handle this for you): The `clientName` and `clientVersion` should be sent with any URL request which needs headers so your client can be identified by tools meant to see what client is using which request. The `addApolloClientHeaders` method is provided below to do this for you if you're using Apollo Studio. - -- Parameters: - - operation: The operation to send. - - cachePolicy: The `CachePolicy` to use making this request. - - contextIdentifier: [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. - - callbackQueue: The queue to call back on with the results. Should default to `.main`. - - completionHandler: A closure to call when a request completes. On `success` will contain the response received from the server. On `failure` will contain the error which occurred. -- Returns: An object that can be used to cancel an in progress request. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send. | -| cachePolicy | The `CachePolicy` to use making this request. | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | A closure to call when a request completes. On `success` will contain the response received from the server. On `failure` will contain the error which occurred. | \ No newline at end of file diff --git a/docs/source/api/Apollo/protocols/NormalizedCache.md b/docs/source/api/Apollo/protocols/NormalizedCache.md deleted file mode 100644 index 08397355be..0000000000 --- a/docs/source/api/Apollo/protocols/NormalizedCache.md +++ /dev/null @@ -1,103 +0,0 @@ -**PROTOCOL** - -# `NormalizedCache` - -```swift -public protocol NormalizedCache -``` - -## Methods -### `loadRecords(forKeys:)` - -```swift -func loadRecords(forKeys keys: Set) throws -> [CacheKey: Record] -``` - -Loads records corresponding to the given keys. - -- Parameters: - - key: The cache keys to load data for -- Returns: A dictionary of cache keys to records containing the records that have been found. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache keys to load data for | - -### `merge(records:)` - -```swift -func merge(records: RecordSet) throws -> Set -``` - -Merges a set of records into the cache. - -- Parameters: - - records: The set of records to merge. -- Returns: A set of keys corresponding to *fields* that have changed (i.e. QUERY_ROOT.Foo.myField). These are the same type of keys as are returned by RecordSet.merge(records:). - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| records | The set of records to merge. | - -### `removeRecord(for:)` - -```swift -func removeRecord(for key: CacheKey) throws -``` - -Removes a record for the specified key. This method will only -remove whole records, not individual fields. - -If you attempt to pass a cache key for a single field, this -method will do nothing since it won't be able to locate a -record to remove based on that key. - -This method does not support cascading delete - it will only -remove the record for the specified key, and not any references to it or from it. - -- Parameters: - - key: The cache key to remove the record for - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache key to remove the record for | - -### `removeRecords(matching:)` - -```swift -func removeRecords(matching pattern: CacheKey) throws -``` - -Removes records with keys that match the specified pattern. This method will only -remove whole records, it does not perform cascading deletes. This means only the -records with matched keys will be removed, and not any references to them. Key -matching is case-insensitive. - -If you attempt to pass a cache path for a single field, this method will do nothing -since it won't be able to locate a record to remove based on that path. - -- Note: This method can be very slow depending on the number of records in the cache. -It is recommended that this method be called in a background queue. - -- Parameters: - - pattern: The pattern that will be applied to find matching keys. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pattern | The pattern that will be applied to find matching keys. | - -### `clear()` - -```swift -func clear() throws -``` - -Clears all records. diff --git a/docs/source/api/Apollo/protocols/RequestBodyCreator.md b/docs/source/api/Apollo/protocols/RequestBodyCreator.md deleted file mode 100644 index d38506f51a..0000000000 --- a/docs/source/api/Apollo/protocols/RequestBodyCreator.md +++ /dev/null @@ -1,35 +0,0 @@ -**PROTOCOL** - -# `RequestBodyCreator` - -```swift -public protocol RequestBodyCreator -``` - -## Methods -### `requestBody(for:sendOperationIdentifiers:sendQueryDocument:autoPersistQuery:)` - -```swift -func requestBody(for operation: Operation, - sendOperationIdentifiers: Bool, - sendQueryDocument: Bool, - autoPersistQuery: Bool) -> GraphQLMap -``` - -Creates a `GraphQLMap` out of the passed-in operation - -- Parameters: - - operation: The operation to use - - sendOperationIdentifiers: Whether or not to send operation identifiers. Should default to `false`. - - sendQueryDocument: Whether or not to send the full query document. Should default to `true`. - - autoPersistQuery: Whether to use auto-persisted query information. Should default to `false`. -- Returns: The created `GraphQLMap` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to use | -| sendOperationIdentifiers | Whether or not to send operation identifiers. Should default to `false`. | -| sendQueryDocument | Whether or not to send the full query document. Should default to `true`. | -| autoPersistQuery | Whether to use auto-persisted query information. Should default to `false`. | \ No newline at end of file diff --git a/docs/source/api/Apollo/protocols/UploadingNetworkTransport.md b/docs/source/api/Apollo/protocols/UploadingNetworkTransport.md deleted file mode 100644 index aad8e0a0c6..0000000000 --- a/docs/source/api/Apollo/protocols/UploadingNetworkTransport.md +++ /dev/null @@ -1,38 +0,0 @@ -**PROTOCOL** - -# `UploadingNetworkTransport` - -```swift -public protocol UploadingNetworkTransport: NetworkTransport -``` - -A network transport which can also handle uploads of files. - -## Methods -### `upload(operation:files:callbackQueue:completionHandler:)` - -```swift -func upload( - operation: Operation, - files: [GraphQLFile], - callbackQueue: DispatchQueue, - completionHandler: @escaping (Result,Error>) -> Void) -> Cancellable -``` - -Uploads the given files with the given operation. - -- Parameters: - - operation: The operation to send - - files: An array of `GraphQLFile` objects to send. - - callbackQueue: The queue to call back on with the results. Should default to `.main`. - - completionHandler: The completion handler to execute when the request completes or errors -- Returns: An object that can be used to cancel an in progress request. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send | -| files | An array of `GraphQLFile` objects to send. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | The completion handler to execute when the request completes or errors | \ No newline at end of file diff --git a/docs/source/api/Apollo/structs/ApolloRequestBodyCreator.md b/docs/source/api/Apollo/structs/ApolloRequestBodyCreator.md deleted file mode 100644 index 1877e0a0db..0000000000 --- a/docs/source/api/Apollo/structs/ApolloRequestBodyCreator.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `ApolloRequestBodyCreator` - -```swift -public struct ApolloRequestBodyCreator: RequestBodyCreator -``` - -## Methods -### `init()` - -```swift -public init() -``` diff --git a/docs/source/api/Apollo/structs/AutomaticPersistedQueryInterceptor.md b/docs/source/api/Apollo/structs/AutomaticPersistedQueryInterceptor.md deleted file mode 100644 index aee375bf5c..0000000000 --- a/docs/source/api/Apollo/structs/AutomaticPersistedQueryInterceptor.md +++ /dev/null @@ -1,35 +0,0 @@ -**STRUCT** - -# `AutomaticPersistedQueryInterceptor` - -```swift -public struct AutomaticPersistedQueryInterceptor: ApolloInterceptor -``` - -## Methods -### `init()` - -```swift -public init() -``` - -Designated initializer - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/structs/CacheReadInterceptor.md b/docs/source/api/Apollo/structs/CacheReadInterceptor.md deleted file mode 100644 index 42d3cb6750..0000000000 --- a/docs/source/api/Apollo/structs/CacheReadInterceptor.md +++ /dev/null @@ -1,45 +0,0 @@ -**STRUCT** - -# `CacheReadInterceptor` - -```swift -public struct CacheReadInterceptor: ApolloInterceptor -``` - -An interceptor that reads data from the cache for queries, following the `HTTPRequest`'s `cachePolicy`. - -## Methods -### `init(store:)` - -```swift -public init(store: ApolloStore) -``` - -Designated initializer - -- Parameter store: The store to use when reading from the cache. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| store | The store to use when reading from the cache. | - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/structs/CacheReference.md b/docs/source/api/Apollo/structs/CacheReference.md deleted file mode 100644 index 0d2204d58b..0000000000 --- a/docs/source/api/Apollo/structs/CacheReference.md +++ /dev/null @@ -1,23 +0,0 @@ -**STRUCT** - -# `CacheReference` - -```swift -public struct CacheReference -``` - -A reference to a cache record. - -## Properties -### `key` - -```swift -public let key: String -``` - -## Methods -### `init(key:)` - -```swift -public init(key: String) -``` diff --git a/docs/source/api/Apollo/structs/CacheWriteInterceptor.md b/docs/source/api/Apollo/structs/CacheWriteInterceptor.md deleted file mode 100644 index ad53aa3b16..0000000000 --- a/docs/source/api/Apollo/structs/CacheWriteInterceptor.md +++ /dev/null @@ -1,52 +0,0 @@ -**STRUCT** - -# `CacheWriteInterceptor` - -```swift -public struct CacheWriteInterceptor: ApolloInterceptor -``` - -An interceptor which writes data to the cache, following the `HTTPRequest`'s `cachePolicy`. - -## Properties -### `store` - -```swift -public let store: ApolloStore -``` - -## Methods -### `init(store:)` - -```swift -public init(store: ApolloStore) -``` - -Designated initializer - -- Parameter store: The store to use when writing to the cache. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| store | The store to use when writing to the cache. | - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/structs/FieldArguments.md b/docs/source/api/Apollo/structs/FieldArguments.md deleted file mode 100644 index d89d7c4d92..0000000000 --- a/docs/source/api/Apollo/structs/FieldArguments.md +++ /dev/null @@ -1,26 +0,0 @@ -**STRUCT** - -# `FieldArguments` - -```swift -public struct FieldArguments: ExpressibleByDictionaryLiteral -``` - -## Methods -### `init(dictionaryLiteral:)` - -```swift -public init(dictionaryLiteral elements: (String, InputValue)...) -``` - -### `evaluate(with:)` - -```swift -public func evaluate(with variables: [String: JSONEncodable]?) throws -> JSONValue -``` - -### `evaluate(with:)` - -```swift -public func evaluate(with variables: [String: JSONEncodable]?) throws -> JSONObject -``` diff --git a/docs/source/api/Apollo/structs/GraphQLBooleanCondition.md b/docs/source/api/Apollo/structs/GraphQLBooleanCondition.md deleted file mode 100644 index 3b5eebbd2c..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLBooleanCondition.md +++ /dev/null @@ -1,16 +0,0 @@ -**STRUCT** - -# `GraphQLBooleanCondition` - -```swift -public struct GraphQLBooleanCondition: GraphQLSelection -``` - -## Methods -### `init(variableName:inverted:selections:)` - -```swift -public init(variableName: String, - inverted: Bool, - selections: [GraphQLSelection]) -``` diff --git a/docs/source/api/Apollo/structs/GraphQLError.Location.md b/docs/source/api/Apollo/structs/GraphQLError.Location.md deleted file mode 100644 index 973299c804..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLError.Location.md +++ /dev/null @@ -1,26 +0,0 @@ -**STRUCT** - -# `GraphQLError.Location` - -```swift -public struct Location -``` - -Represents a location in a GraphQL document. - -## Properties -### `line` - -```swift -public let line: Int -``` - -The line number of a syntax element. - -### `column` - -```swift -public let column: Int -``` - -The column number of a syntax element. diff --git a/docs/source/api/Apollo/structs/GraphQLError.md b/docs/source/api/Apollo/structs/GraphQLError.md deleted file mode 100644 index 8cce95136b..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLError.md +++ /dev/null @@ -1,43 +0,0 @@ -**STRUCT** - -# `GraphQLError` - -```swift -public struct GraphQLError: Error -``` - -Represents an error encountered during the execution of a GraphQL operation. - - - SeeAlso: [The Response Format section in the GraphQL specification](https://facebook.github.io/graphql/#sec-Response-Format) - -## Properties -### `message` - -```swift -public var message: String? -``` - -A description of the error. - -### `locations` - -```swift -public var locations: [Location]? -``` - -A list of locations in the requested GraphQL document associated with the error. - -### `extensions` - -```swift -public var extensions: [String : Any]? -``` - -A dictionary which services can use however they see fit to provide additional information in errors to clients. - -## Methods -### `init(_:)` - -```swift -public init(_ object: JSONObject) -``` diff --git a/docs/source/api/Apollo/structs/GraphQLField.md b/docs/source/api/Apollo/structs/GraphQLField.md deleted file mode 100644 index 5100270cfd..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLField.md +++ /dev/null @@ -1,23 +0,0 @@ -**STRUCT** - -# `GraphQLField` - -```swift -public struct GraphQLField: GraphQLSelection -``` - -## Methods -### `init(_:alias:arguments:type:)` - -```swift -public init(_ name: String, - alias: String? = nil, - arguments: FieldArguments? = nil, - type: GraphQLOutputType) -``` - -### `cacheKey(with:)` - -```swift -public func cacheKey(with variables: [String: JSONEncodable]?) throws -> String -``` diff --git a/docs/source/api/Apollo/structs/GraphQLFile.md b/docs/source/api/Apollo/structs/GraphQLFile.md deleted file mode 100644 index 53673632a3..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLFile.md +++ /dev/null @@ -1,121 +0,0 @@ -**STRUCT** - -# `GraphQLFile` - -```swift -public struct GraphQLFile -``` - -A file which can be uploaded to a GraphQL server - -## Properties -### `fieldName` - -```swift -public let fieldName: String -``` - -### `originalName` - -```swift -public let originalName: String -``` - -### `mimeType` - -```swift -public let mimeType: String -``` - -### `data` - -```swift -public let data: Data? -``` - -### `fileURL` - -```swift -public let fileURL: URL? -``` - -### `contentLength` - -```swift -public let contentLength: UInt64 -``` - -### `octetStreamMimeType` - -```swift -public static let octetStreamMimeType = "application/octet-stream" -``` - -A convenience constant for declaring your mimetype is octet-stream. - -## Methods -### `init(fieldName:originalName:mimeType:data:)` - -```swift -public init(fieldName: String, - originalName: String, - mimeType: String = GraphQLFile.octetStreamMimeType, - data: Data) -``` - -Convenience initializer for raw data - -- Parameters: - - fieldName: The name of the field this file is being sent for - - originalName: The original name of the file - - mimeType: The mime type of the file to send to the server. Defaults to `GraphQLFile.octetStreamMimeType`. - - data: The raw data to send for the file. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| fieldName | The name of the field this file is being sent for | -| originalName | The original name of the file | -| mimeType | The mime type of the file to send to the server. Defaults to `GraphQLFile.octetStreamMimeType`. | -| data | The raw data to send for the file. | - -### `init(fieldName:originalName:mimeType:fileURL:)` - -```swift -public init(fieldName: String, - originalName: String, - mimeType: String = GraphQLFile.octetStreamMimeType, - fileURL: URL) throws -``` - -Throwing convenience initializer for files in the filesystem - -- Parameters: - - fieldName: The name of the field this file is being sent for - - originalName: The original name of the file - - mimeType: The mime type of the file to send to the server. Defaults to `GraphQLFile.octetStreamMimeType`. - - fileURL: The URL of the file to upload. -- Throws: If the file's size could not be determined - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| fieldName | The name of the field this file is being sent for | -| originalName | The original name of the file | -| mimeType | The mime type of the file to send to the server. Defaults to `GraphQLFile.octetStreamMimeType`. | -| fileURL | The URL of the file to upload. | - -### `generateInputStream()` - -```swift -public func generateInputStream() throws -> InputStream -``` - -Uses either the data or the file URL to create an -`InputStream` that can be used to stream data into -a multipart-form. - -- Returns: The created `InputStream`. -- Throws: If an input stream could not be created from either data or a file URL. diff --git a/docs/source/api/Apollo/structs/GraphQLFragmentSpread.md b/docs/source/api/Apollo/structs/GraphQLFragmentSpread.md deleted file mode 100644 index 38d4be6499..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLFragmentSpread.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `GraphQLFragmentSpread` - -```swift -public struct GraphQLFragmentSpread: GraphQLSelection -``` - -## Methods -### `init(_:)` - -```swift -public init(_ fragment: GraphQLFragment.Type) -``` diff --git a/docs/source/api/Apollo/structs/GraphQLGETTransformer.md b/docs/source/api/Apollo/structs/GraphQLGETTransformer.md deleted file mode 100644 index d8d045751d..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLGETTransformer.md +++ /dev/null @@ -1,37 +0,0 @@ -**STRUCT** - -# `GraphQLGETTransformer` - -```swift -public struct GraphQLGETTransformer -``` - -## Methods -### `init(body:url:)` - -```swift -public init(body: GraphQLMap, url: URL) -``` - -A helper for transforming a GraphQLMap that can be sent with a `POST` request into a URL with query parameters for a `GET` request. - -- Parameters: - - body: The GraphQLMap to transform from the body of a `POST` request - - url: The base url to append the query to. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| body | The GraphQLMap to transform from the body of a `POST` request | -| url | The base url to append the query to. | - -### `createGetURL()` - -```swift -public func createGetURL() -> URL? -``` - -Creates the get URL. - -- Returns: [optional] The created get URL or nil if the provided information couldn't be used to access the appropriate parameters. diff --git a/docs/source/api/Apollo/structs/GraphQLResult.md b/docs/source/api/Apollo/structs/GraphQLResult.md deleted file mode 100644 index 6278cb2e44..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLResult.md +++ /dev/null @@ -1,53 +0,0 @@ -**STRUCT** - -# `GraphQLResult` - -```swift -public struct GraphQLResult -``` - -Represents the result of a GraphQL operation. - -## Properties -### `data` - -```swift -public let data: Data? -``` - -The typed result data, or `nil` if an error was encountered that prevented a valid response. - -### `errors` - -```swift -public let errors: [GraphQLError]? -``` - -A list of errors, or `nil` if the operation completed without encountering any errors. - -### `extensions` - -```swift -public let extensions: [String: Any]? -``` - -A dictionary which services can use however they see fit to provide additional information to clients. - -### `source` - -```swift -public let source: Source -``` - -Source of data - -## Methods -### `init(data:extensions:errors:source:dependentKeys:)` - -```swift -public init(data: Data?, - extensions: [String: Any]?, - errors: [GraphQLError]?, - source: Source, - dependentKeys: Set?) -``` diff --git a/docs/source/api/Apollo/structs/GraphQLResultError.md b/docs/source/api/Apollo/structs/GraphQLResultError.md deleted file mode 100644 index d8938b3533..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLResultError.md +++ /dev/null @@ -1,32 +0,0 @@ -**STRUCT** - -# `GraphQLResultError` - -```swift -public struct GraphQLResultError: Error, LocalizedError -``` - -An error which has occurred in processing a GraphQLResult - -## Properties -### `pathString` - -```swift -public var pathString: String -``` - -### `underlying` - -```swift -public let underlying: Error -``` - -The error that occurred during parsing. - -### `errorDescription` - -```swift -public var errorDescription: String? -``` - -A description of the error which includes the path where the error occurred. diff --git a/docs/source/api/Apollo/structs/GraphQLTypeCase.md b/docs/source/api/Apollo/structs/GraphQLTypeCase.md deleted file mode 100644 index 81e518740b..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLTypeCase.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `GraphQLTypeCase` - -```swift -public struct GraphQLTypeCase: GraphQLSelection -``` - -## Methods -### `init(variants:default:)` - -```swift -public init(variants: [String: [GraphQLSelection]], default: [GraphQLSelection]) -``` diff --git a/docs/source/api/Apollo/structs/GraphQLTypeCondition.md b/docs/source/api/Apollo/structs/GraphQLTypeCondition.md deleted file mode 100644 index 2e7edab946..0000000000 --- a/docs/source/api/Apollo/structs/GraphQLTypeCondition.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `GraphQLTypeCondition` - -```swift -public struct GraphQLTypeCondition: GraphQLSelection -``` - -## Methods -### `init(possibleTypes:selections:)` - -```swift -public init(possibleTypes: [String], selections: [GraphQLSelection]) -``` diff --git a/docs/source/api/Apollo/structs/JSONResponseParsingInterceptor.md b/docs/source/api/Apollo/structs/JSONResponseParsingInterceptor.md deleted file mode 100644 index 6af0b57db3..0000000000 --- a/docs/source/api/Apollo/structs/JSONResponseParsingInterceptor.md +++ /dev/null @@ -1,45 +0,0 @@ -**STRUCT** - -# `JSONResponseParsingInterceptor` - -```swift -public struct JSONResponseParsingInterceptor: ApolloInterceptor -``` - -An interceptor which parses JSON response data into a `GraphQLResult` and attaches it to the `HTTPResponse`. - -## Properties -### `cacheKeyForObject` - -```swift -public let cacheKeyForObject: CacheKeyForObject? -``` - -## Methods -### `init(cacheKeyForObject:)` - -```swift -public init(cacheKeyForObject: CacheKeyForObject? = nil) -``` - -Designated Initializer - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void -) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/structs/JSONValueMatcher.md b/docs/source/api/Apollo/structs/JSONValueMatcher.md deleted file mode 100644 index 6e8a37464c..0000000000 --- a/docs/source/api/Apollo/structs/JSONValueMatcher.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `JSONValueMatcher` - -```swift -public struct JSONValueMatcher -``` - -## Methods -### `equals(_:_:)` - -```swift -public static func equals(_ lhs: Any, _ rhs: Any) -> Bool -``` diff --git a/docs/source/api/Apollo/structs/Record.md b/docs/source/api/Apollo/structs/Record.md deleted file mode 100644 index 939e02482f..0000000000 --- a/docs/source/api/Apollo/structs/Record.md +++ /dev/null @@ -1,29 +0,0 @@ -**STRUCT** - -# `Record` - -```swift -public struct Record -``` - -A cache record. - -## Properties -### `key` - -```swift -public let key: CacheKey -``` - -### `fields` - -```swift -public private(set) var fields: Fields -``` - -## Methods -### `init(key:_:)` - -```swift -public init(key: CacheKey, _ fields: Fields = [:]) -``` diff --git a/docs/source/api/Apollo/structs/RecordSet.md b/docs/source/api/Apollo/structs/RecordSet.md deleted file mode 100644 index 8538c020c3..0000000000 --- a/docs/source/api/Apollo/structs/RecordSet.md +++ /dev/null @@ -1,77 +0,0 @@ -**STRUCT** - -# `RecordSet` - -```swift -public struct RecordSet -``` - -A set of cache records. - -## Properties -### `storage` - -```swift -public private(set) var storage: [CacheKey: Record] = [:] -``` - -### `isEmpty` - -```swift -public var isEmpty: Bool -``` - -### `keys` - -```swift -public var keys: Set -``` - -## Methods -### `init(records:)` - -```swift -public init(records: S) where S.Iterator.Element == Record -``` - -### `insert(_:)` - -```swift -public mutating func insert(_ record: Record) -``` - -### `removeRecord(for:)` - -```swift -public mutating func removeRecord(for key: CacheKey) -``` - -### `removeRecords(matching:)` - -```swift -public mutating func removeRecords(matching pattern: CacheKey) -``` - -### `clear()` - -```swift -public mutating func clear() -``` - -### `insert(contentsOf:)` - -```swift -public mutating func insert(contentsOf records: S) where S.Iterator.Element == Record -``` - -### `merge(records:)` - -```swift -@discardableResult public mutating func merge(records: RecordSet) -> Set -``` - -### `merge(record:)` - -```swift -@discardableResult public mutating func merge(record: Record) -> Set -``` diff --git a/docs/source/api/Apollo/structs/ResponseCodeInterceptor.md b/docs/source/api/Apollo/structs/ResponseCodeInterceptor.md deleted file mode 100644 index 6e8ecfb568..0000000000 --- a/docs/source/api/Apollo/structs/ResponseCodeInterceptor.md +++ /dev/null @@ -1,37 +0,0 @@ -**STRUCT** - -# `ResponseCodeInterceptor` - -```swift -public struct ResponseCodeInterceptor: ApolloInterceptor -``` - -An interceptor to check the response code returned with a request. - -## Methods -### `init()` - -```swift -public init() -``` - -Designated initializer - -### `interceptAsync(chain:request:response:completion:)` - -```swift -public func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| chain | The chain the interceptor is a part of. | -| request | The request, as far as it has been constructed | -| response | [optional] The response, if received | -| completion | The completion block to fire when data needs to be returned to the UI. | \ No newline at end of file diff --git a/docs/source/api/Apollo/typealiases/CacheKey.md b/docs/source/api/Apollo/typealiases/CacheKey.md deleted file mode 100644 index 11979fa02f..0000000000 --- a/docs/source/api/Apollo/typealiases/CacheKey.md +++ /dev/null @@ -1,9 +0,0 @@ -**TYPEALIAS** - -# `CacheKey` - -```swift -public typealias CacheKey = String -``` - -A cache key for a record. \ No newline at end of file diff --git a/docs/source/api/Apollo/typealiases/CacheKeyForObject.md b/docs/source/api/Apollo/typealiases/CacheKeyForObject.md deleted file mode 100644 index c7c827558b..0000000000 --- a/docs/source/api/Apollo/typealiases/CacheKeyForObject.md +++ /dev/null @@ -1,9 +0,0 @@ -**TYPEALIAS** - -# `CacheKeyForObject` - -```swift -public typealias CacheKeyForObject = (_ object: JSONObject) -> JSONValue? -``` - -A function that returns a cache key for a particular result object. If it returns `nil`, a default cache key based on the field path will be used. \ No newline at end of file diff --git a/docs/source/api/Apollo/typealiases/DataLoader.BatchLoad.md b/docs/source/api/Apollo/typealiases/DataLoader.BatchLoad.md deleted file mode 100644 index be78601c7d..0000000000 --- a/docs/source/api/Apollo/typealiases/DataLoader.BatchLoad.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `DataLoader.BatchLoad` - -```swift -public typealias BatchLoad = (Set) throws -> [Key: Value] -``` diff --git a/docs/source/api/Apollo/typealiases/DidChangeKeysFunc.md b/docs/source/api/Apollo/typealiases/DidChangeKeysFunc.md deleted file mode 100644 index 78becdf477..0000000000 --- a/docs/source/api/Apollo/typealiases/DidChangeKeysFunc.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `DidChangeKeysFunc` - -```swift -public typealias DidChangeKeysFunc = (Set, UUID?) -> Void -``` diff --git a/docs/source/api/Apollo/typealiases/GraphQLID.md b/docs/source/api/Apollo/typealiases/GraphQLID.md deleted file mode 100644 index 53d710388c..0000000000 --- a/docs/source/api/Apollo/typealiases/GraphQLID.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `GraphQLID` - -```swift -public typealias GraphQLID = String -``` diff --git a/docs/source/api/Apollo/typealiases/GraphQLMap.md b/docs/source/api/Apollo/typealiases/GraphQLMap.md deleted file mode 100644 index c1cfbb24f9..0000000000 --- a/docs/source/api/Apollo/typealiases/GraphQLMap.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `GraphQLMap` - -```swift -public typealias GraphQLMap = [String: JSONEncodable?] -``` diff --git a/docs/source/api/Apollo/typealiases/GraphQLResultHandler.md b/docs/source/api/Apollo/typealiases/GraphQLResultHandler.md deleted file mode 100644 index 9170f5fb73..0000000000 --- a/docs/source/api/Apollo/typealiases/GraphQLResultHandler.md +++ /dev/null @@ -1,12 +0,0 @@ -**TYPEALIAS** - -# `GraphQLResultHandler` - -```swift -public typealias GraphQLResultHandler = (Result, Error>) -> Void -``` - -A handler for operation results. - -- Parameters: - - result: The result of a performed operation. Will have a `GraphQLResult` with any parsed data and any GraphQL errors on `success`, and an `Error` on `failure`. \ No newline at end of file diff --git a/docs/source/api/Apollo/typealiases/JSONObject.md b/docs/source/api/Apollo/typealiases/JSONObject.md deleted file mode 100644 index 3c258fba44..0000000000 --- a/docs/source/api/Apollo/typealiases/JSONObject.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `JSONObject` - -```swift -public typealias JSONObject = [String: JSONValue] -``` diff --git a/docs/source/api/Apollo/typealiases/JSONValue.md b/docs/source/api/Apollo/typealiases/JSONValue.md deleted file mode 100644 index 5804fbea97..0000000000 --- a/docs/source/api/Apollo/typealiases/JSONValue.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `JSONValue` - -```swift -public typealias JSONValue = Any -``` diff --git a/docs/source/api/Apollo/typealiases/Record.Fields.md b/docs/source/api/Apollo/typealiases/Record.Fields.md deleted file mode 100644 index 9768d32ff0..0000000000 --- a/docs/source/api/Apollo/typealiases/Record.Fields.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `Record.Fields` - -```swift -public typealias Fields = [CacheKey: Value] -``` diff --git a/docs/source/api/Apollo/typealiases/Record.Value.md b/docs/source/api/Apollo/typealiases/Record.Value.md deleted file mode 100644 index aa3488fc5d..0000000000 --- a/docs/source/api/Apollo/typealiases/Record.Value.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `Record.Value` - -```swift -public typealias Value = Any -``` diff --git a/docs/source/api/Apollo/typealiases/ResultMap.md b/docs/source/api/Apollo/typealiases/ResultMap.md deleted file mode 100644 index 7efae72794..0000000000 --- a/docs/source/api/Apollo/typealiases/ResultMap.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `ResultMap` - -```swift -public typealias ResultMap = [String: Any?] -``` diff --git a/docs/source/api/Apollo/typealiases/URLSessionClient.Completion.md b/docs/source/api/Apollo/typealiases/URLSessionClient.Completion.md deleted file mode 100644 index 19aef74ca3..0000000000 --- a/docs/source/api/Apollo/typealiases/URLSessionClient.Completion.md +++ /dev/null @@ -1,9 +0,0 @@ -**TYPEALIAS** - -# `URLSessionClient.Completion` - -```swift -public typealias Completion = (Result<(Data, HTTPURLResponse), Error>) -> Void -``` - -A completion block returning a result. On `.success` it will contain a tuple with non-nil `Data` and its corresponding `HTTPURLResponse`. On `.failure` it will contain an error. \ No newline at end of file diff --git a/docs/source/api/Apollo/typealiases/URLSessionClient.RawCompletion.md b/docs/source/api/Apollo/typealiases/URLSessionClient.RawCompletion.md deleted file mode 100644 index 89b05ddb07..0000000000 --- a/docs/source/api/Apollo/typealiases/URLSessionClient.RawCompletion.md +++ /dev/null @@ -1,9 +0,0 @@ -**TYPEALIAS** - -# `URLSessionClient.RawCompletion` - -```swift -public typealias RawCompletion = (Data?, HTTPURLResponse?, Error?) -> Void -``` - -A completion block to be called when the raw task has completed, with the raw information from the session \ No newline at end of file diff --git a/docs/source/api/ApolloAPI/README.md b/docs/source/api/ApolloAPI/README.md deleted file mode 100644 index eb3e326f0f..0000000000 --- a/docs/source/api/ApolloAPI/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Reference Documentation - -## Protocols - -- [AnySelectionSet](protocols/AnySelectionSet/) -- [Fragment](protocols/Fragment/) -- [GraphQLSchema](protocols/GraphQLSchema/) -- [HasFragments](protocols/HasFragments/) -- [ResponseObject](protocols/ResponseObject/) -- [ScalarType](protocols/ScalarType/) -- [SchemaObjectType](protocols/SchemaObjectType/) -- [SchemaTypeEnum](protocols/SchemaTypeEnum/) -- [SchemaUnion](protocols/SchemaUnion/) -- [SelectionSet](protocols/SelectionSet/) - -## Structs - -- [Field.Arguments](structs/Field.Arguments/) -- [ResponseDict](structs/ResponseDict/) -- [Selection.BooleanCondition](structs/Selection.BooleanCondition/) -- [Selection.Field](structs/Selection.Field/) -- [Selection.FragmentSpread](structs/Selection.FragmentSpread/) -- [Selection.TypeCase](structs/Selection.TypeCase/) - -## Enums - -- [Field.OutputType](enums/Field.OutputType/) -- [GraphQLEnum](enums/GraphQLEnum/) -- [GraphQLOptional](enums/GraphQLOptional/) -- [InputValue](enums/InputValue/) -- [Selection](enums/Selection/) -- [SelectionSetType](enums/SelectionSetType/) - -## Extensions - -- [GraphQLEnum](extensions/GraphQLEnum/) -- [GraphQLOptional](extensions/GraphQLOptional/) -- [InputValue](extensions/InputValue/) -- [KeyedDecodingContainer](extensions/KeyedDecodingContainer/) -- [KeyedEncodingContainer](extensions/KeyedEncodingContainer/) - -## Typealiases - -- [GraphQLEnum.RawValue](typealiases/GraphQLEnum.RawValue/) - -## Methods - -- [!=(____)](methods/!=(____)/) -- [==(____)](methods/==(____)/) -- [~=(____)](methods/~=(____)/) - -This file was generated by [SourceDocs](https://github.com/eneko/SourceDocs) \ No newline at end of file diff --git a/docs/source/api/ApolloAPI/enums/Field.OutputType.md b/docs/source/api/ApolloAPI/enums/Field.OutputType.md deleted file mode 100644 index 291eaa2d40..0000000000 --- a/docs/source/api/ApolloAPI/enums/Field.OutputType.md +++ /dev/null @@ -1,32 +0,0 @@ -**ENUM** - -# `Field.OutputType` - -```swift -public indirect enum OutputType -``` - -## Cases -### `scalar(_:)` - -```swift -case scalar(Any.Type) -``` - -### `object(_:)` - -```swift -case object([Selection]) -``` - -### `nonNull(_:)` - -```swift -case nonNull(OutputType) -``` - -### `list(_:)` - -```swift -case list(OutputType) -``` diff --git a/docs/source/api/ApolloAPI/enums/GraphQLEnum.md b/docs/source/api/ApolloAPI/enums/GraphQLEnum.md deleted file mode 100644 index 11ca74097f..0000000000 --- a/docs/source/api/ApolloAPI/enums/GraphQLEnum.md +++ /dev/null @@ -1,75 +0,0 @@ -**ENUM** - -# `GraphQLEnum` - -```swift -public enum GraphQLEnum: CaseIterable, Equatable, RawRepresentable -where T: RawRepresentable & CaseIterable, T.RawValue == String -``` - -A generic enum that wraps a generated enum from a GraphQL Schema. - -`GraphQLEnum` provides an `__unknown` case that is used when the response returns a value that -is not recognized as a valid enum case. This is usually caused by future cases added to the enum -on the schema after code generation. - -## Cases -### `case(_:)` - -```swift -case `case`(T) -``` - -A recognized case of the wrapped enum. - -### `__unknown(_:)` - -```swift -case __unknown(String) -``` - -An unrecognized value for the enum. -The associated value exposes the raw `String` data from the response. - -## Properties -### `value` - -```swift -public var value: T? -``` - -The underlying enum case. If the value is `__unknown`, this will be `nil`. - -### `rawValue` - -```swift -public var rawValue: String -``` - -### `allCases` - -```swift -public static var allCases: [GraphQLEnum] -``` - -A collection of all known values of the wrapped enum. -This collection does not include the `__unknown` case. - -## Methods -### `init(_:)` - -```swift -public init(_ caseValue: T) -``` - -### `init(rawValue:)` - -```swift -public init(rawValue: String) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| rawValue | The raw value to use for the new instance. | \ No newline at end of file diff --git a/docs/source/api/ApolloAPI/enums/GraphQLOptional.md b/docs/source/api/ApolloAPI/enums/GraphQLOptional.md deleted file mode 100644 index f87e4d84cc..0000000000 --- a/docs/source/api/ApolloAPI/enums/GraphQLOptional.md +++ /dev/null @@ -1,26 +0,0 @@ -**ENUM** - -# `GraphQLOptional` - -```swift -public enum GraphQLOptional -``` - -## Cases -### `notPresent` - -```swift -case notPresent -``` - -### `nullValue` - -```swift -case nullValue -``` - -### `value(_:)` - -```swift -case value(T) -``` diff --git a/docs/source/api/ApolloAPI/enums/InputValue.md b/docs/source/api/ApolloAPI/enums/InputValue.md deleted file mode 100644 index c0c559cafd..0000000000 --- a/docs/source/api/ApolloAPI/enums/InputValue.md +++ /dev/null @@ -1,56 +0,0 @@ -**ENUM** - -# `InputValue` - -```swift -public indirect enum InputValue -``` - -Represents an input value to an argument on a `GraphQLField`'s `FieldArguments`. - -- See: [GraphQLSpec - Input Values](http://spec.graphql.org/June2018/#sec-Input-Values) - -## Cases -### `scalar(_:)` - -```swift -case scalar(ScalarType) -``` - -A direct input value, valid types are `String`, `Int` `Float` and `Bool`. -For enum input values, the enum cases's `rawValue` as a `String` should be used. - -### `variable(_:)` - -```swift -case variable(String) -``` - -A variable input value to be evaluated using the operation's `variables` dictionary at runtime. - -### `list(_:)` - -```swift -case list([InputValue]) -``` - -A GraphQL "List" input value. -- See: [GraphQLSpec - Input Values - List Value](http://spec.graphql.org/June2018/#sec-List-Value) - -### `object(_:)` - -```swift -case object([String: InputValue]) -``` - -A GraphQL "InputObject" input value. Represented as a dictionary of input values. -- See: [GraphQLSpec - Input Values - Input Object Values](http://spec.graphql.org/June2018/#sec-Input-Object-Values) - -### `none` - -```swift -case none -``` - -A null input value. -- See: [GraphQLSpec - Input Values - Null Value](http://spec.graphql.org/June2018/#sec-Null-Value) diff --git a/docs/source/api/ApolloAPI/enums/Selection.md b/docs/source/api/ApolloAPI/enums/Selection.md deleted file mode 100644 index 1791c7c397..0000000000 --- a/docs/source/api/ApolloAPI/enums/Selection.md +++ /dev/null @@ -1,32 +0,0 @@ -**ENUM** - -# `Selection` - -```swift -public enum Selection -``` - -## Cases -### `field(_:)` - -```swift -case field(Field) -``` - -### `booleanCondition(_:)` - -```swift -case booleanCondition(BooleanCondition) -``` - -### `typeCase(_:)` - -```swift -case typeCase(TypeCase) -``` - -### `fragmentSpread(_:)` - -```swift -case fragmentSpread(FragmentSpread) -``` diff --git a/docs/source/api/ApolloAPI/enums/SelectionSetType.md b/docs/source/api/ApolloAPI/enums/SelectionSetType.md deleted file mode 100644 index f063338b5e..0000000000 --- a/docs/source/api/ApolloAPI/enums/SelectionSetType.md +++ /dev/null @@ -1,26 +0,0 @@ -**ENUM** - -# `SelectionSetType` - -```swift -public enum SelectionSetType -``` - -## Cases -### `ObjectType(_:)` - -```swift -case ObjectType(S.ObjectType) -``` - -### `Interface(_:)` - -```swift -case Interface(S.Interface) -``` - -### `Union(_:)` - -```swift -case Union(S.Union) -``` diff --git a/docs/source/api/ApolloAPI/extensions/GraphQLEnum.md b/docs/source/api/ApolloAPI/extensions/GraphQLEnum.md deleted file mode 100644 index b545fdbbdb..0000000000 --- a/docs/source/api/ApolloAPI/extensions/GraphQLEnum.md +++ /dev/null @@ -1,32 +0,0 @@ -**EXTENSION** - -# `GraphQLEnum` -```swift -extension GraphQLEnum -``` - -## Methods -### `==(_:_:)` - -```swift -public static func ==(lhs: GraphQLEnum, rhs: GraphQLEnum) -> Bool -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| lhs | A value to compare. | -| rhs | Another value to compare. | - -### `==(_:_:)` - -```swift -public static func ==(lhs: GraphQLEnum, rhs: T) -> Bool -``` - -### `!=(_:_:)` - -```swift -public static func !=(lhs: GraphQLEnum, rhs: T) -> Bool -``` diff --git a/docs/source/api/ApolloAPI/extensions/GraphQLOptional.md b/docs/source/api/ApolloAPI/extensions/GraphQLOptional.md deleted file mode 100644 index 8110ec8c8e..0000000000 --- a/docs/source/api/ApolloAPI/extensions/GraphQLOptional.md +++ /dev/null @@ -1,32 +0,0 @@ -**EXTENSION** - -# `GraphQLOptional` -```swift -extension GraphQLOptional: Hashable where T: Hashable -``` - -## Methods -### `hash(into:)` - -```swift -public func hash(into hasher: inout Hasher) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| hasher | The hasher to use when combining the components of this instance. | - -### `==(_:_:)` - -```swift -public static func ==(lhs: GraphQLOptional, rhs: GraphQLOptional) -> Bool -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| lhs | A value to compare. | -| rhs | Another value to compare. | \ No newline at end of file diff --git a/docs/source/api/ApolloAPI/extensions/InputValue.md b/docs/source/api/ApolloAPI/extensions/InputValue.md deleted file mode 100644 index f719ef8c33..0000000000 --- a/docs/source/api/ApolloAPI/extensions/InputValue.md +++ /dev/null @@ -1,73 +0,0 @@ -**EXTENSION** - -# `InputValue` -```swift -extension InputValue: ExpressibleByNilLiteral -``` - -## Methods -### `init(nilLiteral:)` - -```swift -@inlinable public init(nilLiteral: ()) -``` - -### `init(stringLiteral:)` - -```swift -@inlinable public init(stringLiteral value: StringLiteralType) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| value | The value of the new instance. | - -### `init(integerLiteral:)` - -```swift -@inlinable public init(integerLiteral value: IntegerLiteralType) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| value | The value to create. | - -### `init(floatLiteral:)` - -```swift -@inlinable public init(floatLiteral value: FloatLiteralType) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| value | The value to create. | - -### `init(booleanLiteral:)` - -```swift -@inlinable public init(booleanLiteral value: BooleanLiteralType) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| value | The value of the new instance. | - -### `init(arrayLiteral:)` - -```swift -@inlinable public init(arrayLiteral elements: InputValue...) -``` - -### `init(dictionaryLiteral:)` - -```swift -public init(dictionaryLiteral elements: (String, InputValue)...) -``` diff --git a/docs/source/api/ApolloAPI/extensions/KeyedDecodingContainer.md b/docs/source/api/ApolloAPI/extensions/KeyedDecodingContainer.md deleted file mode 100644 index 8cfbbd3184..0000000000 --- a/docs/source/api/ApolloAPI/extensions/KeyedDecodingContainer.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `KeyedDecodingContainer` -```swift -public extension KeyedDecodingContainer -``` - -## Methods -### `decodeGraphQLOptional(forKey:)` - -```swift -func decodeGraphQLOptional(forKey key: K) throws -> GraphQLOptional -``` diff --git a/docs/source/api/ApolloAPI/extensions/KeyedEncodingContainer.md b/docs/source/api/ApolloAPI/extensions/KeyedEncodingContainer.md deleted file mode 100644 index 571f540f6e..0000000000 --- a/docs/source/api/ApolloAPI/extensions/KeyedEncodingContainer.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `KeyedEncodingContainer` -```swift -public extension KeyedEncodingContainer -``` - -## Methods -### `encodeGraphQLOptional(_:forKey:)` - -```swift -mutating func encodeGraphQLOptional(_ optional: GraphQLOptional, forKey key: K) throws -``` diff --git a/docs/source/api/ApolloAPI/methods/!=(____).md b/docs/source/api/ApolloAPI/methods/!=(____).md deleted file mode 100644 index 0b3439a43e..0000000000 --- a/docs/source/api/ApolloAPI/methods/!=(____).md +++ /dev/null @@ -1,6 +0,0 @@ -### `!=(_:_:)` - -```swift -public func !=(lhs: GraphQLEnum?, rhs: T) -> Bool -where T.RawValue == String -``` diff --git a/docs/source/api/ApolloAPI/methods/==(____).md b/docs/source/api/ApolloAPI/methods/==(____).md deleted file mode 100644 index 0d8f3079d7..0000000000 --- a/docs/source/api/ApolloAPI/methods/==(____).md +++ /dev/null @@ -1,6 +0,0 @@ -### `==(_:_:)` - -```swift -public func ==(lhs: GraphQLEnum?, rhs: T) -> Bool -where T.RawValue == String -``` diff --git a/docs/source/api/ApolloAPI/methods/~=(____).md b/docs/source/api/ApolloAPI/methods/~=(____).md deleted file mode 100644 index 1fa1ae454f..0000000000 --- a/docs/source/api/ApolloAPI/methods/~=(____).md +++ /dev/null @@ -1,5 +0,0 @@ -### `~=(_:_:)` - -```swift -public func ~=(lhs: T, rhs: GraphQLEnum) -> Bool -``` diff --git a/docs/source/api/ApolloAPI/protocols/AnySelectionSet.md b/docs/source/api/ApolloAPI/protocols/AnySelectionSet.md deleted file mode 100644 index 5c552d8060..0000000000 --- a/docs/source/api/ApolloAPI/protocols/AnySelectionSet.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `AnySelectionSet` - -```swift -public protocol AnySelectionSet: ResponseObject -``` - -## Properties -### `selections` - -```swift -static var selections: [Selection] -``` diff --git a/docs/source/api/ApolloAPI/protocols/Fragment.md b/docs/source/api/ApolloAPI/protocols/Fragment.md deleted file mode 100644 index 2ed9348395..0000000000 --- a/docs/source/api/ApolloAPI/protocols/Fragment.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `Fragment` - -```swift -public protocol Fragment: SelectionSet -``` - -A protocol representing a fragment that a `ResponseObject` object may be converted to. - -A `ResponseObject` that conforms to `HasFragments` can be converted to -any `Fragment` included in it's `Fragments` object via its `fragments` property. - -- SeeAlso: `HasFragments`, `ToFragments` diff --git a/docs/source/api/ApolloAPI/protocols/GraphQLSchema.md b/docs/source/api/ApolloAPI/protocols/GraphQLSchema.md deleted file mode 100644 index 12c65cdab7..0000000000 --- a/docs/source/api/ApolloAPI/protocols/GraphQLSchema.md +++ /dev/null @@ -1,13 +0,0 @@ -**PROTOCOL** - -# `GraphQLSchema` - -```swift -public protocol GraphQLSchema -``` - -A protocol that a generated GraphQL Schema should conform to. - -A `GraphQLSchema` contains information on the types within a schema and their relationships -to other types. This information is used to verify that a `SelectionSet` can be converted to -a given type condition. diff --git a/docs/source/api/ApolloAPI/protocols/HasFragments.md b/docs/source/api/ApolloAPI/protocols/HasFragments.md deleted file mode 100644 index 4e2531d6d0..0000000000 --- a/docs/source/api/ApolloAPI/protocols/HasFragments.md +++ /dev/null @@ -1,9 +0,0 @@ -**PROTOCOL** - -# `HasFragments` - -```swift -public protocol HasFragments: SelectionSet -``` - -A protocol that a `ResponseObject` that contains fragments should conform to. diff --git a/docs/source/api/ApolloAPI/protocols/ResponseObject.md b/docs/source/api/ApolloAPI/protocols/ResponseObject.md deleted file mode 100644 index 82910fb256..0000000000 --- a/docs/source/api/ApolloAPI/protocols/ResponseObject.md +++ /dev/null @@ -1,21 +0,0 @@ -**PROTOCOL** - -# `ResponseObject` - -```swift -public protocol ResponseObject -``` - -## Properties -### `data` - -```swift -var data: ResponseDict -``` - -## Methods -### `init(data:)` - -```swift -init(data: ResponseDict) -``` diff --git a/docs/source/api/ApolloAPI/protocols/ScalarType.md b/docs/source/api/ApolloAPI/protocols/ScalarType.md deleted file mode 100644 index 3f4e69c90e..0000000000 --- a/docs/source/api/ApolloAPI/protocols/ScalarType.md +++ /dev/null @@ -1,7 +0,0 @@ -**PROTOCOL** - -# `ScalarType` - -```swift -public protocol ScalarType -``` diff --git a/docs/source/api/ApolloAPI/protocols/SchemaObjectType.md b/docs/source/api/ApolloAPI/protocols/SchemaObjectType.md deleted file mode 100644 index 307f7e80f0..0000000000 --- a/docs/source/api/ApolloAPI/protocols/SchemaObjectType.md +++ /dev/null @@ -1,20 +0,0 @@ -**PROTOCOL** - -# `SchemaObjectType` - -```swift -public protocol SchemaObjectType: SchemaTypeEnum -``` - -## Properties -### `unknownCase` - -```swift -static var unknownCase: Self -``` - -### `implementedInterfaces` - -```swift -var implementedInterfaces: [Interface] -``` diff --git a/docs/source/api/ApolloAPI/protocols/SchemaTypeEnum.md b/docs/source/api/ApolloAPI/protocols/SchemaTypeEnum.md deleted file mode 100644 index aea170273e..0000000000 --- a/docs/source/api/ApolloAPI/protocols/SchemaTypeEnum.md +++ /dev/null @@ -1,7 +0,0 @@ -**PROTOCOL** - -# `SchemaTypeEnum` - -```swift -public protocol SchemaTypeEnum: RawRepresentable, Equatable where RawValue == String -``` diff --git a/docs/source/api/ApolloAPI/protocols/SchemaUnion.md b/docs/source/api/ApolloAPI/protocols/SchemaUnion.md deleted file mode 100644 index 7c75c606e7..0000000000 --- a/docs/source/api/ApolloAPI/protocols/SchemaUnion.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `SchemaUnion` - -```swift -public protocol SchemaUnion: SchemaTypeEnum -``` - -## Properties -### `possibleTypes` - -```swift -var possibleTypes: [ObjectType] -``` diff --git a/docs/source/api/ApolloAPI/protocols/SelectionSet.md b/docs/source/api/ApolloAPI/protocols/SelectionSet.md deleted file mode 100644 index 3bbc44f1a0..0000000000 --- a/docs/source/api/ApolloAPI/protocols/SelectionSet.md +++ /dev/null @@ -1,18 +0,0 @@ -**PROTOCOL** - -# `SelectionSet` - -```swift -public protocol SelectionSet: ResponseObject, Equatable -``` - -## Properties -### `__parentType` - -```swift -static var __parentType: SelectionSetType -``` - -The GraphQL type for the `SelectionSet`. - -This may be a concrete type (`ConcreteType`) or an abstract type (`Interface`). diff --git a/docs/source/api/ApolloAPI/structs/Field.Arguments.md b/docs/source/api/ApolloAPI/structs/Field.Arguments.md deleted file mode 100644 index 4732b0c646..0000000000 --- a/docs/source/api/ApolloAPI/structs/Field.Arguments.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `Field.Arguments` - -```swift -public struct Arguments: ExpressibleByDictionaryLiteral -``` - -## Methods -### `init(dictionaryLiteral:)` - -```swift -public init(dictionaryLiteral elements: (String, InputValue)...) -``` diff --git a/docs/source/api/ApolloAPI/structs/ResponseDict.md b/docs/source/api/ApolloAPI/structs/ResponseDict.md deleted file mode 100644 index 9623582ddd..0000000000 --- a/docs/source/api/ApolloAPI/structs/ResponseDict.md +++ /dev/null @@ -1,9 +0,0 @@ -**STRUCT** - -# `ResponseDict` - -```swift -public struct ResponseDict -``` - -A structure that wraps the underlying data dictionary used by `SelectionSet`s. diff --git a/docs/source/api/ApolloAPI/structs/Selection.BooleanCondition.md b/docs/source/api/ApolloAPI/structs/Selection.BooleanCondition.md deleted file mode 100644 index c7d64bec00..0000000000 --- a/docs/source/api/ApolloAPI/structs/Selection.BooleanCondition.md +++ /dev/null @@ -1,16 +0,0 @@ -**STRUCT** - -# `Selection.BooleanCondition` - -```swift -public struct BooleanCondition -``` - -## Methods -### `init(variableName:inverted:selections:)` - -```swift -public init(variableName: String, - inverted: Bool, - selections: [Selection]) -``` diff --git a/docs/source/api/ApolloAPI/structs/Selection.Field.md b/docs/source/api/ApolloAPI/structs/Selection.Field.md deleted file mode 100644 index a207e01587..0000000000 --- a/docs/source/api/ApolloAPI/structs/Selection.Field.md +++ /dev/null @@ -1,17 +0,0 @@ -**STRUCT** - -# `Selection.Field` - -```swift -public struct Field -``` - -## Methods -### `init(_:alias:arguments:type:)` - -```swift -public init(_ name: String, - alias: String? = nil, - arguments: Arguments? = nil, - type: OutputType) -``` diff --git a/docs/source/api/ApolloAPI/structs/Selection.FragmentSpread.md b/docs/source/api/ApolloAPI/structs/Selection.FragmentSpread.md deleted file mode 100644 index ff07049df5..0000000000 --- a/docs/source/api/ApolloAPI/structs/Selection.FragmentSpread.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `Selection.FragmentSpread` - -```swift -public struct FragmentSpread -``` - -## Methods -### `init(_:)` - -```swift -public init(_ fragment: AnySelectionSet.Type) -``` diff --git a/docs/source/api/ApolloAPI/structs/Selection.TypeCase.md b/docs/source/api/ApolloAPI/structs/Selection.TypeCase.md deleted file mode 100644 index 4e551a0ca9..0000000000 --- a/docs/source/api/ApolloAPI/structs/Selection.TypeCase.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `Selection.TypeCase` - -```swift -public struct TypeCase -``` - -## Methods -### `init(variants:default:)` - -```swift -public init(variants: [String: [Selection]], default: [Selection]) -``` diff --git a/docs/source/api/ApolloAPI/typealiases/GraphQLEnum.RawValue.md b/docs/source/api/ApolloAPI/typealiases/GraphQLEnum.RawValue.md deleted file mode 100644 index c5d7446c1c..0000000000 --- a/docs/source/api/ApolloAPI/typealiases/GraphQLEnum.RawValue.md +++ /dev/null @@ -1,7 +0,0 @@ -**TYPEALIAS** - -# `GraphQLEnum.RawValue` - -```swift -public typealias RawValue = String -``` diff --git a/docs/source/api/ApolloCodegenLib/README.md b/docs/source/api/ApolloCodegenLib/README.md deleted file mode 100644 index f8da293d44..0000000000 --- a/docs/source/api/ApolloCodegenLib/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Reference Documentation - -## Structs - -- [ApolloCLI](structs/ApolloCLI/) -- [ApolloCodegenOptions](structs/ApolloCodegenOptions/) -- [ApolloSchemaDownloadConfiguration](structs/ApolloSchemaDownloadConfiguration/) -- [ApolloSchemaDownloadConfiguration.HTTPHeader](structs/ApolloSchemaDownloadConfiguration.HTTPHeader/) -- [ApolloSchemaDownloader](structs/ApolloSchemaDownloader/) -- [Basher](structs/Basher/) -- [CodegenLogger](structs/CodegenLogger/) -- [DownloadMethod.ApolloRegistrySettings](structs/DownloadMethod.ApolloRegistrySettings/) -- [FileFinder](structs/FileFinder/) -- [GraphQLSourceLocation](structs/GraphQLSourceLocation/) - -## Classes - -- [ASTNode](classes/ASTNode/) -- [ApolloCodegen](classes/ApolloCodegen/) -- [ApolloCodegenFrontend](classes/ApolloCodegenFrontend/) -- [CompilationResult](classes/CompilationResult/) -- [CompilationResult.Argument](classes/CompilationResult.Argument/) -- [CompilationResult.Field](classes/CompilationResult.Field/) -- [CompilationResult.FragmentDefinition](classes/CompilationResult.FragmentDefinition/) -- [CompilationResult.FragmentSpread](classes/CompilationResult.FragmentSpread/) -- [CompilationResult.InlineFragment](classes/CompilationResult.InlineFragment/) -- [CompilationResult.OperationDefinition](classes/CompilationResult.OperationDefinition/) -- [CompilationResult.SelectionSet](classes/CompilationResult.SelectionSet/) -- [CompilationResult.VariableDefinition](classes/CompilationResult.VariableDefinition/) -- [GraphQLAbstractType](classes/GraphQLAbstractType/) -- [GraphQLCompositeType](classes/GraphQLCompositeType/) -- [GraphQLDocument](classes/GraphQLDocument/) -- [GraphQLEnumType](classes/GraphQLEnumType/) -- [GraphQLEnumValue](classes/GraphQLEnumValue/) -- [GraphQLError](classes/GraphQLError/) -- [GraphQLField](classes/GraphQLField/) -- [GraphQLInputField](classes/GraphQLInputField/) -- [GraphQLInputObjectType](classes/GraphQLInputObjectType/) -- [GraphQLInterfaceType](classes/GraphQLInterfaceType/) -- [GraphQLNamedType](classes/GraphQLNamedType/) -- [GraphQLObjectType](classes/GraphQLObjectType/) -- [GraphQLScalarType](classes/GraphQLScalarType/) -- [GraphQLSchema](classes/GraphQLSchema/) -- [GraphQLSchemaValidationError](classes/GraphQLSchemaValidationError/) -- [GraphQLSource](classes/GraphQLSource/) -- [GraphQLUnionType](classes/GraphQLUnionType/) -- [JavaScriptError](classes/JavaScriptError/) -- [JavaScriptObject](classes/JavaScriptObject/) - -## Enums - -- [ApolloCodegen.CodegenError](enums/ApolloCodegen.CodegenError/) -- [ApolloCodegenOptions.AccessModifier](enums/ApolloCodegenOptions.AccessModifier/) -- [ApolloCodegenOptions.CodeGenerationEngine](enums/ApolloCodegenOptions.CodeGenerationEngine/) -- [ApolloCodegenOptions.CustomScalarFormat](enums/ApolloCodegenOptions.CustomScalarFormat/) -- [ApolloCodegenOptions.OutputFormat](enums/ApolloCodegenOptions.OutputFormat/) -- [ApolloSchemaDownloadConfiguration.DownloadMethod](enums/ApolloSchemaDownloadConfiguration.DownloadMethod/) -- [ApolloSchemaDownloader.SchemaDownloadError](enums/ApolloSchemaDownloader.SchemaDownloadError/) -- [ApolloURLError](enums/ApolloURLError/) -- [Basher.BashError](enums/Basher.BashError/) -- [CodegenLogger.LogLevel](enums/CodegenLogger.LogLevel/) -- [CompilationResult.OperationType](enums/CompilationResult.OperationType/) -- [CompilationResult.Selection](enums/CompilationResult.Selection/) -- [DownloadMethod.HTTPMethod](enums/DownloadMethod.HTTPMethod/) -- [GraphQLType](enums/GraphQLType/) - -## Extensions - -- [ApolloCodegenOptions](extensions/ApolloCodegenOptions/) -- [ApolloExtension](extensions/ApolloExtension/) -- [ApolloSchemaDownloadConfiguration](extensions/ApolloSchemaDownloadConfiguration/) -- [FileHandle](extensions/FileHandle/) -- [GraphQLType](extensions/GraphQLType/) -- [JavaScriptError](extensions/JavaScriptError/) -- [JavaScriptObject](extensions/JavaScriptObject/) - -This file was generated by [SourceDocs](https://github.com/eneko/SourceDocs) \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/classes/ASTNode.md b/docs/source/api/ApolloCodegenLib/classes/ASTNode.md deleted file mode 100644 index afa21cdf7f..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/ASTNode.md +++ /dev/null @@ -1,9 +0,0 @@ -**CLASS** - -# `ASTNode` - -```swift -public class ASTNode: JavaScriptObject -``` - -An AST node. diff --git a/docs/source/api/ApolloCodegenLib/classes/ApolloCodegen.md b/docs/source/api/ApolloCodegenLib/classes/ApolloCodegen.md deleted file mode 100644 index c8d1bc9233..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/ApolloCodegen.md +++ /dev/null @@ -1,34 +0,0 @@ -**CLASS** - -# `ApolloCodegen` - -```swift -public class ApolloCodegen -``` - -A class to facilitate running code generation - -## Methods -### `run(from:with:options:)` - -```swift -public static func run(from folder: URL, - with cliFolderURL: URL, - options: ApolloCodegenOptions) throws -> String -``` - -Runs code generation from the given folder with the passed-in options - -- Parameters: - - folder: The folder to run the script from. Should be the folder that at some depth, contains all `.graphql` files. - - cliFolderURL: The folder where the Apollo CLI is/should be downloaded. - - options: The options object to use to run the code generation. -- Returns: Output from a successful run - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| folder | The folder to run the script from. Should be the folder that at some depth, contains all `.graphql` files. | -| cliFolderURL | The folder where the Apollo CLI is/should be downloaded. | -| options | The options object to use to run the code generation. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/classes/ApolloCodegenFrontend.md b/docs/source/api/ApolloCodegenLib/classes/ApolloCodegenFrontend.md deleted file mode 100644 index c73e98d6a2..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/ApolloCodegenFrontend.md +++ /dev/null @@ -1,104 +0,0 @@ -**CLASS** - -# `ApolloCodegenFrontend` - -```swift -public final class ApolloCodegenFrontend -``` - -## Methods -### `init()` - -```swift -public init() throws -``` - -### `loadSchema(from:)` - -```swift -public func loadSchema(from fileURL: URL) throws -> GraphQLSchema -``` - -Load a schema by parsing either an introspection result or SDL based on the file extension. - -### `loadSchemaFromIntrospectionResult(_:)` - -```swift -public func loadSchemaFromIntrospectionResult(_ introspectionResult: String) throws -> GraphQLSchema -``` - -Load a schema by parsing an introspection result. - -### `loadSchemaFromSDL(_:)` - -```swift -public func loadSchemaFromSDL(_ source: GraphQLSource) throws -> GraphQLSchema -``` - -Load a schema by parsing SDL. - -### `printSchemaAsSDL(schema:)` - -```swift -public func printSchemaAsSDL(schema: GraphQLSchema) throws -> String -``` - -Take a loaded GQL schema and print it as SDL. - -### `makeSource(_:filePath:)` - -```swift -public func makeSource(_ body: String, filePath: String) throws -> GraphQLSource -``` - -Create a `GraphQLSource` object from a string. - -### `makeSource(from:)` - -```swift -public func makeSource(from fileURL: URL) throws -> GraphQLSource -``` - -Create a `GraphQLSource` object by reading from a file. - -### `parseDocument(_:)` - -```swift -public func parseDocument(_ source: GraphQLSource) throws -> GraphQLDocument -``` - -Parses a GraphQL document from a source, returning a reference to the parsed AST that can be passed on to validation and compilation. -Syntax errors will result in throwing a `GraphQLError`. - -### `parseDocument(from:)` - -```swift -public func parseDocument(from fileURL: URL) throws -> GraphQLDocument -``` - -Parses a GraphQL document from a file, returning a reference to the parsed AST that can be passed on to validation and compilation. -Syntax errors will result in throwing a `GraphQLError`. - -### `mergeDocuments(_:)` - -```swift -public func mergeDocuments(_ documents: [GraphQLDocument]) throws -> GraphQLDocument -``` - -Validation and compilation take a single document, but you can merge documents, and operations and fragments will remember their source. - -### `validateDocument(schema:document:)` - -```swift -public func validateDocument(schema: GraphQLSchema, document: GraphQLDocument) throws -> [GraphQLError] -``` - -Validate a GraphQL document and return any validation errors as `GraphQLError`s. - -### `compile(schema:document:)` - -```swift -public func compile(schema: GraphQLSchema, document: GraphQLDocument) throws -> CompilationResult -``` - -Compiles a GraphQL document into an intermediate representation that is more suitable for analysis and code generation. diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.Argument.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.Argument.md deleted file mode 100644 index c0fa69ea1d..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.Argument.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.Argument` - -```swift -public class Argument: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.Field.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.Field.md deleted file mode 100644 index 40db3659f1..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.Field.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.Field` - -```swift -public class Field: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.FragmentDefinition.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.FragmentDefinition.md deleted file mode 100644 index b43f6e8e22..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.FragmentDefinition.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.FragmentDefinition` - -```swift -public class FragmentDefinition: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.FragmentSpread.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.FragmentSpread.md deleted file mode 100644 index b9bad95a7d..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.FragmentSpread.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.FragmentSpread` - -```swift -public class FragmentSpread: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.InlineFragment.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.InlineFragment.md deleted file mode 100644 index cd73bb90c4..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.InlineFragment.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.InlineFragment` - -```swift -public class InlineFragment: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.OperationDefinition.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.OperationDefinition.md deleted file mode 100644 index 7aef2c648c..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.OperationDefinition.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.OperationDefinition` - -```swift -public class OperationDefinition: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.SelectionSet.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.SelectionSet.md deleted file mode 100644 index e953dcbc11..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.SelectionSet.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.SelectionSet` - -```swift -public class SelectionSet: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.VariableDefinition.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.VariableDefinition.md deleted file mode 100644 index e7a207c8be..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.VariableDefinition.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `CompilationResult.VariableDefinition` - -```swift -public class VariableDefinition: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.md b/docs/source/api/ApolloCodegenLib/classes/CompilationResult.md deleted file mode 100644 index 02766ea74c..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/CompilationResult.md +++ /dev/null @@ -1,9 +0,0 @@ -**CLASS** - -# `CompilationResult` - -```swift -public class CompilationResult: JavaScriptObject -``` - -The output of the frontend compiler. diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLAbstractType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLAbstractType.md deleted file mode 100644 index 20bf3be726..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLAbstractType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLAbstractType` - -```swift -public class GraphQLAbstractType: GraphQLCompositeType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLCompositeType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLCompositeType.md deleted file mode 100644 index d25d4a19bc..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLCompositeType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLCompositeType` - -```swift -public class GraphQLCompositeType: GraphQLNamedType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLDocument.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLDocument.md deleted file mode 100644 index f4446f3c00..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLDocument.md +++ /dev/null @@ -1,9 +0,0 @@ -**CLASS** - -# `GraphQLDocument` - -```swift -public class GraphQLDocument: ASTNode -``` - -A parsed GraphQL document. diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLEnumType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLEnumType.md deleted file mode 100644 index a1960602e3..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLEnumType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLEnumType` - -```swift -public class GraphQLEnumType: GraphQLNamedType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLEnumValue.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLEnumValue.md deleted file mode 100644 index c241e61302..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLEnumValue.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLEnumValue` - -```swift -public class GraphQLEnumValue: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLError.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLError.md deleted file mode 100644 index d3ef95737f..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLError.md +++ /dev/null @@ -1,11 +0,0 @@ -**CLASS** - -# `GraphQLError` - -```swift -public class GraphQLError: JavaScriptError -``` - -A GraphQL error. -Corresponds to https://github.com/graphql/graphql-js/blob/master/src/error/GraphQLError.js -You can get error details if you need them, or call `error.logLines` to get errors in a format that lets Xcode show inline errors. diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLField.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLField.md deleted file mode 100644 index e5e7ea03a7..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLField.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLField` - -```swift -public class GraphQLField: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLInputField.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLInputField.md deleted file mode 100644 index 70dfd2ec5b..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLInputField.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLInputField` - -```swift -public class GraphQLInputField: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLInputObjectType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLInputObjectType.md deleted file mode 100644 index 7385a63162..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLInputObjectType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLInputObjectType` - -```swift -public class GraphQLInputObjectType: GraphQLNamedType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLInterfaceType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLInterfaceType.md deleted file mode 100644 index 273e84b2a1..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLInterfaceType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLInterfaceType` - -```swift -public class GraphQLInterfaceType: GraphQLAbstractType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLNamedType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLNamedType.md deleted file mode 100644 index aa4a27223f..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLNamedType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLNamedType` - -```swift -public class GraphQLNamedType: JavaScriptObject -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLObjectType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLObjectType.md deleted file mode 100644 index 859875fe63..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLObjectType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLObjectType` - -```swift -public class GraphQLObjectType: GraphQLCompositeType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLScalarType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLScalarType.md deleted file mode 100644 index 6f060144fe..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLScalarType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLScalarType` - -```swift -public class GraphQLScalarType: GraphQLNamedType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLSchema.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLSchema.md deleted file mode 100644 index 81c37e8501..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLSchema.md +++ /dev/null @@ -1,9 +0,0 @@ -**CLASS** - -# `GraphQLSchema` - -```swift -public class GraphQLSchema: JavaScriptObject -``` - -A GraphQL schema. diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLSchemaValidationError.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLSchemaValidationError.md deleted file mode 100644 index bf4af6af38..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLSchemaValidationError.md +++ /dev/null @@ -1,9 +0,0 @@ -**CLASS** - -# `GraphQLSchemaValidationError` - -```swift -public class GraphQLSchemaValidationError: JavaScriptError -``` - -A GraphQL schema validation error. This wraps one or more underlying validation errors. diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLSource.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLSource.md deleted file mode 100644 index e1ef66e52b..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLSource.md +++ /dev/null @@ -1,10 +0,0 @@ -**CLASS** - -# `GraphQLSource` - -```swift -public class GraphQLSource: JavaScriptObject -``` - -A representation of source input to GraphQL parsing. -Corresponds to https://github.com/graphql/graphql-js/blob/master/src/language/source.js diff --git a/docs/source/api/ApolloCodegenLib/classes/GraphQLUnionType.md b/docs/source/api/ApolloCodegenLib/classes/GraphQLUnionType.md deleted file mode 100644 index 939b9dfd7f..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/GraphQLUnionType.md +++ /dev/null @@ -1,7 +0,0 @@ -**CLASS** - -# `GraphQLUnionType` - -```swift -public class GraphQLUnionType: GraphQLAbstractType -``` diff --git a/docs/source/api/ApolloCodegenLib/classes/JavaScriptError.md b/docs/source/api/ApolloCodegenLib/classes/JavaScriptError.md deleted file mode 100644 index 1385b6e0cb..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/JavaScriptError.md +++ /dev/null @@ -1,10 +0,0 @@ -**CLASS** - -# `JavaScriptError` - -```swift -public class JavaScriptError: JavaScriptObject, Error, @unchecked Sendable -``` - -An error thrown during JavaScript execution. -See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error diff --git a/docs/source/api/ApolloCodegenLib/classes/JavaScriptObject.md b/docs/source/api/ApolloCodegenLib/classes/JavaScriptObject.md deleted file mode 100644 index c1a4fe0229..0000000000 --- a/docs/source/api/ApolloCodegenLib/classes/JavaScriptObject.md +++ /dev/null @@ -1,9 +0,0 @@ -**CLASS** - -# `JavaScriptObject` - -```swift -public class JavaScriptObject: JavaScriptValueDecodable -``` - -A type that references an underlying JavaScript object. diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegen.CodegenError.md b/docs/source/api/ApolloCodegenLib/enums/ApolloCodegen.CodegenError.md deleted file mode 100644 index e98f7102f3..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegen.CodegenError.md +++ /dev/null @@ -1,35 +0,0 @@ -**ENUM** - -# `ApolloCodegen.CodegenError` - -```swift -public enum CodegenError: Error, LocalizedError -``` - -Errors which can happen with code generation - -## Cases -### `folderDoesNotExist(_:)` - -```swift -case folderDoesNotExist(_ url: URL) -``` - -### `multipleFilesButNotDirectoryURL(_:)` - -```swift -case multipleFilesButNotDirectoryURL(_ url: URL) -``` - -### `singleFileButNotSwiftFileURL(_:)` - -```swift -case singleFileButNotSwiftFileURL(_ url: URL) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.AccessModifier.md b/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.AccessModifier.md deleted file mode 100644 index a3f3bdef87..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.AccessModifier.md +++ /dev/null @@ -1,37 +0,0 @@ -**ENUM** - -# `ApolloCodegenOptions.AccessModifier` - -```swift -public enum AccessModifier -``` - -The possible access modifiers for code generated by this tool. - -## Cases -### `public` - -```swift -case `public` -``` - -### `internal` - -```swift -case `internal` -``` - -### `none` - -```swift -case `none` -``` - -## Properties -### `prefixValue` - -```swift -public var prefixValue: String -``` - -The prefix which should be used for classes, enums, and structs generated by this tool. diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.CodeGenerationEngine.md b/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.CodeGenerationEngine.md deleted file mode 100644 index b4df3db997..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.CodeGenerationEngine.md +++ /dev/null @@ -1,27 +0,0 @@ -**ENUM** - -# `ApolloCodegenOptions.CodeGenerationEngine` - -```swift -public enum CodeGenerationEngine: Equatable -``` - -Enum to select which code generation you wish to use - -## Cases -### `typescript` - -```swift -case typescript -``` - -The default, tried and true code generation engine - -## Properties -### `default` - -```swift -public static var `default`: CodeGenerationEngine -``` - -The current default for the code generation engine. diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.CustomScalarFormat.md b/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.CustomScalarFormat.md deleted file mode 100644 index 52acffb8e2..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.CustomScalarFormat.md +++ /dev/null @@ -1,34 +0,0 @@ -**ENUM** - -# `ApolloCodegenOptions.CustomScalarFormat` - -```swift -public enum CustomScalarFormat: Equatable -``` - -Enum to select how to handle properties using a custom scalar from the schema. - -## Cases -### `none` - -```swift -case none -``` - -Uses a default type instead of a custom scalar. - -### `passthrough` - -```swift -case passthrough -``` - -Use your own types for custom scalars. - -### `passthroughWithPrefix(_:)` - -```swift -case passthroughWithPrefix(String) -``` - -Use your own types for custom scalars with a prefix. diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.OutputFormat.md b/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.OutputFormat.md deleted file mode 100644 index b2275174f5..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloCodegenOptions.OutputFormat.md +++ /dev/null @@ -1,28 +0,0 @@ -**ENUM** - -# `ApolloCodegenOptions.OutputFormat` - -```swift -public enum OutputFormat -``` - -Enum to select how you want to export your API files. - -## Cases -### `singleFile(atFileURL:)` - -```swift -case singleFile(atFileURL: URL) -``` - -Outputs everything into a single file at the given URL. -NOTE: URL must be a file URL - -### `multipleFiles(inFolderAtURL:)` - -```swift -case multipleFiles(inFolderAtURL: URL) -``` - -Outputs everything into individual files in a folder a the given URL -NOTE: URL must be a folder URL diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloSchemaDownloadConfiguration.DownloadMethod.md b/docs/source/api/ApolloCodegenLib/enums/ApolloSchemaDownloadConfiguration.DownloadMethod.md deleted file mode 100644 index 9a315519d2..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloSchemaDownloadConfiguration.DownloadMethod.md +++ /dev/null @@ -1,40 +0,0 @@ -**ENUM** - -# `ApolloSchemaDownloadConfiguration.DownloadMethod` - -```swift -public enum DownloadMethod: Equatable -``` - -How to attempt to download your schema - -## Cases -### `apolloRegistry(_:)` - -```swift -case apolloRegistry(_ settings: ApolloRegistrySettings) -``` - -The Apollo Schema Registry, which serves as a central hub for managing your graph. - -### `introspection(endpointURL:httpMethod:)` - -```swift -case introspection(endpointURL: URL, httpMethod: HTTPMethod = .POST) -``` - -GraphQL Introspection connecting to the specified URL. - -## Methods -### `==(_:_:)` - -```swift -public static func == (lhs: DownloadMethod, rhs: DownloadMethod) -> Bool -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| lhs | A value to compare. | -| rhs | Another value to compare. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloSchemaDownloader.SchemaDownloadError.md b/docs/source/api/ApolloCodegenLib/enums/ApolloSchemaDownloader.SchemaDownloadError.md deleted file mode 100644 index 5d2d7800e7..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloSchemaDownloader.SchemaDownloadError.md +++ /dev/null @@ -1,69 +0,0 @@ -**ENUM** - -# `ApolloSchemaDownloader.SchemaDownloadError` - -```swift -public enum SchemaDownloadError: Error, LocalizedError -``` - -## Cases -### `downloadedRegistryJSONFileNotFound(underlying:)` - -```swift -case downloadedRegistryJSONFileNotFound(underlying: Error) -``` - -### `downloadedIntrospectionJSONFileNotFound(underlying:)` - -```swift -case downloadedIntrospectionJSONFileNotFound(underlying: Error) -``` - -### `couldNotParseRegistryJSON(underlying:)` - -```swift -case couldNotParseRegistryJSON(underlying: Error) -``` - -### `unexpectedRegistryJSONType` - -```swift -case unexpectedRegistryJSONType -``` - -### `couldNotExtractSDLFromRegistryJSON` - -```swift -case couldNotExtractSDLFromRegistryJSON -``` - -### `couldNotCreateSDLDataToWrite(schema:)` - -```swift -case couldNotCreateSDLDataToWrite(schema: String) -``` - -### `couldNotConvertIntrospectionJSONToSDL(underlying:)` - -```swift -case couldNotConvertIntrospectionJSONToSDL(underlying: Error) -``` - -### `couldNotCreateURLComponentsFromEndpointURL(url:)` - -```swift -case couldNotCreateURLComponentsFromEndpointURL(url: URL) -``` - -### `couldNotGetURLFromURLComponents(components:)` - -```swift -case couldNotGetURLFromURLComponents(components: URLComponents) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/ApolloURLError.md b/docs/source/api/ApolloCodegenLib/enums/ApolloURLError.md deleted file mode 100644 index 588838d529..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/ApolloURLError.md +++ /dev/null @@ -1,21 +0,0 @@ -**ENUM** - -# `ApolloURLError` - -```swift -public enum ApolloURLError: Error, LocalizedError -``` - -## Cases -### `fileNameIsEmpty` - -```swift -case fileNameIsEmpty -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/Basher.BashError.md b/docs/source/api/ApolloCodegenLib/enums/Basher.BashError.md deleted file mode 100644 index 2fd6b4b28c..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/Basher.BashError.md +++ /dev/null @@ -1,27 +0,0 @@ -**ENUM** - -# `Basher.BashError` - -```swift -public enum BashError: Error, LocalizedError -``` - -## Cases -### `errorDuringTask(code:)` - -```swift -case errorDuringTask(code: Int32) -``` - -### `noOutput(code:)` - -```swift -case noOutput(code: Int32) -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/CodegenLogger.LogLevel.md b/docs/source/api/ApolloCodegenLib/enums/CodegenLogger.LogLevel.md deleted file mode 100644 index 1e5462cf29..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/CodegenLogger.LogLevel.md +++ /dev/null @@ -1,26 +0,0 @@ -**ENUM** - -# `CodegenLogger.LogLevel` - -```swift -public enum LogLevel: Int -``` - -## Cases -### `error` - -```swift -case error -``` - -### `warning` - -```swift -case warning -``` - -### `debug` - -```swift -case debug -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/CompilationResult.OperationType.md b/docs/source/api/ApolloCodegenLib/enums/CompilationResult.OperationType.md deleted file mode 100644 index a1d20e96e6..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/CompilationResult.OperationType.md +++ /dev/null @@ -1,26 +0,0 @@ -**ENUM** - -# `CompilationResult.OperationType` - -```swift -public enum OperationType: String, Equatable, JavaScriptValueDecodable -``` - -## Cases -### `query` - -```swift -case query -``` - -### `mutation` - -```swift -case mutation -``` - -### `subscription` - -```swift -case subscription -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/CompilationResult.Selection.md b/docs/source/api/ApolloCodegenLib/enums/CompilationResult.Selection.md deleted file mode 100644 index b1ee593790..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/CompilationResult.Selection.md +++ /dev/null @@ -1,26 +0,0 @@ -**ENUM** - -# `CompilationResult.Selection` - -```swift -public enum Selection: JavaScriptValueDecodable -``` - -## Cases -### `field(_:)` - -```swift -case field(Field) -``` - -### `inlineFragment(_:)` - -```swift -case inlineFragment(InlineFragment) -``` - -### `fragmentSpread(_:)` - -```swift -case fragmentSpread(FragmentSpread) -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/DownloadMethod.HTTPMethod.md b/docs/source/api/ApolloCodegenLib/enums/DownloadMethod.HTTPMethod.md deleted file mode 100644 index 349233d7a9..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/DownloadMethod.HTTPMethod.md +++ /dev/null @@ -1,35 +0,0 @@ -**ENUM** - -# `DownloadMethod.HTTPMethod` - -```swift -public enum HTTPMethod: Equatable, CustomStringConvertible -``` - -The HTTP request method. This is an option on Introspection schema downloads only. Apollo Registry downloads are always -POST requests. - -## Cases -### `POST` - -```swift -case POST -``` - -Use POST for HTTP requests. This is the default for GraphQL. - -### `GET(queryParameterName:)` - -```swift -case GET(queryParameterName: String) -``` - -Use GET for HTTP requests with the GraphQL query being sent in the query string parameter named in -`queryParameterName`. - -## Properties -### `description` - -```swift -public var description: String -``` diff --git a/docs/source/api/ApolloCodegenLib/enums/GraphQLType.md b/docs/source/api/ApolloCodegenLib/enums/GraphQLType.md deleted file mode 100644 index 5bea31a9b2..0000000000 --- a/docs/source/api/ApolloCodegenLib/enums/GraphQLType.md +++ /dev/null @@ -1,35 +0,0 @@ -**ENUM** - -# `GraphQLType` - -```swift -public indirect enum GraphQLType: Equatable -``` - -A GraphQL type. - -## Cases -### `named(_:)` - -```swift -case named(GraphQLNamedType) -``` - -### `nonNull(_:)` - -```swift -case nonNull(GraphQLType) -``` - -### `list(_:)` - -```swift -case list(GraphQLType) -``` - -## Properties -### `typeReference` - -```swift -public var typeReference: String -``` diff --git a/docs/source/api/ApolloCodegenLib/extensions/ApolloCodegenOptions.md b/docs/source/api/ApolloCodegenLib/extensions/ApolloCodegenOptions.md deleted file mode 100644 index 1908e717e2..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/ApolloCodegenOptions.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `ApolloCodegenOptions` -```swift -extension ApolloCodegenOptions: CustomDebugStringConvertible -``` - -## Properties -### `debugDescription` - -```swift -public var debugDescription: String -``` diff --git a/docs/source/api/ApolloCodegenLib/extensions/ApolloExtension.md b/docs/source/api/ApolloCodegenLib/extensions/ApolloExtension.md deleted file mode 100644 index f2ecebc161..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/ApolloExtension.md +++ /dev/null @@ -1,196 +0,0 @@ -**EXTENSION** - -# `ApolloExtension` -```swift -extension ApolloExtension where Base == FileManager -``` - -## Methods -### `fileExists(at:)` - -```swift -public func fileExists(at path: String) -> Bool -``` - -Checks if a file exists (and is not a folder) at the given path - -- Parameter path: The path to check -- Returns: `true` if there is something at the path and it is a file, not a folder. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| path | The path to check | - -### `fileExists(at:)` - -```swift -public func fileExists(at url: URL) -> Bool -``` - -Checks if a file exists (and is not a folder) at the given URL - -- Parameter url: The URL to check -- Returns: `true` if there is something at the URL and it is a file, not a folder. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The URL to check | - -### `folderExists(at:)` - -```swift -public func folderExists(at path: String) -> Bool -``` - -Checks if a folder exists (and is not a file) at the given path. - -- Parameter path: The path to check -- Returns: `true` if there is something at the path and it is a folder, not a file. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| path | The path to check | - -### `folderExists(at:)` - -```swift -public func folderExists(at url: URL) -> Bool -``` - -Checks if a folder exists (and is not a file) at the given URL. - -- Parameter url: The URL to check -- Returns: `true` if there is something at the URL and it is a folder, not a file. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The URL to check | - -### `deleteFolder(at:)` - -```swift -public func deleteFolder(at url: URL) throws -``` - -Checks if a folder exists then attempts to delete it if it's there. - -- Parameter url: The URL to delete the folder for - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The URL to delete the folder for | - -### `deleteFile(at:)` - -```swift -public func deleteFile(at url: URL) throws -``` - -Checks if a file exists then attempts to delete it if it's there. - -- Parameter url: The URL to delete the file for - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The URL to delete the file for | - -### `createContainingFolderIfNeeded(for:)` - -```swift -public func createContainingFolderIfNeeded(for fileURL: URL) throws -``` - -Creates the containing folder (including all intermediate directories) for the given file URL if necessary. - -- Parameter fileURL: The URL of the file to create a containing folder for if necessary. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| fileURL | The URL of the file to create a containing folder for if necessary. | - -### `createFolderIfNeeded(at:)` - -```swift -public func createFolderIfNeeded(at url: URL) throws -``` - -Creates the folder (including all intermediate directories) for the given URL if necessary. - -- Parameter url: The URL of the folder to create if necessary. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The URL of the folder to create if necessary. | - -### `shasum(at:)` - -```swift -public func shasum(at fileURL: URL) throws -> String -``` - -Calculates the SHASUM (ie, SHA256 hash) of the given file - -- Parameter fileURL: The file to calculate the SHASUM for. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| fileURL | The file to calculate the SHASUM for. | - -### `parentFolderURL()` - -```swift -public func parentFolderURL() -> URL -``` - -- Returns: the URL to the parent folder of the current URL. - -### `childFolderURL(folderName:)` - -```swift -public func childFolderURL(folderName: String) -> URL -``` - -- Parameter folderName: The name of the child folder to append to the current URL -- Returns: The full URL including the appended child folder. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| folderName | The name of the child folder to append to the current URL | - -### `childFileURL(fileName:)` - -```swift -public func childFileURL(fileName: String) throws -> URL -``` - -Adds the filename to the caller to get the full URL of a file - -- Parameters: - - fileName: The name of the child file, with an extension, for example `"API.swift"`. Note: For hidden files just pass `".filename"`. -- Returns: The full URL including the full file. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| fileName | The name of the child file, with an extension, for example `"API.swift"`. Note: For hidden files just pass `".filename"`. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/extensions/ApolloSchemaDownloadConfiguration.md b/docs/source/api/ApolloCodegenLib/extensions/ApolloSchemaDownloadConfiguration.md deleted file mode 100644 index 924e389fbb..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/ApolloSchemaDownloadConfiguration.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `ApolloSchemaDownloadConfiguration` -```swift -extension ApolloSchemaDownloadConfiguration: CustomDebugStringConvertible -``` - -## Properties -### `debugDescription` - -```swift -public var debugDescription: String -``` diff --git a/docs/source/api/ApolloCodegenLib/extensions/FileHandle.md b/docs/source/api/ApolloCodegenLib/extensions/FileHandle.md deleted file mode 100644 index 4fbd2f6da9..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/FileHandle.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `FileHandle` -```swift -extension FileHandle: TextOutputStream -``` - -## Methods -### `write(_:)` - -```swift -public func write(_ string: String) -``` diff --git a/docs/source/api/ApolloCodegenLib/extensions/GraphQLType.md b/docs/source/api/ApolloCodegenLib/extensions/GraphQLType.md deleted file mode 100644 index 7a31c9c0c4..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/GraphQLType.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `GraphQLType` -```swift -extension GraphQLType: CustomDebugStringConvertible -``` - -## Properties -### `debugDescription` - -```swift -public var debugDescription: String -``` diff --git a/docs/source/api/ApolloCodegenLib/extensions/JavaScriptError.md b/docs/source/api/ApolloCodegenLib/extensions/JavaScriptError.md deleted file mode 100644 index 0c3b0c7ec9..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/JavaScriptError.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `JavaScriptError` -```swift -extension JavaScriptError: CustomStringConvertible -``` - -## Properties -### `description` - -```swift -public var description: String -``` diff --git a/docs/source/api/ApolloCodegenLib/extensions/JavaScriptObject.md b/docs/source/api/ApolloCodegenLib/extensions/JavaScriptObject.md deleted file mode 100644 index 462cfb4c70..0000000000 --- a/docs/source/api/ApolloCodegenLib/extensions/JavaScriptObject.md +++ /dev/null @@ -1,27 +0,0 @@ -**EXTENSION** - -# `JavaScriptObject` -```swift -extension JavaScriptObject: Equatable -``` - -## Properties -### `debugDescription` - -```swift -public var debugDescription: String -``` - -## Methods -### `==(_:_:)` - -```swift -public static func ==(lhs: JavaScriptObject, rhs: JavaScriptObject) -> Bool -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| lhs | A value to compare. | -| rhs | Another value to compare. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/ApolloCLI.md b/docs/source/api/ApolloCodegenLib/structs/ApolloCLI.md deleted file mode 100644 index 45202703b5..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/ApolloCLI.md +++ /dev/null @@ -1,72 +0,0 @@ -**STRUCT** - -# `ApolloCLI` - -```swift -public struct ApolloCLI -``` - -Wrapper for calling the bundled node-based Apollo CLI. - -## Properties -### `binaryFolderURL` - -```swift -public let binaryFolderURL: URL -``` - -## Methods -### `createCLI(cliFolderURL:timeout:)` - -```swift -public static func createCLI(cliFolderURL: URL, timeout: Double) throws -> ApolloCLI -``` - -Creates an instance of `ApolloCLI`, downloading and extracting if needed - -- Parameters: - - cliFolderURL: The URL to the folder which contains the zip file with the CLI. - - timeout: The maximum time to wait before indicating that the download timed out, in seconds. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| cliFolderURL | The URL to the folder which contains the zip file with the CLI. | -| timeout | The maximum time to wait before indicating that the download timed out, in seconds. | - -### `init(binaryFolderURL:)` - -```swift -public init(binaryFolderURL: URL) -``` - -Designated initializer - -- Parameter binaryFolderURL: The folder where the extracted binary files live. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| binaryFolderURL | The folder where the extracted binary files live. | - -### `runApollo(with:from:)` - -```swift -public func runApollo(with arguments: [String], - from folder: URL? = nil) throws -> String -``` - -Runs a command with the bundled Apollo CLI - -NOTE: Will always run the `--version` command first for debugging purposes. -- Parameter arguments: The arguments to hand to the CLI -- Parameter folder: The folder to run the command from. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| arguments | The arguments to hand to the CLI | -| folder | The folder to run the command from. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/ApolloCodegenOptions.md b/docs/source/api/ApolloCodegenLib/structs/ApolloCodegenOptions.md deleted file mode 100644 index 69121fa041..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/ApolloCodegenOptions.md +++ /dev/null @@ -1,67 +0,0 @@ -**STRUCT** - -# `ApolloCodegenOptions` - -```swift -public struct ApolloCodegenOptions -``` - -An object to hold all the various options for running codegen - -## Methods -### `init(codegenEngine:includes:excludes:mergeInFieldsFromFragmentSpreads:modifier:namespace:omitDeprecatedEnumCases:only:operationIDsURL:outputFormat:customScalarFormat:suppressSwiftMultilineStringLiterals:urlToSchemaFile:downloadTimeout:)` - -```swift -public init(codegenEngine: CodeGenerationEngine = .default, - includes: String = "./**/*.graphql", - excludes: String? = nil, - mergeInFieldsFromFragmentSpreads: Bool = true, - modifier: AccessModifier = .public, - namespace: String? = nil, - omitDeprecatedEnumCases: Bool = false, - only: URL? = nil, - operationIDsURL: URL? = nil, - outputFormat: OutputFormat, - customScalarFormat: CustomScalarFormat = .none, - suppressSwiftMultilineStringLiterals: Bool = false, - urlToSchemaFile: URL, - downloadTimeout: Double = 30.0) -``` - -Designated initializer. - -- Parameters: - - codegenEngine: The code generation engine to use. Defaults to `CodeGenerationEngine.default` - - includes: Glob of files to search for GraphQL operations. This should be used to find queries *and* any client schema extensions. Defaults to `./**/*.graphql`, which will search for `.graphql` files throughout all subfolders of the folder where the script is run. - - excludes: Glob of files to exclude for GraphQL operations. Caveat: this doesn't currently work in watch mode - - mergeInFieldsFromFragmentSpreads: Set true to merge fragment fields onto its enclosing type. Defaults to true. - - modifier: [EXPERIMENTAL SWIFT CODEGEN ONLY] - The access modifier to use on everything created by this tool. Defaults to `.public`. - - namespace: [optional] The namespace to emit generated code into. Defaults to nil. - - omitDeprecatedEnumCases: Whether deprecated enum cases should be omitted from generated code. Defaults to false. - - only: [optional] Parse all input files, but only output generated code for the file at this URL if non-nil. Defaults to nil. - - operationIDsURL: [optional] Path to an operation id JSON map file. If specified, also stores the operation ids (hashes) as properties on operation types. Defaults to nil. - - outputFormat: The `OutputFormat` enum option to use to output generated code. - - customScalarFormat: How to handle properties using a custom scalar from the schema. - - suppressSwiftMultilineStringLiterals: Don't use multi-line string literals when generating code. Defaults to false. - - urlToSchemaFile: The URL to your schema file. Accepted file types are `.json` for JSON files, or either `.graphqls` or `.sdl` for Schema Definition Language files. - - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. - -### `init(targetRootURL:codegenEngine:downloadTimeout:)` - -```swift -public init(targetRootURL folder: URL, - codegenEngine: CodeGenerationEngine = .default, - downloadTimeout: Double = 30.0) -``` - -Convenience initializer that takes the root folder of a target and generates -code with some default assumptions. -Makes the following assumptions: - - Schema is at [folder]/schema.json - - Output is a single file to [folder]/API.swift - - You want operation IDs generated and output to [folder]/operationIDs.json - -- Parameters: - - folder: The root of the target. - - codegenEngine: The code generation engine to use. Defaults to `CodeGenerationEngine.default` - - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds diff --git a/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration.HTTPHeader.md b/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration.HTTPHeader.md deleted file mode 100644 index 72a0060071..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration.HTTPHeader.md +++ /dev/null @@ -1,21 +0,0 @@ -**STRUCT** - -# `ApolloSchemaDownloadConfiguration.HTTPHeader` - -```swift -public struct HTTPHeader: Equatable, CustomDebugStringConvertible -``` - -## Properties -### `debugDescription` - -```swift -public var debugDescription: String -``` - -## Methods -### `init(key:value:)` - -```swift -public init(key: String, value: String) -``` diff --git a/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration.md b/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration.md deleted file mode 100644 index 283d3dd159..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration.md +++ /dev/null @@ -1,72 +0,0 @@ -**STRUCT** - -# `ApolloSchemaDownloadConfiguration` - -```swift -public struct ApolloSchemaDownloadConfiguration -``` - -A configuration object that defines behavior for schema download. - -## Properties -### `downloadMethod` - -```swift -public let downloadMethod: DownloadMethod -``` - -How to download your schema. Supports the Apollo Registry and GraphQL Introspection methods. - -### `downloadTimeout` - -```swift -public let downloadTimeout: Double -``` - -The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. - -### `headers` - -```swift -public let headers: [HTTPHeader] -``` - -Any additional headers to include when retrieving your schema. Defaults to nil. - -### `outputURL` - -```swift -public let outputURL: URL -``` - -The URL of the folder in which the downloaded schema should be written. - -## Methods -### `init(using:timeout:headers:outputFolderURL:schemaFilename:)` - -```swift -public init(using downloadMethod: DownloadMethod, - timeout downloadTimeout: Double = 30.0, - headers: [HTTPHeader] = [], - outputFolderURL: URL, - schemaFilename: String = "schema") -``` - -Designated Initializer - -- Parameters: - - downloadMethod: How to download your schema. - - downloadTimeout: The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. - - headers: [optional] Any additional headers to include when retrieving your schema. Defaults to nil - - outputFolderURL: The URL of the folder in which the downloaded schema should be written - - schemaFilename: The name, without an extension, for your schema file. Defaults to `"schema" - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| downloadMethod | How to download your schema. | -| downloadTimeout | The maximum time to wait before indicating that the download timed out, in seconds. Defaults to 30 seconds. | -| headers | [optional] Any additional headers to include when retrieving your schema. Defaults to nil | -| outputFolderURL | The URL of the folder in which the downloaded schema should be written | -| schemaFilename | The name, without an extension, for your schema file. Defaults to `“schema” | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloader.md b/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloader.md deleted file mode 100644 index 9c0d93aad9..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/ApolloSchemaDownloader.md +++ /dev/null @@ -1,28 +0,0 @@ -**STRUCT** - -# `ApolloSchemaDownloader` - -```swift -public struct ApolloSchemaDownloader -``` - -A wrapper to facilitate downloading a schema with the Apollo node CLI - -## Methods -### `fetch(with:)` - -```swift -public static func fetch(with configuration: ApolloSchemaDownloadConfiguration) throws -``` - -Downloads your schema using the specified configuration object. - -- Parameters: - - configuration: The `ApolloSchemaDownloadConfiguration` object to use to download the schema. -- Returns: Output from a successful run - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| configuration | The `ApolloSchemaDownloadConfiguration` object to use to download the schema. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/Basher.md b/docs/source/api/ApolloCodegenLib/structs/Basher.md deleted file mode 100644 index 2e12d3bc8d..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/Basher.md +++ /dev/null @@ -1,30 +0,0 @@ -**STRUCT** - -# `Basher` - -```swift -public struct Basher -``` - -Bash command runner - -## Methods -### `run(command:from:)` - -```swift -public static func run(command: String, from url: URL?) throws -> String -``` - -Runs the given bash command as a string - -- Parameters: - - command: The bash command to run - - url: [optional] The URL to set as the `currentDirectoryURL`. -- Returns: The result of the command. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| command | The bash command to run | -| url | [optional] The URL to set as the `currentDirectoryURL`. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/CodegenLogger.md b/docs/source/api/ApolloCodegenLib/structs/CodegenLogger.md deleted file mode 100644 index 2ecccda14b..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/CodegenLogger.md +++ /dev/null @@ -1,45 +0,0 @@ -**STRUCT** - -# `CodegenLogger` - -```swift -public struct CodegenLogger -``` - -Helper to get logs printing to stdout so they can be read from the command line. - -## Properties -### `level` - -```swift -public static var level = LogLevel.debug -``` - -The `LogLevel` at which to print logs. Higher raw values than this will -be ignored. Defaults to `debug`. - -## Methods -### `log(_:logLevel:file:line:)` - -```swift -public static func log(_ logString: @autoclosure () -> String, - logLevel: LogLevel = .debug, - file: StaticString = #file, - line: UInt = #line) -``` - -Logs the given string if its `logLevel` is at or above `CodegenLogger.level`, otherwise ignores it. - -- Parameter logString: The string to log out, as an autoclosure -- Parameter logLevel: The log level at which to print this specific log. Defaults to `debug`. -- Parameter file: The file where this function was called. Defaults to the direct caller. -- Parameter line: The line where this function was called. Defaults to the direct caller. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| logString | The string to log out, as an autoclosure | -| logLevel | The log level at which to print this specific log. Defaults to `debug`. | -| file | The file where this function was called. Defaults to the direct caller. | -| line | The line where this function was called. Defaults to the direct caller. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/DownloadMethod.ApolloRegistrySettings.md b/docs/source/api/ApolloCodegenLib/structs/DownloadMethod.ApolloRegistrySettings.md deleted file mode 100644 index b05650cbb1..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/DownloadMethod.ApolloRegistrySettings.md +++ /dev/null @@ -1,56 +0,0 @@ -**STRUCT** - -# `DownloadMethod.ApolloRegistrySettings` - -```swift -public struct ApolloRegistrySettings: Equatable -``` - -## Properties -### `apiKey` - -```swift -public let apiKey: String -``` - -The API key to use when retrieving your schema from the Apollo Registry. - -### `graphID` - -```swift -public let graphID: String -``` - -The identifier of the graph to fetch. Can be found in Apollo Studio. - -### `variant` - -```swift -public let variant: String? -``` - -The variant of the graph in the registry. - -## Methods -### `init(apiKey:graphID:variant:)` - -```swift -public init(apiKey: String, - graphID: String, - variant: String = "current") -``` - -Designated initializer - -- Parameters: - - apiKey: The API key to use when retrieving your schema. - - graphID: The identifier of the graph to fetch. Can be found in Apollo Studio. - - variant: The variant of the graph to fetch. Defaults to "current", which will return whatever is set to the current variant. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| apiKey | The API key to use when retrieving your schema. | -| graphID | The identifier of the graph to fetch. Can be found in Apollo Studio. | -| variant | The variant of the graph to fetch. Defaults to “current”, which will return whatever is set to the current variant. | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/FileFinder.md b/docs/source/api/ApolloCodegenLib/structs/FileFinder.md deleted file mode 100644 index 06dacae773..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/FileFinder.md +++ /dev/null @@ -1,68 +0,0 @@ -**STRUCT** - -# `FileFinder` - -```swift -public struct FileFinder -``` - -## Methods -### `findParentFolder(from:)` - -```swift -public static func findParentFolder(from filePath: StaticString = #filePath) -> URL -``` - -Version that works if you're using the 5.3 compiler or above -- Parameter filePath: The full file path of the file to find. Defaults to the `#filePath` of the caller. -- Returns: The file URL for the parent folder. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| filePath | The full file path of the file to find. Defaults to the `#filePath` of the caller. | - -### `fileURL(from:)` - -```swift -public static func fileURL(from filePath: StaticString = #filePath) -> URL -``` - -The URL of a file at a given path -- Parameter filePath: The full file path of the file to find -- Returns: The file's URL - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| filePath | The full file path of the file to find | - -### `findParentFolder(from:)` - -Version that works if you're using the 5.2 compiler or below -- Parameter file: The full file path of the file to find. Defaults to the `#file` of the caller. -- Returns: The file URL for the parent folder. - -### `fileURL(from:)` - -The URL of a file at a given path -- Parameter filePath: The full file path of the file to find -- Returns: The file's URL - -### `findParentFolder(from:)` - -```swift -public static func findParentFolder(from filePath: String) -> URL -``` - -Finds the parent folder from a given file path. -- Parameter filePath: The full file path, as a string -- Returns: The file URL for the parent folder. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| filePath | The full file path, as a string | \ No newline at end of file diff --git a/docs/source/api/ApolloCodegenLib/structs/GraphQLSourceLocation.md b/docs/source/api/ApolloCodegenLib/structs/GraphQLSourceLocation.md deleted file mode 100644 index cc077fc11f..0000000000 --- a/docs/source/api/ApolloCodegenLib/structs/GraphQLSourceLocation.md +++ /dev/null @@ -1,9 +0,0 @@ -**STRUCT** - -# `GraphQLSourceLocation` - -```swift -public struct GraphQLSourceLocation -``` - -Represents a location in a GraphQL source file. diff --git a/docs/source/api/ApolloSQLite/README.md b/docs/source/api/ApolloSQLite/README.md deleted file mode 100644 index 8cb54bf69b..0000000000 --- a/docs/source/api/ApolloSQLite/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Reference Documentation - -## Protocols - -- [SQLiteDatabase](protocols/SQLiteDatabase/) - -## Structs - -- [DatabaseRow](structs/DatabaseRow/) - -## Classes - -- [SQLiteDotSwiftDatabase](classes/SQLiteDotSwiftDatabase/) -- [SQLiteNormalizedCache](classes/SQLiteNormalizedCache/) - -## Enums - -- [SQLiteNormalizedCacheError](enums/SQLiteNormalizedCacheError/) - -## Extensions - -- [SQLiteDatabase](extensions/SQLiteDatabase/) -- [SQLiteNormalizedCache](extensions/SQLiteNormalizedCache/) - -This file was generated by [SourceDocs](https://github.com/eneko/SourceDocs) \ No newline at end of file diff --git a/docs/source/api/ApolloSQLite/classes/SQLiteDotSwiftDatabase.md b/docs/source/api/ApolloSQLite/classes/SQLiteDotSwiftDatabase.md deleted file mode 100644 index a8df246ac8..0000000000 --- a/docs/source/api/ApolloSQLite/classes/SQLiteDotSwiftDatabase.md +++ /dev/null @@ -1,56 +0,0 @@ -**CLASS** - -# `SQLiteDotSwiftDatabase` - -```swift -public final class SQLiteDotSwiftDatabase: SQLiteDatabase -``` - -## Methods -### `init(fileURL:)` - -```swift -public init(fileURL: URL) throws -``` - -### `init(connection:)` - -```swift -public init(connection: Connection) -``` - -### `createRecordsTableIfNeeded()` - -```swift -public func createRecordsTableIfNeeded() throws -``` - -### `selectRawRows(forKeys:)` - -```swift -public func selectRawRows(forKeys keys: Set) throws -> [DatabaseRow] -``` - -### `addOrUpdateRecordString(_:for:)` - -```swift -public func addOrUpdateRecordString(_ recordString: String, for cacheKey: CacheKey) throws -``` - -### `deleteRecord(for:)` - -```swift -public func deleteRecord(for cacheKey: CacheKey) throws -``` - -### `deleteRecords(matching:)` - -```swift -public func deleteRecords(matching pattern: CacheKey) throws -``` - -### `clearDatabase(shouldVacuumOnClear:)` - -```swift -public func clearDatabase(shouldVacuumOnClear: Bool) throws -``` diff --git a/docs/source/api/ApolloSQLite/classes/SQLiteNormalizedCache.md b/docs/source/api/ApolloSQLite/classes/SQLiteNormalizedCache.md deleted file mode 100644 index 2ece84cd5a..0000000000 --- a/docs/source/api/ApolloSQLite/classes/SQLiteNormalizedCache.md +++ /dev/null @@ -1,39 +0,0 @@ -**CLASS** - -# `SQLiteNormalizedCache` - -```swift -public final class SQLiteNormalizedCache -``` - -A `NormalizedCache` implementation which uses a SQLite database to store data. - -## Methods -### `init(fileURL:databaseType:shouldVacuumOnClear:)` - -```swift -public init(fileURL: URL, - databaseType: SQLiteDatabase.Type = SQLiteDotSwiftDatabase.self, - shouldVacuumOnClear: Bool = false) throws -``` - -Designated initializer - -- Parameters: - - fileURL: The file URL to use for your database. - - shouldVacuumOnClear: If the database should also be `VACCUM`ed on clear to remove all traces of info. Defaults to `false` since this involves a performance hit, but this should be used if you are storing any Personally Identifiable Information in the cache. -- Throws: Any errors attempting to open or create the database. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| fileURL | The file URL to use for your database. | -| shouldVacuumOnClear | If the database should also be `VACCUM`ed on clear to remove all traces of info. Defaults to `false` since this involves a performance hit, but this should be used if you are storing any Personally Identifiable Information in the cache. | - -### `init(database:shouldVacuumOnClear:)` - -```swift -public init(database: SQLiteDatabase, - shouldVacuumOnClear: Bool = false) throws -``` diff --git a/docs/source/api/ApolloSQLite/enums/SQLiteNormalizedCacheError.md b/docs/source/api/ApolloSQLite/enums/SQLiteNormalizedCacheError.md deleted file mode 100644 index fc7113b51d..0000000000 --- a/docs/source/api/ApolloSQLite/enums/SQLiteNormalizedCacheError.md +++ /dev/null @@ -1,20 +0,0 @@ -**ENUM** - -# `SQLiteNormalizedCacheError` - -```swift -public enum SQLiteNormalizedCacheError: Error -``` - -## Cases -### `invalidRecordEncoding(record:)` - -```swift -case invalidRecordEncoding(record: String) -``` - -### `invalidRecordShape(object:)` - -```swift -case invalidRecordShape(object: Any) -``` diff --git a/docs/source/api/ApolloSQLite/extensions/SQLiteDatabase.md b/docs/source/api/ApolloSQLite/extensions/SQLiteDatabase.md deleted file mode 100644 index dc849b62cc..0000000000 --- a/docs/source/api/ApolloSQLite/extensions/SQLiteDatabase.md +++ /dev/null @@ -1,31 +0,0 @@ -**EXTENSION** - -# `SQLiteDatabase` -```swift -public extension SQLiteDatabase -``` - -## Properties -### `tableName` - -```swift -static var tableName: String -``` - -### `idColumnName` - -```swift -static var idColumnName: String -``` - -### `keyColumnName` - -```swift -static var keyColumnName: String -``` - -### `recordColumName` - -```swift -static var recordColumName: String -``` diff --git a/docs/source/api/ApolloSQLite/extensions/SQLiteNormalizedCache.md b/docs/source/api/ApolloSQLite/extensions/SQLiteNormalizedCache.md deleted file mode 100644 index 3f143bb0c5..0000000000 --- a/docs/source/api/ApolloSQLite/extensions/SQLiteNormalizedCache.md +++ /dev/null @@ -1,61 +0,0 @@ -**EXTENSION** - -# `SQLiteNormalizedCache` -```swift -extension SQLiteNormalizedCache: NormalizedCache -``` - -## Methods -### `loadRecords(forKeys:)` - -```swift -public func loadRecords(forKeys keys: Set) throws -> [CacheKey: Record] -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache keys to load data for | - -### `merge(records:)` - -```swift -public func merge(records: RecordSet) throws -> Set -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| records | The set of records to merge. | - -### `removeRecord(for:)` - -```swift -public func removeRecord(for key: CacheKey) throws -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | The cache key to remove the record for | - -### `removeRecords(matching:)` - -```swift -public func removeRecords(matching pattern: CacheKey) throws -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pattern | The pattern that will be applied to find matching keys. | - -### `clear()` - -```swift -public func clear() throws -``` diff --git a/docs/source/api/ApolloSQLite/protocols/SQLiteDatabase.md b/docs/source/api/ApolloSQLite/protocols/SQLiteDatabase.md deleted file mode 100644 index ae272cecb6..0000000000 --- a/docs/source/api/ApolloSQLite/protocols/SQLiteDatabase.md +++ /dev/null @@ -1,50 +0,0 @@ -**PROTOCOL** - -# `SQLiteDatabase` - -```swift -public protocol SQLiteDatabase -``` - -## Methods -### `init(fileURL:)` - -```swift -init(fileURL: URL) throws -``` - -### `createRecordsTableIfNeeded()` - -```swift -func createRecordsTableIfNeeded() throws -``` - -### `selectRawRows(forKeys:)` - -```swift -func selectRawRows(forKeys keys: Set) throws -> [DatabaseRow] -``` - -### `addOrUpdateRecordString(_:for:)` - -```swift -func addOrUpdateRecordString(_ recordString: String, for cacheKey: CacheKey) throws -``` - -### `deleteRecord(for:)` - -```swift -func deleteRecord(for cacheKey: CacheKey) throws -``` - -### `deleteRecords(matching:)` - -```swift -func deleteRecords(matching pattern: CacheKey) throws -``` - -### `clearDatabase(shouldVacuumOnClear:)` - -```swift -func clearDatabase(shouldVacuumOnClear: Bool) throws -``` diff --git a/docs/source/api/ApolloSQLite/structs/DatabaseRow.md b/docs/source/api/ApolloSQLite/structs/DatabaseRow.md deleted file mode 100644 index 10ca8a7015..0000000000 --- a/docs/source/api/ApolloSQLite/structs/DatabaseRow.md +++ /dev/null @@ -1,7 +0,0 @@ -**STRUCT** - -# `DatabaseRow` - -```swift -public struct DatabaseRow -``` diff --git a/docs/source/api/ApolloUtils/README.md b/docs/source/api/ApolloUtils/README.md deleted file mode 100644 index 17ea2a7d80..0000000000 --- a/docs/source/api/ApolloUtils/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Reference Documentation - -## Protocols - -- [ApolloCompatible](protocols/ApolloCompatible/) -- [DictionaryType](protocols/DictionaryType/) -- [OptionalType](protocols/OptionalType/) -- [ResultType](protocols/ResultType/) - -## Structs - -- [ApolloExtension](structs/ApolloExtension/) - -## Classes - -- [Atomic](classes/Atomic/) - -## Extensions - -- [ApolloCompatible](extensions/ApolloCompatible/) -- [ApolloExtension](extensions/ApolloExtension/) -- [Atomic](extensions/Atomic/) -- [Dictionary](extensions/Dictionary/) -- [Optional](extensions/Optional/) -- [Result](extensions/Result/) - -This file was generated by [SourceDocs](https://github.com/eneko/SourceDocs) \ No newline at end of file diff --git a/docs/source/api/ApolloUtils/classes/Atomic.md b/docs/source/api/ApolloUtils/classes/Atomic.md deleted file mode 100644 index 9c2fbe2080..0000000000 --- a/docs/source/api/ApolloUtils/classes/Atomic.md +++ /dev/null @@ -1,51 +0,0 @@ -**CLASS** - -# `Atomic` - -```swift -public class Atomic -``` - -Wrapper for a value protected by an NSLock - -## Properties -### `value` - -```swift -public var value: T -``` - -The current value. Read-only. To update the underlying value, use `mutate`. - -## Methods -### `init(_:)` - -```swift -public init(_ value: T) -``` - -Designated initializer - -- Parameter value: The value to begin with. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| value | The value to begin with. | - -### `mutate(block:)` - -```swift -public func mutate(block: (inout T) -> U) -> U -``` - -Mutates the underlying value within a lock. -- Parameter block: The block to execute to mutate the value. -- Returns: The value returned by the block. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| block | The block to execute to mutate the value. | \ No newline at end of file diff --git a/docs/source/api/ApolloUtils/extensions/ApolloCompatible.md b/docs/source/api/ApolloUtils/extensions/ApolloCompatible.md deleted file mode 100644 index 70bb4d58fa..0000000000 --- a/docs/source/api/ApolloUtils/extensions/ApolloCompatible.md +++ /dev/null @@ -1,19 +0,0 @@ -**EXTENSION** - -# `ApolloCompatible` -```swift -extension ApolloCompatible -``` - -## Properties -### `apollo` - -```swift -public var apollo: ApolloExtension -``` - -### `apollo` - -```swift -public static var apollo: ApolloExtension.Type -``` diff --git a/docs/source/api/ApolloUtils/extensions/ApolloExtension.md b/docs/source/api/ApolloUtils/extensions/ApolloExtension.md deleted file mode 100644 index 230efa27a8..0000000000 --- a/docs/source/api/ApolloUtils/extensions/ApolloExtension.md +++ /dev/null @@ -1,41 +0,0 @@ -**EXTENSION** - -# `ApolloExtension` -```swift -public extension ApolloExtension where Base: Collection -``` - -## Properties -### `isNotEmpty` - -```swift -var isNotEmpty: Bool -``` - -Convenience helper to make `guard` statements more readable - -- returns: `true` if the collection has contents. - -### `isEmptyOrNil` - -```swift -var isEmptyOrNil: Bool -``` - -- returns: `true` if the collection is empty or nil - -### `isNotEmpty` - -```swift -var isNotEmpty: Bool -``` - -- returns: `true` if the collection is non-nil AND has contents. - -### `sha256Hash` - -```swift -public var sha256Hash: String -``` - -The SHA256 hash of the current string. diff --git a/docs/source/api/ApolloUtils/extensions/Atomic.md b/docs/source/api/ApolloUtils/extensions/Atomic.md deleted file mode 100644 index f10d7599e2..0000000000 --- a/docs/source/api/ApolloUtils/extensions/Atomic.md +++ /dev/null @@ -1,15 +0,0 @@ -**EXTENSION** - -# `Atomic` -```swift -public extension Atomic where T == Int -``` - -## Methods -### `increment()` - -```swift -func increment() -> T -``` - -Increments in a lock-compatible fashion diff --git a/docs/source/api/ApolloUtils/extensions/Dictionary.md b/docs/source/api/ApolloUtils/extensions/Dictionary.md deleted file mode 100644 index ada2f6cb56..0000000000 --- a/docs/source/api/ApolloUtils/extensions/Dictionary.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `Dictionary` -```swift -extension Dictionary: DictionaryType -``` - -## Properties -### `underlying` - -```swift -public var underlying: [Key: Value] -``` diff --git a/docs/source/api/ApolloUtils/extensions/Optional.md b/docs/source/api/ApolloUtils/extensions/Optional.md deleted file mode 100644 index 01925a8373..0000000000 --- a/docs/source/api/ApolloUtils/extensions/Optional.md +++ /dev/null @@ -1,15 +0,0 @@ -**EXTENSION** - -# `Optional` -```swift -extension Optional: OptionalType -``` - -## Properties -### `underlying` - -```swift -public var underlying: Wrapped? -``` - -Return the value if it exists, otherwise `nil` diff --git a/docs/source/api/ApolloUtils/extensions/Result.md b/docs/source/api/ApolloUtils/extensions/Result.md deleted file mode 100644 index b99358f0e6..0000000000 --- a/docs/source/api/ApolloUtils/extensions/Result.md +++ /dev/null @@ -1,13 +0,0 @@ -**EXTENSION** - -# `Result` -```swift -extension Result: ResultType -``` - -## Properties -### `underlying` - -```swift -public var underlying: Result -``` diff --git a/docs/source/api/ApolloUtils/protocols/ApolloCompatible.md b/docs/source/api/ApolloUtils/protocols/ApolloCompatible.md deleted file mode 100644 index 6aa9715956..0000000000 --- a/docs/source/api/ApolloUtils/protocols/ApolloCompatible.md +++ /dev/null @@ -1,29 +0,0 @@ -**PROTOCOL** - -# `ApolloCompatible` - -```swift -public protocol ApolloCompatible -``` - -Protocol to allow calls to extended methods and vars as object.apollo.method - -NOTE: This does not work with a bunch of stuff involving generic types - those -still need to use old-school `apollo_method` naming conventions. - -## Properties -### `apollo` - -```swift -var apollo: ApolloExtension -``` - -The `ApolloExtension` object for an instance - -### `apollo` - -```swift -static var apollo: ApolloExtension.Type -``` - -The `ApolloExtension` object for a type diff --git a/docs/source/api/ApolloUtils/protocols/DictionaryType.md b/docs/source/api/ApolloUtils/protocols/DictionaryType.md deleted file mode 100644 index 4eb91cc4ba..0000000000 --- a/docs/source/api/ApolloUtils/protocols/DictionaryType.md +++ /dev/null @@ -1,16 +0,0 @@ -**PROTOCOL** - -# `DictionaryType` - -```swift -public protocol DictionaryType: ExpressibleByDictionaryLiteral -``` - -Provides a PAT interface to `Dictionary` - -## Properties -### `underlying` - -```swift -var underlying: [KeyType: ValueType] -``` diff --git a/docs/source/api/ApolloUtils/protocols/OptionalType.md b/docs/source/api/ApolloUtils/protocols/OptionalType.md deleted file mode 100644 index ccfddfa2f3..0000000000 --- a/docs/source/api/ApolloUtils/protocols/OptionalType.md +++ /dev/null @@ -1,16 +0,0 @@ -**PROTOCOL** - -# `OptionalType` - -```swift -public protocol OptionalType: ExpressibleByNilLiteral -``` - -Provides a PAT interface to `Optional` - -## Properties -### `underlying` - -```swift -var underlying: WrappedType? -``` diff --git a/docs/source/api/ApolloUtils/protocols/ResultType.md b/docs/source/api/ApolloUtils/protocols/ResultType.md deleted file mode 100644 index fc67e699ee..0000000000 --- a/docs/source/api/ApolloUtils/protocols/ResultType.md +++ /dev/null @@ -1,16 +0,0 @@ -**PROTOCOL** - -# `ResultType` - -```swift -public protocol ResultType -``` - -Provides a PAT interface to `Result` - -## Properties -### `underlying` - -```swift -var underlying: Result -``` diff --git a/docs/source/api/ApolloUtils/structs/ApolloExtension.md b/docs/source/api/ApolloUtils/structs/ApolloExtension.md deleted file mode 100644 index a06b88b0b2..0000000000 --- a/docs/source/api/ApolloUtils/structs/ApolloExtension.md +++ /dev/null @@ -1,18 +0,0 @@ -**STRUCT** - -# `ApolloExtension` - -```swift -public struct ApolloExtension -``` - -Wrapper to allow calls to extended methods and vars as object.apollo.method - -## Properties -### `base` - -```swift -public let base: Base -``` - -The base type in the extension diff --git a/docs/source/api/ApolloWebSocket/README.md b/docs/source/api/ApolloWebSocket/README.md deleted file mode 100644 index 6cadfce05d..0000000000 --- a/docs/source/api/ApolloWebSocket/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Reference Documentation - -## Protocols - -- [OperationMessageIdCreator](protocols/OperationMessageIdCreator/) -- [SSLTrustValidator](protocols/SSLTrustValidator/) -- [WebSocketClient](protocols/WebSocketClient/) -- [WebSocketClientDelegate](protocols/WebSocketClientDelegate/) -- [WebSocketTransportDelegate](protocols/WebSocketTransportDelegate/) - -## Structs - -- [ApolloSequencedOperationMessageIdCreator](structs/ApolloSequencedOperationMessageIdCreator/) -- [SSLClientCertificateError](structs/SSLClientCertificateError/) -- [SSLSettings](structs/SSLSettings/) -- [WebSocket.WSError](structs/WebSocket.WSError/) -- [WebSocketError](structs/WebSocketError/) - -## Classes - -- [SSLCert](classes/SSLCert/) -- [SSLClientCertificate](classes/SSLClientCertificate/) -- [SSLSecurity](classes/SSLSecurity/) -- [SplitNetworkTransport](classes/SplitNetworkTransport/) -- [WebSocket](classes/WebSocket/) -- [WebSocketTransport](classes/WebSocketTransport/) - -## Enums - -- [WSError.ErrorType](enums/WSError.ErrorType/) -- [WebSocket.OpCode](enums/WebSocket.OpCode/) -- [WebSocket.WSProtocol](enums/WebSocket.WSProtocol/) -- [WebSocketError.ErrorKind](enums/WebSocketError.ErrorKind/) - -## Extensions - -- [SplitNetworkTransport](extensions/SplitNetworkTransport/) -- [WebSocketTransport](extensions/WebSocketTransport/) -- [WebSocketTransportDelegate](extensions/WebSocketTransportDelegate/) - -This file was generated by [SourceDocs](https://github.com/eneko/SourceDocs) \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/classes/SSLCert.md b/docs/source/api/ApolloWebSocket/classes/SSLCert.md deleted file mode 100644 index e312715737..0000000000 --- a/docs/source/api/ApolloWebSocket/classes/SSLCert.md +++ /dev/null @@ -1,44 +0,0 @@ -**CLASS** - -# `SSLCert` - -```swift -open class SSLCert -``` - -## Methods -### `init(data:)` - -```swift -public init(data: Data) -``` - -Designated init for certificates - -- parameter data: is the binary data of the certificate - -- returns: a representation security object to be used with - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| data | is the binary data of the certificate | - -### `init(key:)` - -```swift -public init(key: SecKey) -``` - -Designated init for public keys - -- parameter key: is the public key to be used - -- returns: a representation security object to be used with - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| key | is the public key to be used | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/classes/SSLClientCertificate.md b/docs/source/api/ApolloWebSocket/classes/SSLClientCertificate.md deleted file mode 100644 index 7b3c6612d6..0000000000 --- a/docs/source/api/ApolloWebSocket/classes/SSLClientCertificate.md +++ /dev/null @@ -1,78 +0,0 @@ -**CLASS** - -# `SSLClientCertificate` - -```swift -public class SSLClientCertificate -``` - -## Methods -### `init(pkcs12Path:password:)` - -```swift -public convenience init(pkcs12Path: String, password: String) throws -``` - -Convenience init. -- parameter pkcs12Path: Path to pkcs12 file containing private key and X.509 ceritifacte (.p12) -- parameter password: file password, see **kSecImportExportPassphrase** - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pkcs12Path | Path to pkcs12 file containing private key and X.509 ceritifacte (.p12) | -| password | file password, see | - -### `init(identity:identityCertificate:)` - -```swift -public init(identity: SecIdentity, identityCertificate: SecCertificate) -``` - -Designated init. For more information, see SSLSetCertificate() in Security/SecureTransport.h. -- parameter identity: SecIdentityRef, see **kCFStreamSSLCertificates** -- parameter identityCertificate: CFArray of SecCertificateRefs, see **kCFStreamSSLCertificates** - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| identity | SecIdentityRef, see | -| identityCertificate | CFArray of SecCertificateRefs, see | - -### `init(pkcs12Url:password:)` - -```swift -public convenience init(pkcs12Url: URL, password: String) throws -``` - -Convenience init. -- parameter pkcs12Url: URL to pkcs12 file containing private key and X.509 ceritifacte (.p12) -- parameter password: file password, see **kSecImportExportPassphrase** - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pkcs12Url | URL to pkcs12 file containing private key and X.509 ceritifacte (.p12) | -| password | file password, see | - -### `init(pkcs12Url:importOptions:)` - -```swift -public init(pkcs12Url: URL, importOptions: CFDictionary) throws -``` - -Designated init. -- parameter pkcs12Url: URL to pkcs12 file containing private key and X.509 ceritifacte (.p12) -- parameter importOptions: A dictionary containing import options. A -kSecImportExportPassphrase entry is required at minimum. Only password-based -PKCS12 blobs are currently supported. See **SecImportExport.h** - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| pkcs12Url | URL to pkcs12 file containing private key and X.509 ceritifacte (.p12) | -| importOptions | A dictionary containing import options. A kSecImportExportPassphrase entry is required at minimum. Only password-based PKCS12 blobs are currently supported. See | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/classes/SSLSecurity.md b/docs/source/api/ApolloWebSocket/classes/SSLSecurity.md deleted file mode 100644 index 13b321072b..0000000000 --- a/docs/source/api/ApolloWebSocket/classes/SSLSecurity.md +++ /dev/null @@ -1,151 +0,0 @@ -**CLASS** - -# `SSLSecurity` - -```swift -open class SSLSecurity : SSLTrustValidator -``` - -## Properties -### `validatedDN` - -```swift -public var validatedDN = true -``` - -### `validateEntireChain` - -```swift -public var validateEntireChain = true -``` - -## Methods -### `init(usePublicKeys:)` - -```swift -public convenience init(usePublicKeys: Bool = false) -``` - -Use certs from main app bundle - -- parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation - -- returns: a representation security object to be used with - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| usePublicKeys | is to specific if the publicKeys or certificates should be used for SSL pinning validation | - -### `init(certs:usePublicKeys:)` - -```swift -public init(certs: [SSLCert], usePublicKeys: Bool) -``` - -Designated init - -- parameter certs: is the certificates or public keys to use -- parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation - -- returns: a representation security object to be used with - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| certs | is the certificates or public keys to use | -| usePublicKeys | is to specific if the publicKeys or certificates should be used for SSL pinning validation | - -### `isValid(_:domain:)` - -```swift -open func isValid(_ trust: SecTrust, domain: String?) -> Bool -``` - -Valid the trust and domain name. - -- parameter trust: is the serverTrust to validate -- parameter domain: is the CN domain to validate - -- returns: if the key was successfully validated - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| trust | is the serverTrust to validate | -| domain | is the CN domain to validate | - -### `extractPublicKey(_:)` - -```swift -public func extractPublicKey(_ data: Data) -> SecKey? -``` - -Get the public key from a certificate data - -- parameter data: is the certificate to pull the public key from - -- returns: a public key - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| data | is the certificate to pull the public key from | - -### `extractPublicKey(_:policy:)` - -```swift -public func extractPublicKey(_ cert: SecCertificate, policy: SecPolicy) -> SecKey? -``` - -Get the public key from a certificate - -- parameter data: is the certificate to pull the public key from - -- returns: a public key - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| data | is the certificate to pull the public key from | - -### `certificateChain(_:)` - -```swift -public func certificateChain(_ trust: SecTrust) -> [Data] -``` - -Get the certificate chain for the trust - -- parameter trust: is the trust to lookup the certificate chain for - -- returns: the certificate chain for the trust - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| trust | is the trust to lookup the certificate chain for | - -### `publicKeyChain(_:)` - -```swift -public func publicKeyChain(_ trust: SecTrust) -> [SecKey] -``` - -Get the public key chain for the trust - -- parameter trust: is the trust to lookup the certificate chain and extract the public keys - -- returns: the public keys from the certifcate chain for the trust - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| trust | is the trust to lookup the certificate chain and extract the public keys | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/classes/SplitNetworkTransport.md b/docs/source/api/ApolloWebSocket/classes/SplitNetworkTransport.md deleted file mode 100644 index ac996e40a1..0000000000 --- a/docs/source/api/ApolloWebSocket/classes/SplitNetworkTransport.md +++ /dev/null @@ -1,42 +0,0 @@ -**CLASS** - -# `SplitNetworkTransport` - -```swift -public class SplitNetworkTransport -``` - -A network transport that sends subscriptions using one `NetworkTransport` and other requests using another `NetworkTransport`. Ideal for sending subscriptions via a web socket but everything else via HTTP. - -## Properties -### `clientName` - -```swift -public var clientName: String -``` - -### `clientVersion` - -```swift -public var clientVersion: String -``` - -## Methods -### `init(uploadingNetworkTransport:webSocketNetworkTransport:)` - -```swift -public init(uploadingNetworkTransport: UploadingNetworkTransport, webSocketNetworkTransport: NetworkTransport) -``` - -Designated initializer - -- Parameters: - - uploadingNetworkTransport: An `UploadingNetworkTransport` to use for non-subscription requests. Should generally be a `RequestChainNetworkTransport` or something similar. - - webSocketNetworkTransport: A `NetworkTransport` to use for subscription requests. Should generally be a `WebSocketTransport` or something similar. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| uploadingNetworkTransport | An `UploadingNetworkTransport` to use for non-subscription requests. Should generally be a `RequestChainNetworkTransport` or something similar. | -| webSocketNetworkTransport | A `NetworkTransport` to use for subscription requests. Should generally be a `WebSocketTransport` or something similar. | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/classes/WebSocket.md b/docs/source/api/ApolloWebSocket/classes/WebSocket.md deleted file mode 100644 index c828815000..0000000000 --- a/docs/source/api/ApolloWebSocket/classes/WebSocket.md +++ /dev/null @@ -1,238 +0,0 @@ -**CLASS** - -# `WebSocket` - -```swift -public final class WebSocket: NSObject, WebSocketClient, StreamDelegate, WebSocketStreamDelegate -``` - -## Properties -### `delegate` - -```swift -public weak var delegate: WebSocketClientDelegate? -``` - -Responds to callback about new messages coming in over the WebSocket -and also connection/disconnect messages. - -### `callbackQueue` - -```swift -public var callbackQueue = DispatchQueue.main -``` - -### `onConnect` - -```swift -public var onConnect: (() -> Void)? -``` - -### `onDisconnect` - -```swift -public var onDisconnect: ((Error?) -> Void)? -``` - -### `onText` - -```swift -public var onText: ((String) -> Void)? -``` - -### `onData` - -```swift -public var onData: ((Data) -> Void)? -``` - -### `onPong` - -```swift -public var onPong: ((Data?) -> Void)? -``` - -### `onHttpResponseHeaders` - -```swift -public var onHttpResponseHeaders: (([String: String]) -> Void)? -``` - -### `disableSSLCertValidation` - -```swift -public var disableSSLCertValidation = false -``` - -### `overrideTrustHostname` - -```swift -public var overrideTrustHostname = false -``` - -### `desiredTrustHostname` - -```swift -public var desiredTrustHostname: String? = nil -``` - -### `sslClientCertificate` - -```swift -public var sslClientCertificate: SSLClientCertificate? = nil -``` - -### `enableCompression` - -```swift -public var enableCompression = true -``` - -### `security` - -```swift -public var security: SSLTrustValidator? -``` - -### `enabledSSLCipherSuites` - -```swift -public var enabledSSLCipherSuites: [SSLCipherSuite]? -``` - -### `isConnected` - -```swift -public var isConnected: Bool -``` - -### `request` - -```swift -public var request: URLRequest -``` - -### `currentURL` - -```swift -public var currentURL: URL -``` - -### `respondToPingWithPong` - -```swift -public var respondToPingWithPong: Bool = true -``` - -## Methods -### `init(request:protocol:)` - -```swift -public init(request: URLRequest, protocol: WSProtocol) -``` - -Designated initializer. - -- Parameters: - - request: A URL request object that provides request-specific information such as the URL. - - protocol: Protocol to use for communication over the web socket. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| request | A URL request object that provides request-specific information such as the URL. | -| protocol | Protocol to use for communication over the web socket. | - -### `init(url:protocol:)` - -```swift -public convenience init(url: URL, protocol: WSProtocol) -``` - -Convenience initializer to specify the URL and web socket protocol. - -- Parameters: - - url: The destination URL to connect to. - - protocol: Protocol to use for communication over the web socket. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The destination URL to connect to. | -| protocol | Protocol to use for communication over the web socket. | - -### `init(url:writeQueueQOS:protocol:)` - -```swift -public convenience init( - url: URL, - writeQueueQOS: QualityOfService, - protocol: WSProtocol -) -``` - -Convenience initializer to specify the URL and web socket protocol with a specific quality of -service on the write queue. - -- Parameters: - - url: The destination URL to connect to. - - writeQueueQOS: Specifies the quality of service for the write queue. - - protocol: Protocol to use for communication over the web socket. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| url | The destination URL to connect to. | -| writeQueueQOS | Specifies the quality of service for the write queue. | -| protocol | Protocol to use for communication over the web socket. | - -### `connect()` - -```swift -public func connect() -``` - -Connect to the WebSocket server on a background thread. - -### `disconnect()` - -```swift -public func disconnect() -``` - -### `write(string:)` - -```swift -public func write(string: String) -``` - -### `write(ping:completion:)` - -```swift -public func write(ping: Data, completion: (() -> ())? = nil) -``` - -Write a ping to the websocket. This sends it as a control frame. - -### `newBytesInStream()` - -```swift -public func newBytesInStream() -``` - -Delegate for the stream methods. Processes incoming bytes - -### `streamDidError(error:)` - -```swift -public func streamDidError(error: Error?) -``` - -### `deinit` - -```swift -deinit -``` diff --git a/docs/source/api/ApolloWebSocket/classes/WebSocketTransport.md b/docs/source/api/ApolloWebSocket/classes/WebSocketTransport.md deleted file mode 100644 index 2bd5f15bc2..0000000000 --- a/docs/source/api/ApolloWebSocket/classes/WebSocketTransport.md +++ /dev/null @@ -1,158 +0,0 @@ -**CLASS** - -# `WebSocketTransport` - -```swift -public class WebSocketTransport -``` - -A network transport that uses web sockets requests to send GraphQL subscription operations to a server. - -## Properties -### `delegate` - -```swift -public weak var delegate: WebSocketTransportDelegate? -``` - -### `clientName` - -```swift -public var clientName: String -``` - -- NOTE: Setting this won't override immediately if the socket is still connected, only on reconnection. - -### `clientVersion` - -```swift -public var clientVersion: String -``` - -- NOTE: Setting this won't override immediately if the socket is still connected, only on reconnection. - -## Methods -### `init(websocket:store:clientName:clientVersion:sendOperationIdentifiers:reconnect:reconnectionInterval:allowSendingDuplicates:connectOnInit:connectingPayload:requestBodyCreator:operationMessageIdCreator:)` - -```swift -public init(websocket: WebSocketClient, - store: ApolloStore? = nil, - clientName: String = WebSocketTransport.defaultClientName, - clientVersion: String = WebSocketTransport.defaultClientVersion, - sendOperationIdentifiers: Bool = false, - reconnect: Bool = true, - reconnectionInterval: TimeInterval = 0.5, - allowSendingDuplicates: Bool = true, - connectOnInit: Bool = true, - connectingPayload: GraphQLMap? = [:], - requestBodyCreator: RequestBodyCreator = ApolloRequestBodyCreator(), - operationMessageIdCreator: OperationMessageIdCreator = ApolloSequencedOperationMessageIdCreator()) -``` - -Designated initializer - -- Parameters: - - websocket: The websocket client to use for creating a websocket connection. - - store: [optional] The `ApolloStore` used as a local cache. Defaults to `nil`. - - clientName: The client name to use for this client. Defaults to `Self.defaultClientName` - - clientVersion: The client version to use for this client. Defaults to `Self.defaultClientVersion`. - - sendOperationIdentifiers: Whether or not to send operation identifiers with operations. Defaults to false. - - reconnect: Whether to auto reconnect when websocket looses connection. Defaults to true. - - reconnectionInterval: How long to wait before attempting to reconnect. Defaults to half a second. - - allowSendingDuplicates: Allow sending duplicate messages. Important when reconnected. Defaults to true. - - connectOnInit: Whether the websocket connects immediately on creation. If false, remember to call `resumeWebSocketConnection()` to connect. Defaults to true. - - connectingPayload: [optional] The payload to send on connection. Defaults to an empty `GraphQLMap`. - - requestBodyCreator: The `RequestBodyCreator` to use when serializing requests. Defaults to an `ApolloRequestBodyCreator`. - - operationMessageIdCreator: The `OperationMessageIdCreator` used to generate a unique message identifier per request. Defaults to `ApolloSequencedOperationMessageIdCreator`. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| websocket | The websocket client to use for creating a websocket connection. | -| store | [optional] The `ApolloStore` used as a local cache. Defaults to `nil`. | -| clientName | The client name to use for this client. Defaults to `Self.defaultClientName` | -| clientVersion | The client version to use for this client. Defaults to `Self.defaultClientVersion`. | -| sendOperationIdentifiers | Whether or not to send operation identifiers with operations. Defaults to false. | -| reconnect | Whether to auto reconnect when websocket looses connection. Defaults to true. | -| reconnectionInterval | How long to wait before attempting to reconnect. Defaults to half a second. | -| allowSendingDuplicates | Allow sending duplicate messages. Important when reconnected. Defaults to true. | -| connectOnInit | Whether the websocket connects immediately on creation. If false, remember to call `resumeWebSocketConnection()` to connect. Defaults to true. | -| connectingPayload | [optional] The payload to send on connection. Defaults to an empty `GraphQLMap`. | -| requestBodyCreator | The `RequestBodyCreator` to use when serializing requests. Defaults to an `ApolloRequestBodyCreator`. | -| operationMessageIdCreator | The `OperationMessageIdCreator` used to generate a unique message identifier per request. Defaults to `ApolloSequencedOperationMessageIdCreator`. | - -### `isConnected()` - -```swift -public func isConnected() -> Bool -``` - -### `ping(data:completionHandler:)` - -```swift -public func ping(data: Data, completionHandler: (() -> Void)? = nil) -``` - -### `initServer()` - -```swift -public func initServer() -``` - -### `closeConnection()` - -```swift -public func closeConnection() -``` - -### `deinit` - -```swift -deinit -``` - -### `unsubscribe(_:)` - -```swift -public func unsubscribe(_ subscriptionId: String) -``` - -### `updateHeaderValues(_:reconnectIfConnected:)` - -```swift -public func updateHeaderValues(_ values: [String: String?], reconnectIfConnected: Bool = true) -``` - -### `updateConnectingPayload(_:reconnectIfConnected:)` - -```swift -public func updateConnectingPayload(_ payload: GraphQLMap, reconnectIfConnected: Bool = true) -``` - -### `pauseWebSocketConnection()` - -```swift -public func pauseWebSocketConnection() -``` - -Disconnects the websocket while setting the auto-reconnect value to false, -allowing purposeful disconnects that do not dump existing subscriptions. -NOTE: You will receive an error on the subscription (should be a `WebSocket.WSError` with code 1000) when the socket disconnects. -ALSO NOTE: To reconnect after calling this, you will need to call `resumeWebSocketConnection`. - -### `resumeWebSocketConnection(autoReconnect:)` - -```swift -public func resumeWebSocketConnection(autoReconnect: Bool = true) -``` - -Reconnects a paused web socket. - -- Parameter autoReconnect: `true` if you want the websocket to automatically reconnect if the connection drops. Defaults to true. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| autoReconnect | `true` if you want the websocket to automatically reconnect if the connection drops. Defaults to true. | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/enums/WSError.ErrorType.md b/docs/source/api/ApolloWebSocket/enums/WSError.ErrorType.md deleted file mode 100644 index efad57c85c..0000000000 --- a/docs/source/api/ApolloWebSocket/enums/WSError.ErrorType.md +++ /dev/null @@ -1,44 +0,0 @@ -**ENUM** - -# `WSError.ErrorType` - -```swift -public enum ErrorType -``` - -## Cases -### `outputStreamWriteError` - -```swift -case outputStreamWriteError -``` - -### `invalidSSLError` - -```swift -case invalidSSLError -``` - -### `writeTimeoutError` - -```swift -case writeTimeoutError -``` - -### `protocolError` - -```swift -case protocolError -``` - -### `upgradeError` - -```swift -case upgradeError -``` - -### `closeError` - -```swift -case closeError -``` diff --git a/docs/source/api/ApolloWebSocket/enums/WebSocket.OpCode.md b/docs/source/api/ApolloWebSocket/enums/WebSocket.OpCode.md deleted file mode 100644 index 106d018cc8..0000000000 --- a/docs/source/api/ApolloWebSocket/enums/WebSocket.OpCode.md +++ /dev/null @@ -1,44 +0,0 @@ -**ENUM** - -# `WebSocket.OpCode` - -```swift -public enum OpCode : UInt8 -``` - -## Cases -### `continueFrame` - -```swift -case continueFrame = 0x0 -``` - -### `textFrame` - -```swift -case textFrame = 0x1 -``` - -### `binaryFrame` - -```swift -case binaryFrame = 0x2 -``` - -### `connectionClose` - -```swift -case connectionClose = 0x8 -``` - -### `ping` - -```swift -case ping = 0x9 -``` - -### `pong` - -```swift -case pong = 0xA -``` diff --git a/docs/source/api/ApolloWebSocket/enums/WebSocket.WSProtocol.md b/docs/source/api/ApolloWebSocket/enums/WebSocket.WSProtocol.md deleted file mode 100644 index b609043b0c..0000000000 --- a/docs/source/api/ApolloWebSocket/enums/WebSocket.WSProtocol.md +++ /dev/null @@ -1,35 +0,0 @@ -**ENUM** - -# `WebSocket.WSProtocol` - -```swift -public enum WSProtocol: CustomStringConvertible -``` - -The GraphQL over WebSocket protocols supported by apollo-ios. - -## Cases -### `graphql_ws` - -```swift -case graphql_ws -``` - -WebSocket protocol `graphql-ws`. This is implemented by the [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) -and AWS AppSync libraries. - -### `graphql_transport_ws` - -```swift -case graphql_transport_ws -``` - -WebSocket protocol `graphql-transport-ws`. This is implemented by the [graphql-ws](https://github.com/enisdenjo/graphql-ws) -library. - -## Properties -### `description` - -```swift -public var description: String -``` diff --git a/docs/source/api/ApolloWebSocket/enums/WebSocketError.ErrorKind.md b/docs/source/api/ApolloWebSocket/enums/WebSocketError.ErrorKind.md deleted file mode 100644 index 94c00248db..0000000000 --- a/docs/source/api/ApolloWebSocket/enums/WebSocketError.ErrorKind.md +++ /dev/null @@ -1,44 +0,0 @@ -**ENUM** - -# `WebSocketError.ErrorKind` - -```swift -public enum ErrorKind -``` - -## Cases -### `errorResponse` - -```swift -case errorResponse -``` - -### `networkError` - -```swift -case networkError -``` - -### `unprocessedMessage(_:)` - -```swift -case unprocessedMessage(String) -``` - -### `serializedMessageError` - -```swift -case serializedMessageError -``` - -### `neitherErrorNorPayloadReceived` - -```swift -case neitherErrorNorPayloadReceived -``` - -### `upgradeError(code:)` - -```swift -case upgradeError(code: Int) -``` diff --git a/docs/source/api/ApolloWebSocket/extensions/SplitNetworkTransport.md b/docs/source/api/ApolloWebSocket/extensions/SplitNetworkTransport.md deleted file mode 100644 index 58c960ddad..0000000000 --- a/docs/source/api/ApolloWebSocket/extensions/SplitNetworkTransport.md +++ /dev/null @@ -1,46 +0,0 @@ -**EXTENSION** - -# `SplitNetworkTransport` -```swift -extension SplitNetworkTransport: NetworkTransport -``` - -## Methods -### `send(operation:cachePolicy:contextIdentifier:callbackQueue:completionHandler:)` - -```swift -public func send(operation: Operation, - cachePolicy: CachePolicy, - contextIdentifier: UUID? = nil, - callbackQueue: DispatchQueue = .main, - completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send. | -| cachePolicy | The `CachePolicy` to use making this request. | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | A closure to call when a request completes. On `success` will contain the response received from the server. On `failure` will contain the error which occurred. | - -### `upload(operation:files:callbackQueue:completionHandler:)` - -```swift -public func upload( - operation: Operation, - files: [GraphQLFile], - callbackQueue: DispatchQueue = .main, - completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send | -| files | An array of `GraphQLFile` objects to send. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | The completion handler to execute when the request completes or errors | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/extensions/WebSocketTransport.md b/docs/source/api/ApolloWebSocket/extensions/WebSocketTransport.md deleted file mode 100644 index 0c768c8f2b..0000000000 --- a/docs/source/api/ApolloWebSocket/extensions/WebSocketTransport.md +++ /dev/null @@ -1,85 +0,0 @@ -**EXTENSION** - -# `WebSocketTransport` -```swift -extension WebSocketTransport: NetworkTransport -``` - -## Methods -### `send(operation:cachePolicy:contextIdentifier:callbackQueue:completionHandler:)` - -```swift -public func send( - operation: Operation, - cachePolicy: CachePolicy, - contextIdentifier: UUID? = nil, - callbackQueue: DispatchQueue = .main, - completionHandler: @escaping (Result, Error>) -> Void) -> Cancellable -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| operation | The operation to send. | -| cachePolicy | The `CachePolicy` to use making this request. | -| contextIdentifier | [optional] A unique identifier for this request, to help with deduping cache hits for watchers. Defaults to `nil`. | -| callbackQueue | The queue to call back on with the results. Should default to `.main`. | -| completionHandler | A closure to call when a request completes. On `success` will contain the response received from the server. On `failure` will contain the error which occurred. | - -### `websocketDidConnect(socket:)` - -```swift -public func websocketDidConnect(socket: WebSocketClient) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | - -### `handleConnection()` - -```swift -public func handleConnection() -``` - -### `websocketDidDisconnect(socket:error:)` - -```swift -public func websocketDidDisconnect(socket: WebSocketClient, error: Error?) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | -| error | An optional error if an error occured. | - -### `websocketDidReceiveMessage(socket:text:)` - -```swift -public func websocketDidReceiveMessage(socket: WebSocketClient, text: String) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | -| text | The text received from the server. | - -### `websocketDidReceiveData(socket:data:)` - -```swift -public func websocketDidReceiveData(socket: WebSocketClient, data: Data) -``` - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | -| data | The data received from the server. | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/extensions/WebSocketTransportDelegate.md b/docs/source/api/ApolloWebSocket/extensions/WebSocketTransportDelegate.md deleted file mode 100644 index e299ce858e..0000000000 --- a/docs/source/api/ApolloWebSocket/extensions/WebSocketTransportDelegate.md +++ /dev/null @@ -1,37 +0,0 @@ -**EXTENSION** - -# `WebSocketTransportDelegate` -```swift -public extension WebSocketTransportDelegate -``` - -## Methods -### `webSocketTransportDidConnect(_:)` - -```swift -func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) -``` - -### `webSocketTransportDidReconnect(_:)` - -```swift -func webSocketTransportDidReconnect(_ webSocketTransport: WebSocketTransport) -``` - -### `webSocketTransport(_:didDisconnectWithError:)` - -```swift -func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error:Error?) -``` - -### `webSocketTransport(_:didReceivePingData:)` - -```swift -func webSocketTransport(_ webSocketTransport: WebSocketTransport, didReceivePingData: Data?) -``` - -### `webSocketTransport(_:didReceivePongData:)` - -```swift -func webSocketTransport(_ webSocketTransport: WebSocketTransport, didReceivePongData: Data?) -``` diff --git a/docs/source/api/ApolloWebSocket/protocols/OperationMessageIdCreator.md b/docs/source/api/ApolloWebSocket/protocols/OperationMessageIdCreator.md deleted file mode 100644 index 25f07411f1..0000000000 --- a/docs/source/api/ApolloWebSocket/protocols/OperationMessageIdCreator.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `OperationMessageIdCreator` - -```swift -public protocol OperationMessageIdCreator -``` - -## Methods -### `requestId()` - -```swift -func requestId() -> String -``` diff --git a/docs/source/api/ApolloWebSocket/protocols/SSLTrustValidator.md b/docs/source/api/ApolloWebSocket/protocols/SSLTrustValidator.md deleted file mode 100644 index 8c7a950b25..0000000000 --- a/docs/source/api/ApolloWebSocket/protocols/SSLTrustValidator.md +++ /dev/null @@ -1,14 +0,0 @@ -**PROTOCOL** - -# `SSLTrustValidator` - -```swift -public protocol SSLTrustValidator -``` - -## Methods -### `isValid(_:domain:)` - -```swift -func isValid(_ trust: SecTrust, domain: String?) -> Bool -``` diff --git a/docs/source/api/ApolloWebSocket/protocols/WebSocketClient.md b/docs/source/api/ApolloWebSocket/protocols/WebSocketClient.md deleted file mode 100644 index dfc07da408..0000000000 --- a/docs/source/api/ApolloWebSocket/protocols/WebSocketClient.md +++ /dev/null @@ -1,72 +0,0 @@ -**PROTOCOL** - -# `WebSocketClient` - -```swift -public protocol WebSocketClient: AnyObject -``` - -Protocol allowing alternative implementations of websockets beyond `ApolloWebSocket`. - -## Properties -### `request` - -```swift -var request: URLRequest -``` - -The URLRequest used on connection. - -### `delegate` - -```swift -var delegate: WebSocketClientDelegate? -``` - -The delegate that will receive networking event updates for this websocket client. - -- Note: The `WebSocketTransport` will set itself as the delgate for the client. Consumers -should set themselves as the delegate for the `WebSocketTransport` to observe events. - -### `callbackQueue` - -```swift -var callbackQueue: DispatchQueue -``` - -`DispatchQueue` where the websocket client should call all delegate callbacks. - -## Methods -### `connect()` - -```swift -func connect() -``` - -Connects to the websocket server. - -- Note: This should be implemented to connect the websocket on a background thread. - -### `disconnect()` - -```swift -func disconnect() -``` - -Disconnects from the websocket server. - -### `write(ping:completion:)` - -```swift -func write(ping: Data, completion: (() -> Void)?) -``` - -Writes ping data to the websocket. - -### `write(string:)` - -```swift -func write(string: String) -``` - -Writes a string to the websocket. diff --git a/docs/source/api/ApolloWebSocket/protocols/WebSocketClientDelegate.md b/docs/source/api/ApolloWebSocket/protocols/WebSocketClientDelegate.md deleted file mode 100644 index 8a3727ef3f..0000000000 --- a/docs/source/api/ApolloWebSocket/protocols/WebSocketClientDelegate.md +++ /dev/null @@ -1,79 +0,0 @@ -**PROTOCOL** - -# `WebSocketClientDelegate` - -```swift -public protocol WebSocketClientDelegate: AnyObject -``` - -The delegate for a `WebSocketClient` to recieve notification of socket events. - -## Methods -### `websocketDidConnect(socket:)` - -```swift -func websocketDidConnect(socket: WebSocketClient) -``` - -The websocket client has started a connection to the server. -- Parameter socket: The `WebSocketClient` that sent the delegate event. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | - -### `websocketDidDisconnect(socket:error:)` - -```swift -func websocketDidDisconnect(socket: WebSocketClient, error: Error?) -``` - -The websocket client has disconnected from the server. -- Parameters: - - socket: The `WebSocketClient` that sent the delegate event. - - error: An optional error if an error occured. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | -| error | An optional error if an error occured. | - -### `websocketDidReceiveMessage(socket:text:)` - -```swift -func websocketDidReceiveMessage(socket: WebSocketClient, text: String) -``` - -The websocket client received message text from the server -- Parameters: - - socket: The `WebSocketClient` that sent the delegate event. - - text: The text received from the server. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | -| text | The text received from the server. | - -### `websocketDidReceiveData(socket:data:)` - -```swift -func websocketDidReceiveData(socket: WebSocketClient, data: Data) -``` - -The websocket client received data from the server -- Parameters: - - socket: The `WebSocketClient` that sent the delegate event. - - data: The data received from the server. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| socket | The `WebSocketClient` that sent the delegate event. | -| data | The data received from the server. | \ No newline at end of file diff --git a/docs/source/api/ApolloWebSocket/protocols/WebSocketTransportDelegate.md b/docs/source/api/ApolloWebSocket/protocols/WebSocketTransportDelegate.md deleted file mode 100644 index b71f3d9567..0000000000 --- a/docs/source/api/ApolloWebSocket/protocols/WebSocketTransportDelegate.md +++ /dev/null @@ -1,26 +0,0 @@ -**PROTOCOL** - -# `WebSocketTransportDelegate` - -```swift -public protocol WebSocketTransportDelegate: AnyObject -``` - -## Methods -### `webSocketTransportDidConnect(_:)` - -```swift -func webSocketTransportDidConnect(_ webSocketTransport: WebSocketTransport) -``` - -### `webSocketTransportDidReconnect(_:)` - -```swift -func webSocketTransportDidReconnect(_ webSocketTransport: WebSocketTransport) -``` - -### `webSocketTransport(_:didDisconnectWithError:)` - -```swift -func webSocketTransport(_ webSocketTransport: WebSocketTransport, didDisconnectWithError error:Error?) -``` diff --git a/docs/source/api/ApolloWebSocket/structs/ApolloSequencedOperationMessageIdCreator.md b/docs/source/api/ApolloWebSocket/structs/ApolloSequencedOperationMessageIdCreator.md deleted file mode 100644 index e40e510560..0000000000 --- a/docs/source/api/ApolloWebSocket/structs/ApolloSequencedOperationMessageIdCreator.md +++ /dev/null @@ -1,34 +0,0 @@ -**STRUCT** - -# `ApolloSequencedOperationMessageIdCreator` - -```swift -public struct ApolloSequencedOperationMessageIdCreator: OperationMessageIdCreator -``` - -The default implementation of `OperationMessageIdCreator` that uses a sequential numbering scheme. - -## Methods -### `init(startAt:)` - -```swift -public init(startAt sequenceNumber: Int = 1) -``` - -Designated initializer. - -- Parameter startAt: The number from which the sequenced numbering scheme should start. - -#### Parameters - -| Name | Description | -| ---- | ----------- | -| startAt | The number from which the sequenced numbering scheme should start. | - -### `requestId()` - -```swift -public func requestId() -> String -``` - -Returns the number in the current sequence. Will be incremented when calling this method. diff --git a/docs/source/api/ApolloWebSocket/structs/SSLClientCertificateError.md b/docs/source/api/ApolloWebSocket/structs/SSLClientCertificateError.md deleted file mode 100644 index 0b1b6083fb..0000000000 --- a/docs/source/api/ApolloWebSocket/structs/SSLClientCertificateError.md +++ /dev/null @@ -1,14 +0,0 @@ -**STRUCT** - -# `SSLClientCertificateError` - -```swift -public struct SSLClientCertificateError: LocalizedError -``` - -## Properties -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/api/ApolloWebSocket/structs/SSLSettings.md b/docs/source/api/ApolloWebSocket/structs/SSLSettings.md deleted file mode 100644 index d49b2f5999..0000000000 --- a/docs/source/api/ApolloWebSocket/structs/SSLSettings.md +++ /dev/null @@ -1,44 +0,0 @@ -**STRUCT** - -# `SSLSettings` - -```swift -public struct SSLSettings -``` - -## Properties -### `useSSL` - -```swift -public let useSSL: Bool -``` - -### `disableCertValidation` - -```swift -public let disableCertValidation: Bool -``` - -### `overrideTrustHostname` - -```swift -public var overrideTrustHostname: Bool -``` - -### `desiredTrustHostname` - -```swift -public var desiredTrustHostname: String? -``` - -### `sslClientCertificate` - -```swift -public let sslClientCertificate: SSLClientCertificate? -``` - -### `cipherSuites` - -```swift -public let cipherSuites: [SSLCipherSuite]? -``` diff --git a/docs/source/api/ApolloWebSocket/structs/WebSocket.WSError.md b/docs/source/api/ApolloWebSocket/structs/WebSocket.WSError.md deleted file mode 100644 index a1d9a366fb..0000000000 --- a/docs/source/api/ApolloWebSocket/structs/WebSocket.WSError.md +++ /dev/null @@ -1,26 +0,0 @@ -**STRUCT** - -# `WebSocket.WSError` - -```swift -public struct WSError: Swift.Error -``` - -## Properties -### `type` - -```swift -public let type: ErrorType -``` - -### `message` - -```swift -public let message: String -``` - -### `code` - -```swift -public let code: Int -``` diff --git a/docs/source/api/ApolloWebSocket/structs/WebSocketError.md b/docs/source/api/ApolloWebSocket/structs/WebSocketError.md deleted file mode 100644 index b2430509dc..0000000000 --- a/docs/source/api/ApolloWebSocket/structs/WebSocketError.md +++ /dev/null @@ -1,40 +0,0 @@ -**STRUCT** - -# `WebSocketError` - -```swift -public struct WebSocketError: Error, LocalizedError -``` - -A structure for capturing problems and any associated errors from a `WebSocketTransport`. - -## Properties -### `payload` - -```swift -public let payload: JSONObject? -``` - -The payload of the response. - -### `error` - -```swift -public let error: Error? -``` - -The underlying error, or nil if one was not returned - -### `kind` - -```swift -public let kind: ErrorKind -``` - -The kind of problem which occurred. - -### `errorDescription` - -```swift -public var errorDescription: String? -``` diff --git a/docs/source/caching.mdx b/docs/source/caching.mdx deleted file mode 100644 index b2f64c9bac..0000000000 --- a/docs/source/caching.mdx +++ /dev/null @@ -1,228 +0,0 @@ ---- -title: Client-side caching ---- - -import SPMSQLite from "../shared/sqlite-spm-panel.mdx" -import CocoaPodsSQLite from "../shared/sqlite-cocoapods-panel.mdx" -import CarthageSQLite from "../shared/sqlite-carthage-panel.mdx" - -As mentioned in the introduction, Apollo iOS does more than simply run your queries against a GraphQL server. It normalizes query results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run. - -This means your UI is always internally consistent, and can be kept fully up-to-date with the state on the server with the minimum number of queries required. - -## Types of caches - -All caches used by the `ApolloClient` must conform to the [`NormalizedCache` protocol](api/Apollo/protocols/NormalizedCache/). There are two types of cache provided automatically by Apollo: - -- **`InMemoryNormalizedCache`**: This is included with the main `Apollo` library, and is the default caching strategy for the Apollo Client. This stores normalized results in-memory, so results are not persisted across sessions of the application. -- **`SQLiteCache`**: This is included via the [`ApolloSQLite`](api/ApolloSQLite/README/) library. This writes out cache results to a `SQLite` file rather than holding the results in memory. Note that this in turn causes cache hits to go to disk, which may result in somewhat slower responses. However, this also reduces the chances of unbounded memory growth, since everything gets dumped to disk. - -All caches can be cleared in their entirety by calling [`clear(callbackQueue:completion:)`](api/Apollo/protocols/NormalizedCache/#clear). If you need to work more directly with the cache, please see the [Direct Cache Access](#direct-cache-access) section. - -## Cache Setup - -### In-Memory Cache - -For `InMemoryNormalizedCache`, no sub-libraries are needed. - -This type of cache is used by default when setting up an `ApolloClient`. If you want to use an in-memory cache without modifications, all you have to do is instantiate an `ApolloClient` instance and not pass anything into the `store` parameter. - -If for some reason you find you need to instantiate the in-memory cache yourself, you can do so with one line: - -```swift title="Cache Setup" -import Apollo - -let cache = InMemoryNormalizedCache() -``` - -### SQLite Cache - -To use the `SQLiteNormalizedCache`, you need to add the `ApolloSQLite` sub-library to your project using your preferred package manager: - - - - - - - -Once added, you can do the following: - -1. Set up a file URL for your `SQLite` file. -2. Use that file URL to instantiate a SQLite cache. -3. Use that SQLite cache to instantiate an `ApolloStore`. -4. Pass that `ApolloStore` into the initializer of `ApolloClient`: - -```swift title="Client Setup" -import Apollo - -// NOTE: You need this import line if you are **NOT** using CocoaPods. In CocoaPods, -// ApolloSQLite files are collapsed into the Apollo framework. For other dependency managers, -// ApolloSQLite is a separate framework. -import ApolloSQLite - -// 1. You'll have to figure out where to store your SQLite file. -// A reasonable place is the user's Documents directory in your sandbox. -// In any case, create a file URL for your file: -let documentsPath = NSSearchPathForDirectoriesInDomains( - .documentDirectory, - .userDomainMask, - true).first! -let documentsURL = URL(fileURLWithPath: documentsPath) -let sqliteFileURL = documentsURL.appendingPathComponent("test_apollo_db.sqlite") - -// 2. Use that file URL to instantiate the SQLite cache: -let sqliteCache = try SQLiteNormalizedCache(fileURL: sqliteFileURL) - -// 3. And then instantiate an instance of `ApolloStore` with the cache you've just created: -let store = ApolloStore(cache: sqliteCache) - -// 4. Assuming you've set up your `networkTransport` instance elsewhere, -// pass the store you just created into your `ApolloClient` initializer, -// and you're now set up to use the SQLite cache for persistent storage -let apolloClient = ApolloClient(networkTransport: networkTransport, store: store) -``` - -## Controlling normalization - -While Apollo can do basic caching based on the shape of GraphQL queries and their results, Apollo won't be able to associate objects fetched by different queries without additional information about the identities of the objects returned from the server. - -This is referred to as [cache normalization](https://www.apollographql.com/docs/react/caching/cache-configuration/#data-normalization). You can read about our caching model in detail in our blog post, ["GraphQL Concepts Visualized"](https://medium.com/apollo-stack/the-concepts-of-graphql-bc68bd819be3). - -**By default, Apollo does not use object IDs at all**, doing caching based only on the path to the object from the root query. However, if you specify a function to generate IDs from each object, and supply it as `cacheKeyForObject` to an `ApolloClient` instance, you can decide how Apollo will identify and de-duplicate the objects returned from the server: - -```swift -apollo.cacheKeyForObject = { $0["id"] } -``` - -> **NOTE:** In some cases, just using `cacheKeyForObject` is not enough for your application UI to update correctly. For example, if you want to add something to a list of objects without refetching the entire list, or if there are some objects that to which you can't assign an object identifier, Apollo cannot automatically update existing queries for you. -> - -## Cache normalization concepts - -There are 2 primary ways you will want to manually update the cache. Either you'll want to update the cache for a query, or you will want to update a cached object directly. - -Manual Scenario A - -1. You use the id of the object (after setting up the afore mentioned `apollo.cacheKeyForObject = { $0["id"] }`) to fetch and change the object. This will update any query where this object is referenced. This works well for updating queries which reference this object, but in the case of a create mutation, your queries won't contain this object to update. Which leads us into Scenario B. - -Manual Scenario B - -1. You fire off a mutation which creates a new object. -2. You may then want to update the cache for a List that should contain this new object. This is a bit fiddly at the moment, as `Droid` for `CreateDroidsMutation` is strongly typed: `CreateDroidsMutation.Droid`. When inserting this object into the cache for `ListDroidsQuery` you need to init a `ListDroidsQuery.Droid` object from a `CreateDroidsMutation.Droid` or the types won't match. Your alternative to this is to manually refetch queries on a mutation which will trigger any watchers to update. - -Where you may not need to manually update the cache: - -If you use fragments which contain ID's then a query which returns or mutates this fragment and returns a new state for this object will automatically be merged into your cache and any query which references that object will be updated. It may therefore be advantageous to plan your schemas so Fragments are reused in List / Detail queries and then the same Fragment is returned as the result of a mutation. - -## Specifying a cache policy - -`ApolloClient`'s `fetch(query:)` method takes an optional `cachePolicy` that allows you to specify when results should be fetched from the server, and when data should be loaded from the local cache. - -The default cache policy is `.returnCacheDataElseFetch`, which means data will be loaded from the cache when available, and fetched from the server otherwise. - -Other cache polices which you can specify are: - -- **`.fetchIgnoringCacheData`** to always fetch from the server, but still store results to the cache. -- **`.fetchIgnoringCacheCompletely`** to always fetch from the server and not store results from the cache. If you're not using the cache at all, this method is preferred to `fetchIgnoringCacheData` for performance reasons. -- **`.returnCacheDataDontFetch`** to return data from the cache and never fetch from the server. This policy will return an error if cached data is not available. -- **`.returnCacheDataAndFetch`** to return cached data immediately, *then* perform a fetch to see if there are any updates. This is mostly useful if you're watching queries, since those will be updated when the call to the server returns. - -If you're interested in returning cached data after a failed fetch, the current recommended approach is to use an `additionalErrorInterceptor` on your interceptor chain to examine if the error is one it makes sense to show old data for rather than something that needs to be passed on to the user, and then retrying with a `returnCacheDataDontFetch` retry policy. An example of this setup can be found in the [Cache-dependent interceptor tests](https://github.com/apollographql/apollo-ios/blob/main/Tests/ApolloTests/Cache/CacheDependentInterceptorTests.swift). - -## Watching queries - -Watching a query is very similar to fetching a query. The main difference is that you don't just receive an initial result, but your result handler will be invoked whenever relevant data in the cache changes: - -```swift -let watcher = apollo.watch(query: HeroNameQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - print(data.hero?.name) // Luke Skywalker -} -``` - -> **NOTE:** Remember to call `cancel()` on a watcher when its parent object is deallocated, or you will get a memory leak! This is not (presently) done automatically. - -## Direct cache access - -Similarly to the [Apollo React API](https://www.apollographql.com/docs/react/advanced/caching/#direct), you can directly read and update the cache as needed using Swift's [inout parameters](https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID173). - -This functionality is useful when performing mutations or receiving subscription data, as you should always update the local cache to ensure consistency with the operation that was just performed. The ability to write to the cache directly also prevents you from needing to re-fetch data over the network after a mutation is performed. - -### read - -The `read` function is similar to React Apollo's [`readQuery`](https://www.apollographql.com/docs/react/caching/cache-interaction/#readquery) and React Apollo's [`readFragment`](https://www.apollographql.com/docs/react/caching/cache-interaction/#readfragment) methods and will return the cached data for a given GraphQL query or a GraphQL fragment: - -```swift -// Assuming we have defined an ApolloClient instance `client`: -// Read from a GraphQL query -client.store.withinReadTransaction({ transaction in - let data = try transaction.read( - query: HeroNameQuery(episode: .jedi) - ) - - // Prints "R2-D2" - print(data.hero?.name) -}) - -// Read from a GraphQL fragment -client.store.withinReadTransaction({ transaction -> HeroDetails in - let data = try transaction.readObject( - ofType: HeroDetails.self, - withKey: id - ) - - // Prints "R2-D2" - print(data.hero?.name) -}) -``` - -### update - -The `update` function is similar to React Apollo's [`writeQuery`](https://www.apollographql.com/docs/react/advanced/caching/#writequery-and-writefragment) method and will update the Apollo cache and propagate changes to all listeners (queries using the `watch` method): - -```swift -// Assuming we have defined an ApolloClient instance `client`: -store.withinReadWriteTransaction({ transaction in - let query = HeroNameQuery(episode: .jedi) - - try transaction.update(query: query) { (data: inout HeroNameQuery.Data) in - data.hero?.name = "Artoo" - - let graphQLResult = try? store.load(query: query).result?.get() - - // Prints "Artoo" - print(graphQLResult?.data?.hero?.name) - } -}) -``` - -### delete - -Delete functionality is limited at this time. There are presently three deletion methods available on `ApolloStore`, which are supported by both the in memory and the `SQLite` caches: - -1. `clear` - Removes everything from the cache immediately. This is basically the "Nuke it from orbit, it's the only way to be sure" option. -2. `removeObject(for:)` on `ReadWriteTransaction`. Removes a single object for the given `CacheKey`. -3. `removeObjects(matching:)` on `ReadWriteTransaction`. Removes all objects with a `CacheKey` that matches the given pattern. Pattern matching is **not** case sensitive. For an in memory cache it is the equivalent of checking whether the cache key _contains_ the pattern and `SQLite` caches will perform a `LIKE` query to remove the objects. This method can be very slow depending on the number of records in the cache, it is recommended that this method be called in a background queue. - -`removeObject(for:)` and `removeObjects(matching:)` will only remove things at the level of an object - that is, they cannot remove individual properties from an object, and cannot remove outside references **to** an object. - -You will need to have an understanding of how you are generating cache keys to be able to use these methods effectively. If you're taking advantage of our `cacheKeyForObject` function, that will help significantly: You'll have a clear understanding of how cache keys are generated, so you can easily figure out how to construct a cache key or pattern to delete. - -For instance, let's say your `cacheKeyForObject` function looks like this: - -```swift -apollo.cacheKeyForObject = { $0["id"] } -``` - -This would indicate that for every object which has an `id` property, it will be cached with that `id` as the key. This would be ideal for an API which uses globally unique identifiers, as our Star Wars API does. - -This means that if you have previously fetched an object with the ID `"2001"`, you can: - -1. Call `transaction.removeObject(for: "2001")` on a `ReadWriteTransaction` to remove any object cached with that key, along with all of its associated scalar properties and the references to other objects it stores. -2. Call `transaction.removeObjects(matching: "200")` on a `ReadWriteTransaction` and all objects with `200` somewhere in their cache key would be removed, such as `2001`, `2002`, and `3200`. - -`removeObject(for:)` and `removeObjects(matching:)` do _not_ cascade removals - if you remove an object which has reference to another object, the reference will be removed, but that other object will not be removed and will remain in the cache. Likewise, if you delete an object, references _to_ that object will not be deleted, they will simply fail, causing a cache miss, when you attempt to load the object again. - -This means that if you are planning to remove something, be sure that you either a) Know for sure you no longer need it, or b) Are fine with your cache policy potentially triggering an additional fetch if the missing value causes a read to fail. - -> Note: As of right now, there is not a way to delete a single property's value. For instance, calling `try transaction.removeRecord(for: "2001.name")` will result in no action, as there would not be a record with the cache key `"2001.name"`, since `name` is a scalar field on the `"2001"` record. diff --git a/docs/source/config.json b/docs/source/config.json deleted file mode 100644 index ff6f69e89e..0000000000 --- a/docs/source/config.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "title": "Client (iOS)", - "version": "0.X", - "algoliaFilters": [ - "docset:ios" - ], - "sidebar": { - "Introduction": "/", - "Installation": "/installation", - "API Reference": "/api-reference", - "Tutorial": { - "0. Introduction": "/tutorial/tutorial-introduction", - "1. Add the Apollo SDK": "/tutorial/tutorial-add-sdk", - "2. Obtain your GraphQL schema": "/tutorial/tutorial-obtain-schema", - "3. Execute your first query": "/tutorial/tutorial-execute-query", - "4. Connect your queries to your UI": "/tutorial/tutorial-query-ui", - "5. Paginate results": "/tutorial/tutorial-pagination", - "6. Complete the detail view": "/tutorial/tutorial-detail-view", - "7. Enable authentication": "/tutorial/tutorial-authentication", - "8. Define additional mutations": "/tutorial/tutorial-mutations", - "9. Write your first subscription": "/tutorial/tutorial-subscriptions" - }, - "Usage": { - "Downloading a schema": "/downloading-schema", - "Creating a client": "/initialization", - "Fetching queries": "/fetching-queries", - "Performing mutations": "/mutations", - "Using fragments": "/fragments", - "Client-side caching": "/caching", - "Subscriptions": "/subscriptions", - "Swift scripting": "/swift-scripting", - "Request pipeline (advanced)": "/request-pipeline" - } - } -} \ No newline at end of file diff --git a/docs/source/downloading-schema.md b/docs/source/downloading-schema.md deleted file mode 100644 index 54b8aacc43..0000000000 --- a/docs/source/downloading-schema.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Downloading a schema ---- - -Apollo iOS requires a GraphQL schema file as input to its code generation process. You can provide your schema either as a JSON file (most commonly the result of an introspection query) or as a `.graphqls` file that uses GraphQL SDL syntax. Conventionally, this file is named `schema.json` or `schema.graphqls` (depending on its format), and you store it in the same folder as your project's `App`: - -Location of schema file in project - -> 📣 **Check it out:** Instead of writing the scripts below in Bash, try using our new [Swift Scripting Library](./swift-scripting), now in Beta! It supports downloading a schema and generating code. - -You can use the [Apollo CLI](https://www.apollographql.com/docs/devtools/cli/) to download a GraphQL schema by sending an introspection query to the server. If you've installed the CLI globally, you can use the following command to download your schema: - -```sh -apollo schema:download --endpoint=http://localhost:8080/graphql schema.json -``` - -Note that if you're using the local version set up for codegen, you should use the same method you're using in the [Add a code generation build step](./installation/#5-add-a-code-generation-build-step) instructions to access that specific CLI. For example, if you're using CocoaPods, you can set it up like this to download your schema: - -```bash -SCRIPT_PATH="${PODS_ROOT}/Apollo/scripts" -cd "${SRCROOT}/${TARGET_NAME}" -"${SCRIPT_PATH}"/run-bundled-codegen.sh schema:download --endpoint=http://localhost:8080/graphql schema.json -``` - -If needed, you can use the `header` option to add additional HTTP headers to the request. For example, to include an authentication token, use `--header "Authorization: Bearer "`: - -```sh -[your apollo version] schema:download --endpoint=http://localhost:8080/graphql --header="Authorization: Bearer " -``` diff --git a/docs/source/fetching-queries.md b/docs/source/fetching-queries.md deleted file mode 100644 index 41cf8fd25b..0000000000 --- a/docs/source/fetching-queries.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -title: Fetching queries ---- - -> **Note:** This page is about using Apollo iOS to fetch and access GraphQL query results. You can read about GraphQL queries themselves in detail at [graphql.org](http://graphql.org/docs/queries/). - -When using Apollo iOS, you don't have to learn anything special about the query syntax, since everything is just standard GraphQL. Anything you can type into the GraphiQL query explorer, you can also put into `.graphql` files in your project. - -Apollo iOS takes a schema and a set of `.graphql` files and uses these to generate code you can use to execute queries and access typed results. - -All `.graphql` files in your project (or the subset you specify as input to `apollo` if you customize the script you define as the code generation build phase) will be combined and treated as one big GraphQL document. - -That means fragments defined in one `.graphql` file are available to all other `.graphql` files for example, but it also means operation names and fragment names **must** be unique and you will receive validation errors if they are not. - -## Creating queries - -Queries are represented as instances of generated classes conforming to the `GraphQLQuery` protocol. Constructor arguments can be used to define query variables if needed. You pass a query object to `ApolloClient#fetch(query:)` to send the query to the server, execute it, and receive typed results. - -For example, if you define a query called `HeroName`: - -```graphql -query HeroName($episode: Episode) { - hero(episode: $episode) { - name - } -} -``` - -Apollo iOS will generate a `HeroNameQuery` class that you can construct (with variables) and pass to `ApolloClient#fetch(query:)`: - -```swift -apollo.fetch(query: HeroNameQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - print(data.hero?.name) // Luke Skywalker -} -``` - -By default, Apollo will deliver query results **on the main thread**, which is probably what you want if you're using them to update the UI. `fetch(query:)` takes an optional `queue:` parameter however, if you want your result handler to be called on a background queue. - -To handle potential errors, check the `failure(Error)` result case, which details network or response format errors (such as invalid JSON): - -```swift -apollo.fetch(query: HeroNameQuery(episode: .empire)) { result in - switch result { - case .success(let graphQLResult): - if let name = graphQLResult.data?.hero?.name { - print(name) // Luke Skywalker - } else if let errors = graphQLResult.errors { - // GraphQL errors - print(errors) - } - case .failure(let error): - // Network or response format errors - print(error) - } -} -``` - -In addition to an optional `data` property, `success(Success)` result case contains an optional `errors` array with GraphQL errors (for more on this, see the sections on [response format errors](https://graphql.github.io/graphql-spec/June2018/#sec-Errors) in the GraphQL specification). - -## Typed query results - -Query results are defined as nested immutable structs that at each level only contain the properties defined in the corresponding part of the query definition. This means the type system won't allow you to access fields that are not actually fetched by the query, even if they *are* part of the schema. - -For example, given the following schema: - -```graphql -enum Episode { NEWHOPE, EMPIRE, JEDI } - -interface Character { - id: String! - name: String! - friends: [Character] - appearsIn: [Episode]! - } - - type Human implements Character { - id: String! - name: String! - friends: [Character] - appearsIn: [Episode]! - height(unit: LengthUnit = METER): Float - } - - type Droid implements Character { - id: String! - name: String! - friends: [Character] - appearsIn: [Episode]! - primaryFunction: String -} -``` - -And the following query: - -```graphql -query HeroAndFriendsNames($episode: Episode) { - hero(episode: $episode) { - name - friends { - name - } - } -} -``` - -You can fetch results and access data using the following code: - -```swift -apollo.fetch(query: HeroAndFriendsNamesQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - print(data.hero?.name) // Luke Skywalker - print(data.hero?.friends?.flatMap { $0?.name }.joined(separator: ", ")) - // Prints: Han Solo, Leia Organa, C-3PO, R2-D2 -} -``` - -Because the above query won't fetch `appearsIn`, this property is not part of the returned result type and cannot be accessed here. - -### Notes on working with Custom Scalars - -Custom scalars are types defined by your schema that are based on other GraphQL scalar types (such as `String` or `Int`). Without intervention, code generation will use the underlying types to generate code for the custom scalars. - -If you want to use the custom scalars within your code, you must set `passthroughCustomScalars` to true either at the command line or using Swift Scripting. - -Once you've done that, you can either create your own type locally or use a `typealias` to declare an equivilent. This is very, very frequently used with `Date` types. Please see the [Custom Scalar Playground Page](https://github.com/apollographql/apollo-client-swift-playground/blob/main/Apollo.playground/Pages/CustomScalars.xcplaygroundpage/Contents.swift) for a full example using a custom date type. - -#### JSON and other Custom Scalars with multiple return types - -Some custom scalars are set up to potentially return multiple types at runtime. This is not ideal since you lose type safety, but if you're using an API you don't have control over, there's often not a great alternative to this. - -When this happens, because you don't know the type that's coming in, you can't set up a single `typealias` for that scalar. Instead, you need to define some other way of instantiating your custom scalar object. - -This happens most often with JSON, which can return either an array or a dictionary. Here's an example of how you can use an enum to allow dynamic-but-limited types to parse (with `CustomJSON` as a placeholder type name`): - -```swift -enum CustomJSON { - case dictionary([String: Any]) - case array([Any]) -} - -extension CustomJSON: JSONDecodable { - init(jsonValue value: JSONValue) throws { - if let dict = value as? [String: Any] { - self = .dictionary(dict) - } else if let array = value as? [Any] { - self = .array(array) - } else { - throw JSONDecodingError.couldNotConvert(value: value, to: CustomJSON.self) - } - } -} -``` - -Again, make sure to define this in a file that is outside of your generated code, or it will get overwritten. - -## Specifying a cache policy - -[This section has moved to the Caching documentation](./caching/). - -## Using `GET` instead of `POST` for queries - -By default, Apollo constructs queries and sends them to your graphql endpoint using `POST` with the JSON generated. - -If you want Apollo to use `GET` instead, pass `true` to the optional `useGETForQueries` parameter when setting up your `RequestChainNetworkTransport`. This will set up all queries conforming to `GraphQLQuery` sent through the HTTP transport to use `GET`. - ->**NOTE:** This is a toggle which affects all queries sent through that client, so if you need to have certain queries go as `POST` and certain ones go as `GET`, you will likely have to swap out the `RequestChainNetworkTransport`. - -## JSON serialization - -The classes generated by Apollo iOS can be converted to JSON using their `jsonObject` property. This may be useful for conveniently serializing GraphQL instances for storage in a database, or a file. - -For example: - -```swift -apollo.fetch(query: HeroAndFriendsNamesQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - - // Serialize the response as JSON - let json = data.jsonObject - let serialized = try! JSONSerialization.data(withJSONObject: json, options: []) - - // Deserialize the response - let deserialized = try! JSONSerialization.jsonObject(with: serialized, options: []) as! JSONObject - let heroAndFriendsNames = try! HeroAndFriendsNamesQuery.Data(jsonObject: deserialized) -} -``` - -## Automatic Persisted Queries - -Apollo Server allows you to use a feature called [Automatic Persisted Queries](https://www.apollographql.com/docs/apollo-server/performance/apq/), or APQs, to needing to resend large query documents over and over. - -Each query or mutation is identified by the SHA256 hash of its contents. If the hash can't be found by the server, it sends back an error indicating that it needs the full query. If it receives this specific error, the iOS SDK will automatically retry the operation with the full query document without you having to do anything. - -To use APQs with the iOS SDK: - -- When generating your code, pass a local path for output for the `--operationIdsPath` (or pass a file URL to the `operationIDsURL` on `ApolloCodegenOptions` if using Swift Scripting). - - This will generate a document with all your operations, but more importantly it will cause operation identifiers to be generated with your code. -- When creating your `ApolloClient`, make sure to manually instantiate your `RequestChainNetworkTransport` and set `autoPersistQueries`. - - This will cause the `RequestChainNetworkTransport` to actively look for the "Oh no, I don't have this hash!" error from the server. - -By default, retries of queries will use `POST`. If for some reason (for example, your queries are hitting a CDN that has considerably better performance with `GET`), you need to use a `GET` for the 2nd try of a query, make sure to set the `useGETForPersistedQueryRetry` option to `true`. Most users will want to leave this option as `false`. - -> NOTE: APQs are not supported over Websockets at this time. If you're interested in this feature, please open a PR! diff --git a/docs/source/fragments.md b/docs/source/fragments.md deleted file mode 100644 index 8ea63e777f..0000000000 --- a/docs/source/fragments.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Using fragments ---- - -In GraphQL, [fragments](http://graphql.org/learn/queries/#fragments) define pieces of data you may want to reuse in multiple places: - -```graphql -query HeroAndFriends($episode: Episode) { - hero(episode: $episode) { - name - ...HeroDetails - friends { - ...HeroDetails - } - } -} - -fragment HeroDetails on Character { - name - appearsIn -} -``` - -Apollo iOS generates separate result types for fragments, which means they are a great way of keeping UI components or utility functions independent of specific queries. - -One common pattern is to define a fragment for a child view (like a `UITableViewCell`), and include the fragment in a query defined at a parent level (like a `UITableViewController`). This way, the child view can easily be reused and only depends on the specific data it needs: - -```swift -func configure(with heroDetails: HeroDetails?) { - textLabel?.text = heroDetails?.name -} -``` - -This also works the other way around. The parent view controller only has to know the fragment name, but doesn't need to know anything about the fields it specifies. You can make changes to the fragment definition without affecting the parent. - -In fact, this is the main reason fields included through fragments are not exposed directly, but require you to access the data through the fragment explicitly: - -```swift -apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - print(data.hero?.name) // Luke Skywalker - print(data.hero?.appearsIn) // WON'T WORK - print(data.hero?.fragments.heroDetails.appearsIn) // [.newhope, .empire, .jedi] - print(data.hero?.friends?.flatMap { $0?.fragments.heroDetails.name }.joined(separator: ", ")) // Han Solo, Leia Organa, C-3PO, R2-D2 -} -``` - -In most cases, you'll simply pass the whole fragment to a child view without needing to know anything about the data it specifies: - -```swift -cell.configure(with: hero?.fragments.heroDetails) -``` - -## Type conditions - -The GraphQL type system includes interfaces and unions as abstract types that object types can conform to. In the Star Wars example schema for example, both `Human`s and `Droid`s implement the `Character` interface. If we query for a hero, the result can be either a human or a droid, and if we want to access any type-specific properties we will have to use a fragment with a type condition: - -```graphql -query HeroAndFriends($episode: Episode) { - hero(episode: $episode) { - name - ...DroidDetails - } -} - -fragment DroidDetails on Droid { - name - primaryFunction -} -``` - -You can access named fragments with type conditions the same way you access other fragments, but their type will be optional to reflect the fact that their fields will only be available if the object type matches: - -```swift -apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - data.hero?.fragments.droidDetails?.primaryFunction -} -``` - -Alternatively, you can use [inline fragments](http://graphql.org/learn/queries/#inline-fragments) with type conditions to query for type-specific fields: - -```graphql -query HeroAndFriends($episode: Episode) { - hero(episode: $episode) { - name - ... on Droid { - primaryFunction - } - } -} -``` - -And results from inline fragments with type conditions will be made available through specially generated `as` properties: - -```swift -apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - data.hero?.asDroid?.primaryFunction -} -``` - -You can also use inline fragments inside named fragments: - -```graphql -query HeroAndFriends($episode: Episode) { - hero(episode: $episode) { - name - ...HeroDetails - friends { - ...HeroDetails - } - } -} - -fragment HeroDetails on Character { - name - ... on Droid { - primaryFunction - } -} -``` - -```swift -apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in - guard let data = try? result.get().data else { return } - data.hero?.fragments.heroDetails.asDroid?.primaryFunction -} -``` - -Apollo iOS automatically augments your queries to add a `__typename` field to selection sets. This is used primarily to support conditional fragments, but it means a `__typename` property is always defined and can be used to differentiate between object types manually if needed. diff --git a/docs/source/index.mdx b/docs/source/index.mdx deleted file mode 100644 index d8b70e768b..0000000000 --- a/docs/source/index.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Introduction to Apollo iOS -sidebar_title: Introduction -description: A strongly-typed, caching GraphQL client for iOS, written in Swift ---- - -**Apollo iOS** is an [open-source](https://github.com/apollographql/apollo-ios) GraphQL client for native iOS apps, written in Swift. It enables you to execute queries and mutations against a GraphQL server and returns results as operation-specific Swift types. - -

- - Start the tutorial - - - Installation - -

- -## Benefits - -### Strong typing with codegen - -Thanks to strong typing in Apollo iOS, you don't need to deal with parsing JSON responses or passing around dictionaries of values that require manual casting. You also don't need to write model types yourself, because models are generated from the GraphQL operations your UI defines. - -Because generated types are operation-specific, they include properties _only_ for the GraphQL fields included in their corresponding operation. This means you can rely on the Swift type checker to flag data access errors at compile time. - -Apollo's Xcode integration enables you to work with your UI code and corresponding GraphQL definitions side by side. It even validates your query documents, showing errors inline. - -### Normalized caching - -Apollo iOS normalizes operation results to build a client-side cache of your data, which is updated with every operation you execute. This means your UI is always internally consistent, and it can stay up to date with your backend with as few operation as possible. - -[Learn more about caching.](./caching/) - -## Related libraries - -[Apollo Kotlin](/kotlin/) is a GraphQL client for native Android apps written in Java and Kotlin. It offers Kotlin Multi-Platform integration as well. - -Apollo Client for JavaScript's [React integration](/react) works with [React Native](https://facebook.github.io/react-native/) on both iOS and Android. diff --git a/docs/source/initialization.mdx b/docs/source/initialization.mdx deleted file mode 100644 index 8dc997e9e8..0000000000 --- a/docs/source/initialization.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Creating a client ---- - -Before you can execute GraphQL operations in your app, you need to initialize an `ApolloClient` instance. - -## Basic client creation - -In most cases, you can create a single shared instance of `ApolloClient` and point it at your GraphQL server. The recommended way to do this is to create a singleton like so: - -```swift -import Foundation -import Apollo - -class Network { - static let shared = Network() - - private(set) lazy var apollo = ApolloClient(url: URL(string: "http://localhost:4000/graphql")!) -} -``` - -Under the hood, this creates a client using the default network transport (`RequestChainNetworkTransport`) and default configuration. You can then use this client from anywhere in your code with `Network.shared.apollo`. - -> You should use this initializer unless you need to customize your client's network communication, such as to enable subscription operations. - -## Advanced client creation - -For advanced use cases, you can use a different `ApolloClient` initializer that enables you to customize your client's network transport: - -```swift -public init(networkTransport: NetworkTransport, - store: ApolloStore) -``` - -Apollo iOS provides the following classes that conform to the [`NetworkTransport` protocol](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/NetworkTransport.swift): - -| Class | Description | -|-------|-------------| -| `RequestChainNetworkTransport` | Passes a request through a chain of interceptors that can interact with the request both before and after it's transmitted. Uses standard HTTP requests to communicate with the server. | -| `WebSocketTransport` | Transmits _all_ GraphQL operations via WebSocket. Requires the `Apollo/WebSocket` sub-spec. | -| `SplitNetworkTransport` | Transmits subscription operations via WebSocket and other operations via HTTP. Requires the `Apollo/WebSocket` sub-spec. | - -> * For more information on `RequestChainNetworkTransport`, see [Request pipeline in Apollo iOS](./request-pipeline/). -> * For more information on `WebSocketTransport` and `SplitNetworkTransport`, see [Subscriptions](./subscriptions/). diff --git a/docs/source/installation.mdx b/docs/source/installation.mdx deleted file mode 100644 index 9f4f3d9532..0000000000 --- a/docs/source/installation.mdx +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: Installing Apollo iOS -sidebar_title: Installation ---- - -import SPMInstallationPanel from "../shared/spm-installation-panel.mdx" -import SPMRunScriptPanel from "../shared/spm-run-script-panel.mdx" -import PodsInstallationPanel from "../shared/pods-installation-panel.mdx" -import PodsRunScriptPanel from "../shared/pods-run-script-panel.mdx" -import CarthageInstallationPanel from "../shared/carthage-installation-panel.mdx" -import CarthageRunScriptPanel from "../shared/carthage-run-script-panel.mdx" - -Follow the steps below to add Apollo iOS to your app: - -## 1. Update Xcode - -Before installing Apollo iOS, make sure you're using the latest version of Xcode. You can update Xcode via the [Mac App Store](http://appstore.com/mac/apple/xcode). - -## 2. Install the Apollo framework - -You can install `Apollo.framework` into your project using any of the three major Cocoa ecosystem package managers: Swift Package Manager, CocoaPods, or Carthage. - -
- - - - - - - - -## 3. Add a schema file to your target directory - -For Apollo iOS to generate models for your GraphQL operations, you need a local copy of your GraphQL server's schema. To acquire this schema, see [Downloading a schema](./downloading-schema/). - -Make sure to add your `schema.json`/`schema.graphqls` file to the folder where most of your code is, _not_ to the folder where your `.xcodeproj` and/or `.xcworkspace` files are located. - -Here's an example file structure: - -```{4} -| - your_project_folder - | your_project.xcodeproj - | - your_target_folder - | schema.json or schema.graphqls - | AppDelegate.swift - | ViewController.swift - | etc... - | - another_target_folder - | etc... -``` - -> **Note:** You _can_ put the schema file in a different location, but if you do, you need to modify all relative paths to the file shown in future steps. - -## 3. Install the Xcode add-ons for syntax highlighting (optional) - -Check out the [`xcode-apollo`](https://github.com/apollographql/xcode-graphql) repository and follow its [installation guide](https://github.com/apollographql/xcode-graphql#installation). - -## 4. Create `.graphql` files for your GraphQL operations - -Apollo iOS generates code from GraphQL queries and mutations defined in `.graphql` files in your target. As a useful convention, you can define each `[operation].graphql` file alongside whichever `[operation].swift` file uses the corresponding operation. - -If you have the Xcode add-ons installed, you can use the Xcode companion view to show a `.swift` file and its corresponding `.graphql` file side by side. - -> **Note:** If you don't have _any_ `.graphql` files in your build tree yet, create one that contains a basic valid operation. If you don't, the code generation build step generates the error `No operations or fragments found to generate code for`. - -## 5. Add a code generation build step - -Apollo iOS code generation uses your `.graphql` files to generate API code that helps you execute all forms of GraphQL operations, as well as parse and cache operation responses. To run code generation as part of the Xcode build process, you need to create a build step that runs before "Compile Sources" to invoke a wrapper script. - -The wrapper script calls through to the included binaries and files that constitute the `apollo` command-line interface. This helps ensure that you can use our tooling without having to worry about mismatched versioning between libraries. - -> 📣 **Check it out:** Instead of writing the rest of this in Bash, try using our new [Swift Scripting Library](./swift-scripting), now in Beta! It supports downloading a schema and generating code. - -The location of this wrapper script depends on how you've integrated Apollo into your project, but these first steps are always the same: - -1. On your application target's **Build Phases** settings tab, click the **+** icon and choose **New Run Script Phase**. -2. In the created Run Script, change its name to **Generate Apollo GraphQL API**. -3. Drag this new run script just above **Compile Sources** in your list of **Build Phases** so that it executes _before_ your code is compiled. -4. Add the contents of the appropriate run script for the package manager you're using: - - - - - - - - - - -## 6. Build your target - -At this point, you can try building your target in Xcode. This verifies that the code generation build step can correctly locate your schema file. - -### Troubleshooting - -If you get this error: - -> `Cannot find GraphQL schema file [...]` - -The script can't locate your schema file. Double check the path you've used. - -If you get this error: - -> `No operations or fragments found to generate code for.` - -You haven't defined at least one `.graphql` file with a valid operation in your build tree. - -If you need to validate the structure of a GraphQL operation, you can test it against your GraphQL server using [Apollo Sandbox](https://studio.apollographql.com/sandbox). - -## 7. Add the generated API file to your target - -Drag the generated `API.swift` file to your target. - -> **Note:** Because Apollo iOS generates operation-specific result types, `API.swift` is mostly empty at this point unless you've already added multiple `.graphql` files to your target directory. - -Make sure to uncheck the "Copy Files If Needed" checkbox, because it should already be in your project's folder system. Then, make sure you've checked all the Targets the API file needs to be included in. - -**Installation complete!** You can now start executing GraphQL operations in your app. To learn how, next check out [Creating a client](./initialization/) and [Fetching queries](./fetching-queries/). - -You can also continue reading below for some [advanced codegen tips](#advanced-codegen-tips-and-tricks). - -## Advanced codegen tips and tricks - -After you get up and running, here are a few improvements you can make to your codegen process. - -### Prevent unnecessary recompilation - -#### Set up input and output files in your build phase - -If you're using a tool like Interface Builder or SwiftUI to talk to a module with its own code generation build step, this is helpful to prevent the `API.swift` file from causing an auto-regeneration loop. - -For example, if you're using something like this to run your code generation for a target called `YourTarget`: - -``` -"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" API.swift -``` - -Assuming you've set the script to run from `$(SRCROOT)/YourTarget`, you can add `$(SRCROOT)/YourTarget/**/*.graphql` (the path you're running it from + the glob you're passing to the `includes` CLI parameter) to the list of `Input Files` for your Apollo Run Script Build phase. Then, you can add `$(SRCROOT)/YourTarget/API.swift` (the path you're running it from + the output file) to the list of `Output Files`: - -Setting input and output files - -This should prevent automatic rebuild cycles if none of the `InputFiles` are changed. The script *will* still run if you explicitly build and run. - -There's an [open issue to auto-generate input and output file lists](https://github.com/apollographql/apollo-ios/issues/636) which will be addressed as part of Apollo iOS 1.0, but this will help until that's done. - -#### Write to a temporary file - -If for some reason the input/output file setup above doesn't work for you, you can also decide to first write the file to a temporary location, and then compare this temporary file to the current one. Then, only when the files differ you move the temporary file into place. - -For a target called `YourTarget`, the script could look something like this: - -```bash -"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" "${SRCROOT}/YourTarget/API.swift.new" -if ! diff -q "${SRCROOT}/YourTarget/API.swift.new" "${SRCROOT}/YourTarget/API.swift"; then - mv "${SRCROOT}/YourTarget/API.swift.new" "${SRCROOT}/YourTarget/API.swift" -else - rm "${SRCROOT}/YourTarget/API.swift.new" -fi -``` - -### Generate multiple files in a folder instead of one large file - -Instead of passing a single `API.swift` file, you can pass a (pre-existing) relative folder path such as `API` as the final parameter. This causes the codegen to create individual files and place them in that folder. - -With small sets of `graphql` files this is usually unnecessary, but with large sets that can cause `API.swift` to be huge. Dividing it up like this can help significantly reduce compilation time. diff --git a/docs/source/logo/favicon.png b/docs/source/logo/favicon.png deleted file mode 100644 index 74b56fa621..0000000000 Binary files a/docs/source/logo/favicon.png and /dev/null differ diff --git a/docs/source/logo/icon-apollo-white-200x200.png b/docs/source/logo/icon-apollo-white-200x200.png deleted file mode 100644 index a1b4b5703c..0000000000 Binary files a/docs/source/logo/icon-apollo-white-200x200.png and /dev/null differ diff --git a/docs/source/logo/logo-apollo-space-left.svg b/docs/source/logo/logo-apollo-space-left.svg deleted file mode 100644 index bd0ad9f93c..0000000000 --- a/docs/source/logo/logo-apollo-space-left.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/source/logo/logo-apollo-space.svg b/docs/source/logo/logo-apollo-space.svg deleted file mode 100644 index a168fc113a..0000000000 --- a/docs/source/logo/logo-apollo-space.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/source/logo/logo-apollo-subbrands-developers-space.svg b/docs/source/logo/logo-apollo-subbrands-developers-space.svg deleted file mode 100644 index b1bbe7f0f2..0000000000 --- a/docs/source/logo/logo-apollo-subbrands-developers-space.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/docs/source/mutations.md b/docs/source/mutations.md deleted file mode 100644 index 5d25f523e6..0000000000 --- a/docs/source/mutations.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Performing mutations ---- - -In addition to fetching data using queries, Apollo iOS also handles GraphQL mutations. Mutations are identical to queries in syntax, the only difference being that you use the keyword `mutation` instead of `query` to indicate that the root fields on this query are going to be performing writes to the backend. - -```graphql -mutation UpvotePost($postId: Int!) { - upvotePost(postId: $postId) { - votes - } -} - -``` - -GraphQL mutations represent two things in one query string: - -1. The mutation field name with arguments, `upvotePost`, which represents the actual operation to be done on the server -2. The fields you want back from the result of the mutation to update the client: `{ votes }` - -The above mutation will upvote a post on the server. The result might be: - -``` -{ - "data": { - "upvotePost": { - "id": "123", - "votes": 5 - } - } -} -``` - -Similar to queries, mutations are represented by instances of generated classes, conforming to the `GraphQLMutation` protocol. Constructor arguments are used to define mutation variables. You pass a mutation object to `ApolloClient#perform(mutation:)` to send the mutation to the server, execute it, and receive typed results: - -```swift -apollo.perform(mutation: UpvotePostMutation(postId: postId)) { result in - guard let data = try? result.get().data else { return } - print(data.upvotePost?.votes) -} -``` - -## Using fragments in mutation results - -In many cases, you'll want to use mutation results to update your UI. Fragments can be a great way of sharing result handling between queries and mutations: - -```graphql -mutation UpvotePost($postId: Int!) { - upvotePost(postId: $postId) { - ...PostDetails - } -} -``` - -```swift -apollo.perform(mutation: UpvotePostMutation(postId: postId)) { result in - guard let data = try? result.get().data else { return } - self.configure(with: data.upvotePost?.fragments.postDetails) -} -``` - -## Passing input objects - -The GraphQL type system includes [input objects](http://graphql.org/learn/schema/#input-types) as a way to pass complex values to fields. Input objects are often defined as mutation variables, because they give you a compact way to pass in objects to be created: - -```graphql -mutation CreateReviewForEpisode($episode: Episode!, $review: ReviewInput!) { - createReview(episode: $episode, review: $review) { - stars - commentary - } -} -``` - -```swift -let review = ReviewInput(stars: 5, commentary: "This is a great movie!") -apollo.perform(mutation: CreateReviewForEpisodeMutation(episode: .jedi, review: review)) -``` - -## Designing mutation results - -When people talk about GraphQL, they often focus on the data fetching side of things, because that's where GraphQL brings the most value. Mutations can be pretty nice if done well, but the principles of designing good mutations, and especially good mutation result types, are not yet well-understood in the open source community. So when you are working with mutations it might often feel like you need to make a lot of application-specific decisions. - -In GraphQL, mutations can return any type, and that type can be queried just like a regular GraphQL query. So the question is - what type should a particular mutation return? - -In most cases, the data available from a mutation result should be the server developer's best guess of the data a client would need to understand what happened on the server. For example, a mutation that creates a new comment on a blog post might return the comment itself. A mutation that reorders an array might need to return the whole array. - -## Uploading files - -### An Important Caveat About File Uploads -Apollo recommends only using GraphQL file uploading for proof-of-concept applications. While there is a spec we presently support for making `multipart-form` requests with GraphQL, we've found that in practice that it's much simpler to use more purpose-built tools for file upload. - -In practice, this means using a more traditional method to upload your file like REST `multipart-form` uploads or SDK's that support file uploads, such as AmazonS3. [This article covers how to do that with Typescript](https://www.apollographql.com/blog/graphql-file-uploads-with-react-hooks-typescript-amazon-s3-tutorial-ef39d21066a2), but the general theory for iOS works basically the same: - -- Upload data **not** using GraphQL, getting back either an identifier or URL for the uploaded data. -- Send that received identifier or URL to your graph using GraphQL. - -If you'd still prefer to upload directly with Apollo, instructions follow. - -### Uploading Directly With Apollo - -The iOS SDK supports the [GraphQL Multipart Request Specification](https://github.com/jaydenseric/graphql-multipart-request-spec#multipart-form-field-structure) for uploading files. - -At the moment, we only support uploads for a single operation, not for batch operations. You can upload multiple files for a single operation if your server supports it, though. - -To upload a file, you will need: - -- A `NetworkTransport` which also supports the `UploadingNetworkTransport` protocol on your `ApolloClient` instance. If you're using `RequestChainNetworkTransport` (which is set up by default), this protocol is already supported. -- The correct `MIME` type for the data you're uploading. The default value is `application/octet-stream`. -- Either the data or the file URL of the data you want to upload. -- A mutation which takes an `Upload` as a parameter. Note that this must be supported by your server. - -Here is an example of a GraphQL query for a mutation that accepts a single upload, and then returns the `id` for that upload: - -```graphql -mutation UploadFile($file:Upload!) { - singleUpload(file:$file) { - id - } -} -``` - -If you wanted to use this to upload a file called `a.txt`, it would look something like this: - -```swift -// Create the file to upload -guard - let fileURL = Bundle.main.url(forResource: "a", - withExtension: "txt"), - let file = GraphQLFile(fieldName: "file", // Must be the name of the field the file is being uploaded to - originalName: "a.txt", - mimeType: "text/plain", // <-defaults to "application/octet-stream" - fileURL: fileURL) else { - // Either the file URL couldn't be created or the file couldn't be created. - return -} - -// Actually upload the file -client.upload(operation: UploadFileMutation(file: "a"), // <-- `Upload` is a custom scalar that's a `String` under the hood. - files: [file]) { result in - switch result { - case .success(let graphQLResult): - print("ID: \(graphQLResult.data?.singleUpload.id)") - case .failure(let error): - print("error: \(error)") - } -} -``` - -A few other notes: - -- Due to some limitations around the spec, whatever the file is being added for should be at the root of your GraphQL query. So if you have something like: - - ```graphql - mutation AvatarUpload($userID: GraphQLID!, $file: Upload!) { - id - } - ``` - - it will work, but if you have some kind of object encompassing both of those fields like this: - - ```graphql - // Assumes AvatarObject(userID: GraphQLID, file: Upload) exists - mutation AvatarUpload($avatarObject: AvatarObject!) { - id - } - ``` - - it will not. Generally you should be able to deconstruct upload objects to allow you to send the appropriate fields. - -- If you are uploading an array of files, you need to use the same field name for each file. These will be updated at send time. -- If you are uploading an array of files, the array of `String`s passed into the query must be the same number as the array of files. diff --git a/docs/source/request-pipeline.mdx b/docs/source/request-pipeline.mdx deleted file mode 100644 index 27f999bb22..0000000000 --- a/docs/source/request-pipeline.mdx +++ /dev/null @@ -1,633 +0,0 @@ ---- -title: Request pipeline in Apollo iOS ---- - -In Apollo iOS, most `ApolloClient` instances use the `RequestChainNetworkTransport` to execute GraphQL queries and mutations on a remote server. Appropriately, this network transport uses a structure called a **request chain** to process each operation in individual steps. - -> For more information on the _subscription_ request pipeline, see [Subscriptions](./subscriptions/). - -## Request chains - -A **request chain** defines a sequence of **interceptors** that handle the lifecycle of a particular GraphQL operation's execution. One interceptor might add custom HTTP headers to a request, while the next might be responsible for actually _sending_ the request to a GraphQL server over HTTP. A third interceptor might then write the operation's result to the Apollo iOS cache. - -When an operation is executed, an object called an **`InterceptorProvider`** generates a `RequestChain` for the operation. Then, `kickoff` is called on the request chain, which runs the first interceptor in the chain: - -```mermaid -flowchart TB - operation(Client executes
operation) - operation --> chain(InterceptorProvider
creates request chain) - link1(First
interceptor) - link2(Second
interceptor) - complete(Chain complete) - result(Return Result) - error(Handle Error) - chain--"kickoff called"-->link1 - link1--proceedAsync called-->link2 - link2 --> complete - complete--No result available-->error - complete--Result available-->result - class error secondary; - class result tertiary; -``` - -An interceptor can perform arbitrary, asynchronous logic on any thread. When an interceptor finishes running, it calls `proceedAsync` on its `RequestChain`, which advances to the next interceptor. - -By default when the last interceptor in the chain finishes, if a parsed operation result is available, that result is returned to the operation's original caller. Otherwise, error-handling logic is called. - -**Each request has its own short-lived `RequestChain`.** This means that the sequence of interceptors can differ for each operation. - -## Interceptor providers - -To generate a [request chain](#request-chains) for each GraphQL operation, Apollo iOS passes operations to an object called an **interceptor provider**. This object conforms to the [`InterceptorProvider` protocol](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/InterceptorProvider.swift). - -### Default provider - -`DefaultInterceptorProvider` is a default implementation of an interceptor provider. It works with the Apollo iOS parsing and caching system and tries to replicate the experience of using the old `HTTPNetworkTransport` as closely as possible. It takes a `URLSessionClient` and an `ApolloStore` to pass into the interceptors it creates. - -**`DefaultInterceptorProvider` is recommended for most applications.** If necessary, you can create a [custom interceptor provider](#custom-interceptor-providers). - -#### Default interceptors - -The `DefaultInterceptorProvider` creates a request chain with the following interceptors for _every_ operation, as shown in the [source](https://github.com/apollographql/apollo-ios/blob/57c07f1fa046b98ce86107ebacb521dd7cd9855c/Sources/Apollo/DefaultInterceptorProvider.swift#L30-L40): - - - -```mermaid -flowchart TB - max(MaxRetryInterceptor) --> cacheRead(CacheReadInterceptor) - cacheRead --> network(NetworkFetchInterceptor) - network --> response(ResponseCodeInterceptor) - response --> json(JSONResponseParsingInterceptor) - json --> apq(AutomaticPersistedQueryInterceptor) - apq --> cacheWrite(CacheWriteInterceptor) -``` - - - -> These built-in interceptors are described [below](#built-in-interceptors). - -### Custom interceptor providers - -> [See an example interceptor provider.](#example-interceptor-provider) - -If your use case requires it, you can create a custom struct or class that conforms to the [`InterceptorProvider` protocol](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/InterceptorProvider.swift). - -If you define a custom `InterceptorProvider`, it should almost always create a `RequestChain` that uses a similar structure to the [default](#default-interceptors), but that includes additions or modifications as needed for particular operations. - -> If you only need to add interceptors to the beginning or end of the default request chain, you can _subclass_ `DefaultInterceptorProvider` instead of creating a new class from scratch. - -When creating request chains in your custom interceptor provider, note the following: - -* Interceptors are designed to be **short-lived**. Your interceptor provider should provide a completely new set of interceptors for each request to avoid having multiple calls use the same interceptor instance simultaneously. -* Holding references to individual interceptors (outside of test verification) is generally not recommended. Instead, you can create an interceptor that holds onto a longer-lived object, and the provider can pass this object into each new set of interceptors. This way, each interceptor is disposable, but you don't have to recreate the underlying object that does heavier work. - -If you do create your own `InterceptorProvider`, you can use any of the built-in interceptors that are included in Apollo iOS: - -### Built-in interceptors - -Apollo iOS provides a collection of built-in interceptors you can create in a [custom interceptor provider](#custom-interceptor-providers). You can also create a custom interceptor by defining a class that conforms to the [`ApolloInterceptor` protocol](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/ApolloInterceptor.swift). - -> [See examples of custom interceptors](#example-interceptors) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDescription
- -**Pre-network** -
- -##### `MaxRetryInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/MaxRetryInterceptor.swift) - - -Enforces a maximum number of retries for a GraphQL operation that initially fails (default three retries). -
- -##### `CacheReadInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/CacheReadInterceptor.swift) - - -Reads data from the Apollo iOS cache _before_ an operation is executed on the server, according to that operation's `cachePolicy`. - -If cached data is found that fully resolves the operation, that data is returned. The request chain then continues or terminates according to the operation's `cachePolicy`. -
- -**Network** -
- -##### `NetworkFetchInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/NetworkFetchInterceptor.swift) - - -Takes a [`URLSessionClient`](#the-urlsessionclient-class) and uses it to send the prepared HTTPRequest (or subclass thereof) to the GraphQL server. - -If you're sending operations over the network, your `RequestChain` requires this interceptor (or a custom interceptor that handles network communication). - -
- -**Post-network** -
- -##### `ResponseCodeInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/ResponseCodeInterceptor.swift) - - -For unsuccessfully executed operations, checks the response code of the GraphQL server's HTTP response and passes it to the `RequestChain`'s `handleErrorAsync` callback. - -Note that most errors at the GraphQL level are returned with a `200` status code and information in the `errors` array (per the [GraphQL spec](https://spec.graphql.org/October2021/#sec-Response-Format)). This interceptor helps with server-level errors (such as `500`s) and errors that are returned by middleware. - -For more information, see [this article on error handling in GraphQL](https://medium.com/@sachee/200-ok-error-handling-in-graphql-7ec869aec9bc). - -
- -##### `AutomaticPersistedQueryInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/AutomaticPersistedQueryInterceptor.swift) - - -Checks a GraphQL server's response _after_ execution to see whether the provided APQ hash for the operation was successfully found by the server. If it _wasn't_, the interceptor restarts the chain and the operation is retried with the full query string. - -
- -##### `JSONResponseParsingInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/JSONResponseParsingInterceptor.swift) - - -Parses a GraphQL server's JSON response into a `GraphQLResult` object and attaches it to the `HTTPResponse`. - -
- -##### `CacheWriteInterceptor` - -[View source](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/CacheWriteInterceptor.swift) - - -Writes response data to the Apollo iOS cache _after_ an operation is executed on the server, according to that operation's `cachePolicy`. - -
- -#### `additionalErrorInterceptor` - -An `InterceptorProvider` can optionally provide an `additionalErrorInterceptor` that's called before an error is returned to the caller. This is mostly useful for logging and tracing errors. This interceptor must conform to the [`ApolloErrorInterceptor` protocol](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/ApolloErrorInterceptor.swift). - -The `additionalErrorInterceptor` is _not_ part of the request chain. Instead, any other interceptor can invoke this interceptor by calling `chain.handleErrorAsync`. - -Note that for _expected_ errors with a clear resolution (such as renewing an expired authentication token), you should define an interceptor _within_ your request chain that can resolve the issue and retry the operation. - -### Interceptor flow - -Most interceptors execute their logic and then call `chain.proceedAsync` to proceed to the next interceptor in the request chain. However, interceptors can call other methods to override this default flow. - -#### Retrying an operation - -Any interceptor can call `chain.retry` to immediately restart the current request chain from the beginning. This can be helpful if the interceptor needed to refresh an access token or modify other configuration for the operation to succeed. - -> **Important:** Do not call `retry` in an unbounded way. If your server is returning `500`s or if the user has no internet connection, repeatedly retrying can create an infinite loop of requests (especially if you aren't using the `MaxRetryInterceptor` to limit the number of retries). -> -> Unbounded retries will drain your user's battery and might also run up their data usage. Make sure to only `retry` when there's something your code can do about the original failure! - -#### Returning a value - -An interceptor can directly return a value to the operation's original caller, instead of waiting for the request chain to complete. To do so, the interceptor can call `chain.returnValueAsync`. - -**This does not prevent the rest of the request chain from executing.** An interceptor can still call `chain.proceedAsync` as usual after calling `chain.returnValueAsync`. - -You can even call `chain.returnValueAsync` multiple times within a request chain! This is helpful when initially returning a _locally cached_ value before returning a value returned by the GraphQL server. - -#### Returning an error - -If an interceptor encounters an error, it can return the details of that error by calling `chain.handleErrorAsync`. - -**This does not prevent the rest of the request chain from executing.** An interceptor can still call `chain.proceedAsync` as usual after calling `chain.handleErrorAsync`. However, if the encountered error will cause the operation to fail, you can skip calling `chain.proceedAsync` to end the request chain. - -## Examples - -The following example snippets demonstrate how to use an advanced request pipeline with custom interceptors. This code assumes you have the following _hypothetical_ classes in your own code (these classes are _not_ part of Apollo iOS): - -- **`UserManager`:** Checks whether the active user is logged in, performs associated checks on errors and responses to see if they need to renew their token, and performs that renewal when necessary. -- **`Logger`:** Handles printing logs based on their level. Supports `.debug`, `.error`, and `.always` log levels. - -### Example interceptors - -#### `UserManagementInterceptor` - -This example interceptor checks whether the active user is logged in. If so, it asynchronously renews that user's access token if it's expired. Finally, it adds the access token to an `Authorization` header before proceeding to the next interceptor in the request chain. - -```swift -import Apollo - -class UserManagementInterceptor: ApolloInterceptor { - - enum UserError: Error { - case noUserLoggedIn - } - - /// Helper function to add the token then move on to the next step - private func addTokenAndProceed( - _ token: Token, - to request: HTTPRequest, - chain: RequestChain, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - request.addHeader(name: "Authorization", value: "Bearer \(token.value)") - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - guard let token = UserManager.shared.token else { - // In this instance, no user is logged in, so we want to call - // the error handler, then return to prevent further work - chain.handleErrorAsync(UserError.noUserLoggedIn, - request: request, - response: response, - completion: completion) - return - } - - // If we've gotten here, there is a token! - if token.isExpired { - // Call an async method to renew the token - UserManager.shared.renewToken { [weak self] tokenRenewResult in - guard let self = self else { - return - } - - switch tokenRenewResult { - case .failure(let error): - // Pass the token renewal error up the chain, and do - // not proceed further. Note that you could also wrap this in a - // `UserError` if you want. - chain.handleErrorAsync(error, - request: request, - response: response, - completion: completion) - case .success(let token): - // Renewing worked! Add the token and move on - self.addTokenAndProceed(token, - to: request, - chain: chain, - response: response, - completion: completion) - } - } - } else { - // We don't need to wait for renewal, add token and move on - self.addTokenAndProceed(token, - to: request, - chain: chain, - response: response, - completion: completion) - } - } -} -``` - -#### `RequestLoggingInterceptor` - -This example interceptor logs the outgoing request using the hypothetical `Logger` class, then proceeds to the next interceptor in the request chain: - -```swift -import Apollo - -class RequestLoggingInterceptor: ApolloInterceptor { - - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - Logger.log(.debug, "Outgoing request: \(request)") - chain.proceedAsync(request: request, - response: response, - completion: completion) - } -} -``` - -#### `‌ResponseLoggingInterceptor` - -This example interceptor uses the hypothetical `Logger` class to log the request's response if it exists, then proceeds to the next interceptor in the request chain. - -This is an example of an interceptor that can both proceed _and_ throw an error. We don't necessarily want to stop processing if this interceptor was added in wrong place, but we _do_ want to know about that error. - -```swift -import Apollo - -class ResponseLoggingInterceptor: ApolloInterceptor { - - enum ResponseLoggingError: Error { - case notYetReceived - } - - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - defer { - // Even if we can't log, we still want to keep going. - chain.proceedAsync(request: request, - response: response, - completion: completion) - } - - guard let receivedResponse = response else { - chain.handleErrorAsync(ResponseLoggingError.notYetReceived, - request: request, - response: response, - completion: completion) - return - } - - Logger.log(.debug, "HTTP Response: \(receivedResponse.httpResponse)") - - if let stringData = String(bytes: receivedResponse.rawData, encoding: .utf8) { - Logger.log(.debug, "Data: \(stringData)") - } else { - Logger.log(.error, "Could not convert data to string!") - } - } -} -``` - -### Example interceptor provider - -This `InterceptorProvider` creates request chains using all of the [default interceptors](#default-interceptors) in their usual order, with all of the [example interceptors](#example-interceptors) defined above added at the appropriate points in the request pipeline: - -```swift -import Foundation -import Apollo - -struct NetworkInterceptorProvider: InterceptorProvider { - - // These properties will remain the same throughout the life of the `InterceptorProvider`, even though they - // will be handed to different interceptors. - private let store: ApolloStore - private let client: URLSessionClient - - init(store: ApolloStore, - client: URLSessionClient) { - self.store = store - self.client = client - } - - func interceptors(for operation: Operation) -> [ApolloInterceptor] { - return [ - MaxRetryInterceptor(), - CacheReadInterceptor(store: self.store), - UserManagementInterceptor(), - RequestLoggingInterceptor(), - NetworkFetchInterceptor(client: self.client), - ResponseLoggingInterceptor(), - ResponseCodeInterceptor(), - JSONResponseParsingInterceptor(cacheKeyForObject: self.store.cacheKeyForObject), - AutomaticPersistedQueryInterceptor(), - CacheWriteInterceptor(store: self.store) - ] - } -} -``` - -### Example `Network` singleton - -As when initializing a [basic client](./initialization/#basic-client-creation), it's recommended to create a `Network` singleton to use a single `ApolloClient` instance across your app. - -Here's what that singleton might look like for an advanced client: - -```swift -import Foundation -import Apollo - -class Network { - static let shared = Network() - - private(set) lazy var apollo: ApolloClient = { - // The cache is necessary to set up the store, which we're going to hand to the provider - let cache = InMemoryNormalizedCache() - let store = ApolloStore(cache: cache) - - let client = URLSessionClient() - let provider = NetworkInterceptorProvider(store: store, client: client) - let url = URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/graphql")! - - let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: url) - - - // Remember to give the store you already created to the client so it - // doesn't create one on its own - return ApolloClient(networkTransport: requestChainTransport, - store: store) - }() -} -``` - -An example of setting up a client that can handle WebSocket and subscriptions is included in the [subscriptions documentation](subscriptions/#sample-subscription-supporting-initializer). - -## `RequestChainNetworkTransport` API reference - -The initializer for `RequestChainNetworkTransport` accepts the following properties, which provide you with fine-grained control of your HTTP requests and responses: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name /
Type
Description
- -##### `interceptorProvider` - -`InterceptorProvider` - - -**Required.** The interceptor provider to use when constructing a [request chain](#request-chains). See below for details on interceptor providers. -
- -##### `endpointURL` - -`URL` - - -**Required.** The GraphQL endpoint URL to use for all operations. -
- -##### `additionalHeaders` - -`Dictionary` - - -Any additional HTTP headers that should be added to **every** request, such as an API key or a language setting. - -If a header should only be added to _certain_ requests, or if its value might differ between requests, you should add that header in an interceptor instead. - -The default value is an empty dictionary. -
- -##### `autoPersistQueries` - -`Bool` - - -If `true`, Apollo iOS uses [Automatic Persisted Queries](https://www.apollographql.com/docs/apollo-server/performance/apq/) (APQ) to send an operation's hash instead of the full operation body by default. - -**Note:** To use APQ, make sure to generate your types with operation identifiers. In your Swift Script, make sure to pass a non-`nil` `operationIDsURL` to have this output. Also make sure you're using the `AutomaticPersistedQueryInterceptor` in your chain after a network request has come back to handle known APQ errors. - -The default value is `false`. -
- -##### `requestBodyCreator` - -`RequestBodyCreator` - - -The `RequestBodyCreator` object to use to build your `URLRequest`s. - -The default value is an `ApolloRequestBodyCreator` initialized with the default configuration. -
- -##### `useGETForQueries` - -`Bool` - - -If `true`, Apollo iOS sends all query operations using `GET` instead of `POST`. Mutation operations always use `POST`. - -This can improve performance if your GraphQL server uses a CDN (Content Delivery Network) to cache the results of queries that rarely change. - -The default value is `false`. -
- -##### `useGETForPersistedQueryRetry` - -`Bool` - - -If `true`, Apollo iOS sends a full query operation using `GET` instead of `POST` after the GraphQL server reports that an APQ hash is not available in its cache. - -The default value is `false`. -
- -## The `URLSessionClient` class - -Because `URLSession` only supports use in the background using the delegate-based API, Apollo iOS provides a [`URLSessionClient`](https://github.com/apollographql/apollo-ios/blob/main/Sources/Apollo/URLSessionClient.swift) class that helps configure that. - -> Note that because setting up a delegate is only possible in the initializer for `URLSession`, you can only pass `URLSessionClient`'s initializer a `URLSessionConfiguration`, **not** an existing `URLSession`. - -By default, instances of `URLSessionClient` use `URLSessionConfiguration.default` to set up their URL session, and instances of `DefaultInterceptorProvider` use the default initializer for `URLSessionClient`. - -The `URLSessionClient` class and most of its methods are `open`, so you can subclass it if you need to override any of the delegate methods for the `URLSession` delegates we're using, or if you need to handle additional delegate scenarios. diff --git a/docs/source/screenshot/codegen_success.png b/docs/source/screenshot/codegen_success.png deleted file mode 100644 index 611def458b..0000000000 Binary files a/docs/source/screenshot/codegen_success.png and /dev/null differ diff --git a/docs/source/screenshot/graphiql_docs_tab.png b/docs/source/screenshot/graphiql_docs_tab.png deleted file mode 100644 index ba95839d9c..0000000000 Binary files a/docs/source/screenshot/graphiql_docs_tab.png and /dev/null differ diff --git a/docs/source/screenshot/graphiql_empty.png b/docs/source/screenshot/graphiql_empty.png deleted file mode 100644 index 9c01960691..0000000000 Binary files a/docs/source/screenshot/graphiql_empty.png and /dev/null differ diff --git a/docs/source/screenshot/graphiql_query.png b/docs/source/screenshot/graphiql_query.png deleted file mode 100644 index 089d236bb1..0000000000 Binary files a/docs/source/screenshot/graphiql_query.png and /dev/null differ diff --git a/docs/source/screenshot/graphql_file_launchlist.png b/docs/source/screenshot/graphql_file_launchlist.png deleted file mode 100644 index 8f685a5bb9..0000000000 Binary files a/docs/source/screenshot/graphql_file_launchlist.png and /dev/null differ diff --git a/docs/source/screenshot/input_output_files.png b/docs/source/screenshot/input_output_files.png deleted file mode 100644 index bb6b08047d..0000000000 Binary files a/docs/source/screenshot/input_output_files.png and /dev/null differ diff --git a/docs/source/screenshot/new_run_script_phase.png b/docs/source/screenshot/new_run_script_phase.png deleted file mode 100644 index 9879d97b8d..0000000000 Binary files a/docs/source/screenshot/new_run_script_phase.png and /dev/null differ diff --git a/docs/source/screenshot/schema_download_success.png b/docs/source/screenshot/schema_download_success.png deleted file mode 100644 index b954fd4c2c..0000000000 Binary files a/docs/source/screenshot/schema_download_success.png and /dev/null differ diff --git a/docs/source/screenshot/schema_location.jpg b/docs/source/screenshot/schema_location.jpg deleted file mode 100644 index c48e9c306f..0000000000 Binary files a/docs/source/screenshot/schema_location.jpg and /dev/null differ diff --git a/docs/source/screenshot/spm_packages_add_dependency.png b/docs/source/screenshot/spm_packages_add_dependency.png deleted file mode 100644 index 1612cf7a93..0000000000 Binary files a/docs/source/screenshot/spm_packages_add_dependency.png and /dev/null differ diff --git a/docs/source/screenshot/spm_packages_add_package.jpg b/docs/source/screenshot/spm_packages_add_package.jpg deleted file mode 100644 index b6a3d8f1a1..0000000000 Binary files a/docs/source/screenshot/spm_packages_add_package.jpg and /dev/null differ diff --git a/docs/source/screenshot/spm_packages_dialog.jpg b/docs/source/screenshot/spm_packages_dialog.jpg deleted file mode 100644 index abaf1d0541..0000000000 Binary files a/docs/source/screenshot/spm_packages_dialog.jpg and /dev/null differ diff --git a/docs/source/screenshot/spm_packages_setting.png b/docs/source/screenshot/spm_packages_setting.png deleted file mode 100644 index 835082fd96..0000000000 Binary files a/docs/source/screenshot/spm_packages_setting.png and /dev/null differ diff --git a/docs/source/screenshot/spm_paste_url.png b/docs/source/screenshot/spm_paste_url.png deleted file mode 100644 index 60934a8b56..0000000000 Binary files a/docs/source/screenshot/spm_paste_url.png and /dev/null differ diff --git a/docs/source/screenshot/spm_select_package.jpg b/docs/source/screenshot/spm_select_package.jpg deleted file mode 100644 index e87b7d0c53..0000000000 Binary files a/docs/source/screenshot/spm_select_package.jpg and /dev/null differ diff --git a/docs/source/screenshot/spm_select_package.png b/docs/source/screenshot/spm_select_package.png deleted file mode 100644 index b5dbd094af..0000000000 Binary files a/docs/source/screenshot/spm_select_package.png and /dev/null differ diff --git a/docs/source/screenshot/spm_select_version.png b/docs/source/screenshot/spm_select_version.png deleted file mode 100644 index 1bb9a543c9..0000000000 Binary files a/docs/source/screenshot/spm_select_version.png and /dev/null differ diff --git a/docs/source/screenshot/spm_version_change.png b/docs/source/screenshot/spm_version_change.png deleted file mode 100644 index fc293a9f36..0000000000 Binary files a/docs/source/screenshot/spm_version_change.png and /dev/null differ diff --git a/docs/source/screenshot/would_like_to_access.png b/docs/source/screenshot/would_like_to_access.png deleted file mode 100644 index 94c9cda220..0000000000 Binary files a/docs/source/screenshot/would_like_to_access.png and /dev/null differ diff --git a/docs/source/subscriptions.md b/docs/source/subscriptions.md deleted file mode 100644 index a7258dfbe9..0000000000 --- a/docs/source/subscriptions.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Subscriptions ---- - -GraphQL supports [subscriptions](https://graphql.org/blog/subscriptions-in-graphql-and-relay/) to allow clients to be immediately updated when the data changes on a server. - -The Apollo iOS library supports the use of subscriptions primarily through the use of [`ApolloWebSocket`](api/ApolloSQLite/README/), an optional additional library that uses popular iOS WebSocket library [`Starscream`](https://github.com/daltoniam/Starscream) under the hood to use WebSockets to connect to your GraphQL server. - -Subscriptions are also supported through code generation: Any time your schema declares a subscription field, an operation conforming to `GraphQLSubscription` will be generated which allows you to pass in any parameters that subscription field takes. - -Once those operations are generated, you can use an instance of `ApolloClient` using a subscription-supporting network transport to subscribe, and continue to receive updates about changes until the subscription is cancelled. - -## Transport types which support subscriptions - -There are two different classes which conform to the [`NetworkTransport` protocol](api/Apollo/protocols/NetworkTransport/) within the `ApolloWebSocket` library: - -- **`WebSocketTransport`** sends all operations over a web socket. -- **`SplitNetworkTransport`** hangs onto both a [`WebSocketTransport`](api/ApolloWebSocket/classes/WebSocketTransport/) instance and an [`UploadingNetworkTransport`](api/Apollo/protocols/UploadingNetworkTransport/) instance (usually [`RequestChainNetworkTransport`](api/Apollo/classes/RequestChainNetworkTransport/)) in order to create a single network transport that can use http for queries and mutations, and web sockets for subscriptions. - -Typically, you'll want to use `SplitNetworkTransport`, since this allows you to retain the single `NetworkTransport` setup and avoids any potential issues of using multiple client objects. - -## GraphQL over WebSocket protocols - -There are two protocols supported by apollo-ios: -1. [`graphql-ws`](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) protocol which is implemented in the [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) and [AWS AppSync](https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html#handshake-details-to-establish-the-websocket-connection) libraries. -2. [`graphql-transport-ws`](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) protocol which is implemented in the [graphql-ws](https://github.com/enisdenjo/graphql-ws) library. - -It is important to note that the protocols are not cross-compatible and you will need to know which is implemented in the service you're connecting to. All `WebSocket` initializers allow you to specify which GraphQL over WebSocket protocol should be used. - -## Sample subscription-supporting initializer - -Here is an example of setting up a singleton similar to the [Example Advanced Client Setup](initialization/#advanced-client-creation), but which uses a `SplitNetworkTransport` to support both subscriptions and queries: - -```swift -import Foundation -import Apollo -import ApolloWebSocket - -// MARK: - Singleton Wrapper - -class Apollo { - static let shared = Apollo() - - /// A web socket transport to use for subscriptions - private lazy var webSocketTransport: WebSocketTransport = { - let url = URL(string: "ws://localhost:8080/websocket")! - let webSocketClient = WebSocket(url: url, protocol: .graphql_transport_ws) - return WebSocketTransport(websocket: webSocketClient) - }() - - /// An HTTP transport to use for queries and mutations - private lazy var normalTransport: RequestChainNetworkTransport = { - let url = URL(string: "http://localhost:8080/graphql")! - return RequestChainNetworkTransport(interceptorProvider: DefaultInterceptorProvider(store: self.store), endpointURL: url) - }() - - /// A split network transport to allow the use of both of the above - /// transports through a single `NetworkTransport` instance. - private lazy var splitNetworkTransport = SplitNetworkTransport( - uploadingNetworkTransport: self.normalTransport, - webSocketNetworkTransport: self.webSocketTransport - ) - - /// Create a client using the `SplitNetworkTransport`. - private(set) lazy var client = ApolloClient(networkTransport: self.splitNetworkTransport, store: self.store) - - /// A common store to use for `normalTransport` and `client`. - private lazy var store = ApolloStore() -} -``` - -## Example usage of a subscription - -Let's say you're using the [Sample Star Wars API](https://github.com/apollographql/apollo-ios/blob/main/Sources/StarWarsAPI/API.swift), and you want to use a view controller with a `UITableView` to show a list of reviews that will automatically update whenever a new review is added. - -You can use the [`ReviewAddedSubscription`](https://github.com/apollographql/apollo-ios/blob/main/Sources/StarWarsAPI/API.swift#L5386) to accomplish this: - -```swift -class ReviewViewController: UIViewController { - - private var subscription: Cancellable? - private var reviewList = [Review]() - - // Assume data source and delegate are hooked up in Interface Builder - @IBOutlet private var reviewTableView: UITableView! - - override func viewDidLoad() { - super.viewDidLoad() - - // Set the subscription variable up - be careful not to create a retain cycle! - self.subscription = Apollo.shared.client - .subscribe(subscription: ReviewAddedSubscription()) { [weak self] result in - guard let self = self else { - return - } - - switch result { - case .success(let graphQLResult): - if let review = graphQLResult.data?.reviewAdded { - // A review was added - append it to the list then reload the data. - self.reviewList.append(review) - self.reviewTableView.reloadData() - } // else, something went wrong and you should check `graphQLResult.error` for problems - case .failure(let error): - // Not included here: Show some kind of alert - } - } - } - - deinit { - // Make sure the subscription is cancelled, if it exists, when this object is deallocated. - self.subscription?.cancel() - } - - // MARK: - Standard TableView Stuff - - func tableView(_ tableView: UITableView, - numberOfRowsInSection section: Int) -> Int { - return self.reviewList.count - } - - func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - // Assume `ReviewCell` is a cell for displaying reviews created elsewhere - guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? ReviewCell else { - return UITableViewCell() - } - - let review = self.reviewList[indexPath.row] - - cell.episode = review.episode - cell.stars = review.stars - cell.commentary = review.commentary - - return cell - } -} -``` - -Each time a review is added, the subscription's closure is called and if the proper data is included, the new data will be displayed immediately. - -Note that if you only wanted to be updated reviews for a specific episode, you could specify that episode in the initializer for `ReviewAddedSubscription`. - -## Subscriptions and authorization tokens - -In a standard HTTP operation, if authentication is necessary an `Authorization` header is often sent with requests. However, with a web socket, this can't be sent with every payload since a persistent connection is required. - -For web sockets, the `connectingPayload` provides those parameters you would traditionally specify as part of the headers of your request. - -Note that this must be set **when the `WebSocketTransport` is created**. If you need to update the `connectingPayload`, you will need to recreate the client using a new `webSocketTransport`. - -Assuming you (or your backend developers) have read [the authentication section](https://www.apollographql.com/docs/apollo-server/security/authentication/) and [subscriptions example / authentication over WebSocket](https://www.apollographql.com/docs/apollo-server/data/subscriptions/) of our backend documentation, you will need to initialize your `ApolloClient` instance as follows: - -```swift -import Foundation -import Apollo -import ApolloWebSocket - -// MARK: - Singleton Wrapper - -let magicToken = "So long and thanks for all the fish" - -class Apollo { - static let shared = Apollo() - - /// A web socket transport to use for subscriptions - // This web socket will have to provide the connecting payload which - // initializes the connection as an authorized channel. - private lazy var webSocketTransport: WebSocketTransport = { - let url = URL(string: "ws://localhost:8080/websocket")! - let webSocketClient = WebSocket(url: url, protocol: .graphql_transport_ws) - let authPayload = ["authToken": magicToken] - return WebSocketTransport(websocket: webSocketClient, connectingPayload: authPayload) - }() - - /// An HTTP transport to use for queries and mutations. - private lazy var normalTransport: RequestChainNetworkTransport = { - let url = URL(string: "http://localhost:8080/graphql")! - return RequestChainNetworkTransport(interceptorProvider: DefaultInterceptorProvider(store: self.store), endpointURL: url) - }() - - /// A split network transport to allow the use of both of the above - /// transports through a single `NetworkTransport` instance. - private lazy var splitNetworkTransport = SplitNetworkTransport( - uploadingNetworkTransport: self.normalTransport, - webSocketNetworkTransport: self.webSocketTransport - ) - - /// Create a client using the `SplitNetworkTransport`. - private(set) lazy var client = ApolloClient(networkTransport: self.splitNetworkTransport, store: self.store) - - /// A common store to use for `normalTransport` and `client`. - private lazy var store = ApolloStore() -} -``` - - - diff --git a/docs/source/swift-scripting.md b/docs/source/swift-scripting.md deleted file mode 100644 index c34c72abac..0000000000 --- a/docs/source/swift-scripting.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -title: Swift scripting ---- - -Apollo Client for iOS enables you to use Swift scripting to perform certain operations that otherwise require the command line. - -This document guides you through setting up a Swift Package Manager executable project using our template, and then using that project to: - -- Download a schema -- Generate Swift code for your model objects based on your schema and operations - -## Conceptual background - -Apollo's code generation requires both of the following to run: - -* Your **schema**, which defines what it's *possible* for you to request from or send to your server -* One or more **operations**, which define what you are *actually* requesting from the server - -If you're missing either of these, codegen can't run. If you define operations but no schema, the operations can't be validated. If you define a schema but no operations, there's nothing to validate or generate code for. - -Or, more succinctly: - -``` -schema + operations = code -``` - -Each operation you define can be one of the following: - -- A **query**, which is a one-time request for specific data -- A **mutation**, which changes data on the server and then receives updated data back -- A **subscription**, which allows you to listen for changes to a particular object or type of object - -Code generation takes your operations and compares them to the schema to confirm that they're valid. If an operation _isn't_ valid, the whole process errors out. If all operations are valid, codegen generates Swift code that gives you end-to-end type safety for each operation. - -The rest of this guide will help you set up a Swift Package Manager executable that will live alongside your main `xcodeproj` and which can be used either from your main `xcodeproj` or on its own to download a schema, generate code, or both. - -## Setup - -We've created a template of a Swift Package Manager Executable to speed things along. - -This project is provided as a template for an executable rather than a compiled executable to allow you to make changes to the executable relevant to your setup. This allows you to customize while still using Swift as much as possible and bash as little as possible, to preserve both type safety and readability. - -You can download the current version of the template from this repo: [https://github.com/apollographql/iOSCodegenTemplate](https://github.com/apollographql/iOSCodegenTemplate) - -When you unzip the downloaded repo, you'll see that there's a folder called **`ApolloCodgen`**. - -If you're using the default target structure for an Xcode project, your project's file structure will look essentially like this in Finder: - -```txt title="Sample Project Structure" -MyProject // Source root -├─ MyProject.xcodeproj -├─ MyProject/ // Contains app target source files -├─ MyLibraryTarget/ // Contains lib target source files -├─ MyProjectTests/ // Contains test files -``` - -Drag the `ApolloCodegen` folder in **at the same level as your other targets** (in Finder, not in Xcode): - -```txt title="Sample Project Structure" -MyProject // Source root -├─ MyProject.xcodeproj -├─ MyProject/ // Contains app target source files -├─ MyLibraryTarget/ // Contains lib target source files -├─ MyProjectTests/ // Contains test files -├─ ApolloCodegen/ // Contains the swift scripting files you just downloaded and dragged in -``` - -Double-click `Package.swift` in the `ApolloCodegen` folder to open the executable's package in Xcode. - -**Important!** Since a particular version of code generation is tied to a particular version of the SDK, you need to make sure that the `dependencies` section of `Package.swift` is set to grab the same version of the `apollo-ios` library you're using in your main application: - -```swift title="Package.swift" -.package(name: "Apollo", - url: "https://github.com/apollographql/apollo-ios.git", - .upToNextMinor(from: "0.49.0")) -``` - -Note that these instructions are updated along with newer versions of the library - if you're seeing something that doesn't compile, please check that you're on the most recent version of the SDK both in your app and in your Codegen project. - -## A Tour Of The Template Project - -This section will walk you through the already-set up code in the template project. There are two files: `main.swift` and `FileStructure.swift`. - -### FileStructure - -This structure exists to simplify accessing your local filesystem without needing to pass any URLs through as environment variables. - -It uses `FileFinder` to find the directory that the file containing the code lives in, and then you can use either standard `FileManager` APIs or `.apollo` extension methods provided by `ApolloCodegenLib` to find parent or child files and folders. - -There are two major pieces of information it grabs automatically, assuming you have a filesystem set up as in the example above: - -- The location where the Typescript CLI will be downloaded. This is what (currently) does the actual generation of code and fetching of schemas. **NOTE**: This location should be added to your `.gitignore` file, since it's going to contain a ton of JS that can be redownloaded locally very easily, and will otherwise bloat your repo. -- The `sourceRoot` of your entire repository, which contains both your Xcode project and your Swift Scripting project. - -From `sourceRoot` you should be able to use `FileManager` APIs or their `.apollo` extensions to navigate anywhere in your project's file tree. - -### SwiftScript - -This object uses the [Swift Argument Parser](https://github.com/apple/swift-argument-parser) to create an outer root command which can be run either from the command line if a binary is exported, or run directly by using `swift run` (recommended). - -There are sub-commands to run specific tasks - these are most often what you'll want to focus on, and where you'll need to make changes appropriate to your project's name and structure. - - -#### DownloadSchema - -This command will download a GraphQL schema. There are two pieces you definitely need to fill in: - -- The place you want to download your schema from. This is usually via introspection of your GraphQL endpoint, so the default is set to use this, you just need to replace the `localhost` URL with the URL of your GraphQL endpoint. If you've got it set up, you can also download your schema from the Apollo Schema Registry. You'll need to add your API Key and Graph ID for this, which you can get from Apollo Studio. -- The name of the folder where you want the schema downloaded. If you've followed the template above, you'll want to place the schema in the folder where your target's code lives. - -You can also use [options provided by the `ApolloSchemaDownloadConfiguration` object](https://www.apollographql.com/docs/ios/api/ApolloCodegenLib/structs/ApolloSchemaDownloadConfiguration/) to further configure how and where you want to download your schema. - -#### GenerateCode - -This command will take your downloaded schema and your local operations and combine them to generate code. Note that if you don't have a schema _or_ don't have any local operations, code generation will fail. - -You will need to replace one placeholder: The location of your target's root folder. - -## Running as a script - -To run the script using the command line, `cd` into the `ApolloCodegen` directory and run the following command: - -``` -swift run ApolloCodegen [subcommand] -``` - -This will build and run the executable, and then run the specified subcommand. The first build may take a minute since it will need to check out dependencies, but the Swift build system's caching will prevent any steps that haven't had changes (including dependency fetching) from re-executing. - -If you don't provide a subcommand, a list of available subcommands will be printed. - -### Downloading a schema - -Update the `downloadSchema` command to have the correct download method and download path within the Swift file. Then, from the command line, run: - -``` -swift run ApolloCodegen downloadSchema -``` - -If you're using the template code and following the sample project structure, the schema should download here: - -```txt title="Sample Project Structure" -MyProject // SourceRoot -├─ MyProject.xcodeproj -├─ MyProject/ // Contains app target source files -│ └─ schema.graphqls -├─ MyLibraryTarget/ // Contains lib target source files -├─ MyProjectTests/ // Contains test files -├─ ApolloCodegen/ // Contains Swift Scripting files -``` - -Next, now that you have a schema, you need a GraphQL file with an operation in order to generate code. - -## Adding a `.graphql` file with an operation - -If you're not familiar with creating an operation in graphQL, please check out the [portion of our tutorial on executing your first query](https://www.apollographql.com/docs/ios/tutorial/tutorial-execute-query/). You can stop after the section about adding your query to Xcode. - -Make sure you've added the operation file to the project files, ideally at or above the level of the `schema.graphqls` (Otherwise, you'll need to manually pass the URL of your operation file to your code generation step): - -```txt title="Sample Project Structure" -MyProject // SourceRoot -├─ MyProject.xcodeproj -├─ MyProject/ // Contains app target source files -│ ├─ schema.graphqls -│ └─ LaunchList.graphql -├─ MyLibraryTarget/ // Contains lib target source files -├─ MyProjectTests/ // Contains test files -├─ ApolloCodegen/ // Contains Swift Scripting files -``` - -Here, for example, is what this looks like in a file for one of the queries in our [tutorial application](./tutorial/tutorial-introduction): - -Launch list file - -**Note:** You do **not** need to add this file to your target in Xcode. Only the generated Swift code needs to be included in your target for it to work. - -## Running code generation from your main project - -Codegen should be set up to run from your main project when you build - this will allow any changes you've made to your graphQL files to be picked up and the code to be regenerated. - -This is best achieved with a Run Script Build Phase. - -1. Select the target in your project or workspace you want to run code generation, and go to the `Build Phases` tab. - -2. Create a new Run Script Build Phase by selecting the **+** button in the upper left-hand corner: - ![New run script build phase dialog](screenshot/new_run_script_phase.png) - -3. Update the build phase run script to `cd` into the folder where your executable's code lives, then run `swift run` (using `xcrun` so that you can ensure it runs with the correct SDK, no matter what type of project you're building): - - ``` - # Don't run this during index builds - if [ $ACTION = "indexbuild" ]; then exit 0; fi - - cd "${SRCROOT}"/ApolloCodegen - xcrun -sdk macosx swift run ApolloCodegen generate - - # propagate the xcrun call's return code to Xcode - exit $? - - ``` - - >**Note**: If your package ever seems to have problems with caching, run `swift package clean` before `swift run` for a totally clean build. Do not do this by default, because it substantially increases build time. - -4. Build your target. - -Now, every time you build your project, this script gets called. Because Swift knows not to recompile everything unless something's changed, it should not have a significant impact on your build time. - -## Swift-specific troubleshooting - -If you encounter errors around `SecTaskLoadEntitlements` that result in an immediate exit of the script instead of showing the permission prompt, verify that all the folders you're looking for exist at the correct path. This error is often caused by a typo. diff --git a/docs/source/tutorial/images/add_package_dialog.png b/docs/source/tutorial/images/add_package_dialog.png deleted file mode 100644 index 6c68565508..0000000000 Binary files a/docs/source/tutorial/images/add_package_dialog.png and /dev/null differ diff --git a/docs/source/tutorial/images/book_trip_printout.png b/docs/source/tutorial/images/book_trip_printout.png deleted file mode 100644 index 0d3950e532..0000000000 Binary files a/docs/source/tutorial/images/book_trip_printout.png and /dev/null differ diff --git a/docs/source/tutorial/images/build_phases.png b/docs/source/tutorial/images/build_phases.png deleted file mode 100644 index 4683c35ec3..0000000000 Binary files a/docs/source/tutorial/images/build_phases.png and /dev/null differ diff --git a/docs/source/tutorial/images/completed_id_query.png b/docs/source/tutorial/images/completed_id_query.png deleted file mode 100644 index 259a466709..0000000000 Binary files a/docs/source/tutorial/images/completed_id_query.png and /dev/null differ diff --git a/docs/source/tutorial/images/detail_loaded.png b/docs/source/tutorial/images/detail_loaded.png deleted file mode 100644 index e482ae965a..0000000000 Binary files a/docs/source/tutorial/images/detail_loaded.png and /dev/null differ diff --git a/docs/source/tutorial/images/detail_loaded_merlin_c.png b/docs/source/tutorial/images/detail_loaded_merlin_c.png deleted file mode 100644 index 3c987a0c66..0000000000 Binary files a/docs/source/tutorial/images/detail_loaded_merlin_c.png and /dev/null differ diff --git a/docs/source/tutorial/images/detail_view_launch_id.png b/docs/source/tutorial/images/detail_view_launch_id.png deleted file mode 100644 index fd5f10ac0e..0000000000 Binary files a/docs/source/tutorial/images/detail_view_launch_id.png and /dev/null differ diff --git a/docs/source/tutorial/images/dont_add_to_target.png b/docs/source/tutorial/images/dont_add_to_target.png deleted file mode 100644 index 9eaad7e409..0000000000 Binary files a/docs/source/tutorial/images/dont_add_to_target.png and /dev/null differ diff --git a/docs/source/tutorial/images/drag_run_script.png b/docs/source/tutorial/images/drag_run_script.png deleted file mode 100644 index 3bdff14656..0000000000 Binary files a/docs/source/tutorial/images/drag_run_script.png and /dev/null differ diff --git a/docs/source/tutorial/images/empty_file_template.png b/docs/source/tutorial/images/empty_file_template.png deleted file mode 100644 index 0995af3410..0000000000 Binary files a/docs/source/tutorial/images/empty_file_template.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_add_auth_header.png b/docs/source/tutorial/images/explorer_add_auth_header.png deleted file mode 100644 index b1a2cefbfe..0000000000 Binary files a/docs/source/tutorial/images/explorer_add_auth_header.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_add_launches_query.png b/docs/source/tutorial/images/explorer_add_launches_query.png deleted file mode 100644 index 52ae2d5ab4..0000000000 Binary files a/docs/source/tutorial/images/explorer_add_launches_query.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_added_empty_tab.png b/docs/source/tutorial/images/explorer_added_empty_tab.png deleted file mode 100644 index a543eb3611..0000000000 Binary files a/docs/source/tutorial/images/explorer_added_empty_tab.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_added_login_mutation.png b/docs/source/tutorial/images/explorer_added_login_mutation.png deleted file mode 100644 index efbd47db57..0000000000 Binary files a/docs/source/tutorial/images/explorer_added_login_mutation.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_authentication_header.png b/docs/source/tutorial/images/explorer_authentication_header.png deleted file mode 100644 index 0d44cb1f5f..0000000000 Binary files a/docs/source/tutorial/images/explorer_authentication_header.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_autocomplete.png b/docs/source/tutorial/images/explorer_autocomplete.png deleted file mode 100644 index 8b3f90af56..0000000000 Binary files a/docs/source/tutorial/images/explorer_autocomplete.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_book_trips_starter.png b/docs/source/tutorial/images/explorer_book_trips_starter.png deleted file mode 100644 index 34b995bf17..0000000000 Binary files a/docs/source/tutorial/images/explorer_book_trips_starter.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_book_with_trip_id_singular.png b/docs/source/tutorial/images/explorer_book_with_trip_id_singular.png deleted file mode 100644 index ceb33f9969..0000000000 Binary files a/docs/source/tutorial/images/explorer_book_with_trip_id_singular.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_book_with_trip_ids.png b/docs/source/tutorial/images/explorer_book_with_trip_ids.png deleted file mode 100644 index e28ab4aeeb..0000000000 Binary files a/docs/source/tutorial/images/explorer_book_with_trip_ids.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_cancel_trip_mutation.png b/docs/source/tutorial/images/explorer_cancel_trip_mutation.png deleted file mode 100644 index 6c9bd80cb1..0000000000 Binary files a/docs/source/tutorial/images/explorer_cancel_trip_mutation.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_check_cursor.png b/docs/source/tutorial/images/explorer_check_cursor.png deleted file mode 100644 index 0db0c03f0f..0000000000 Binary files a/docs/source/tutorial/images/explorer_check_cursor.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_details_renamed.png b/docs/source/tutorial/images/explorer_details_renamed.png deleted file mode 100644 index 2cee405dd0..0000000000 Binary files a/docs/source/tutorial/images/explorer_details_renamed.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_initial_added_query.png b/docs/source/tutorial/images/explorer_initial_added_query.png deleted file mode 100644 index 5f5e574e72..0000000000 Binary files a/docs/source/tutorial/images/explorer_initial_added_query.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_launch_detail_result.png b/docs/source/tutorial/images/explorer_launch_detail_result.png deleted file mode 100644 index 8f3ed84dd3..0000000000 Binary files a/docs/source/tutorial/images/explorer_launch_detail_result.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_launch_list_initial_response.png b/docs/source/tutorial/images/explorer_launch_list_initial_response.png deleted file mode 100644 index d0ea9adefa..0000000000 Binary files a/docs/source/tutorial/images/explorer_launch_list_initial_response.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_launch_list_rename.png b/docs/source/tutorial/images/explorer_launch_list_rename.png deleted file mode 100644 index 5d0a602e09..0000000000 Binary files a/docs/source/tutorial/images/explorer_launch_list_rename.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_launch_query_start.png b/docs/source/tutorial/images/explorer_launch_query_start.png deleted file mode 100644 index 1e30702c0e..0000000000 Binary files a/docs/source/tutorial/images/explorer_launch_query_start.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_launches_drill_in.png b/docs/source/tutorial/images/explorer_launches_drill_in.png deleted file mode 100644 index d07ea24ab3..0000000000 Binary files a/docs/source/tutorial/images/explorer_launches_drill_in.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_login_email_added.png b/docs/source/tutorial/images/explorer_login_email_added.png deleted file mode 100644 index dd23eefab0..0000000000 Binary files a/docs/source/tutorial/images/explorer_login_email_added.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_login_mutation_rename.png b/docs/source/tutorial/images/explorer_login_mutation_rename.png deleted file mode 100644 index 246c24ea60..0000000000 Binary files a/docs/source/tutorial/images/explorer_login_mutation_rename.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_meatball_copy.png b/docs/source/tutorial/images/explorer_meatball_copy.png deleted file mode 100644 index 2aea9dc790..0000000000 Binary files a/docs/source/tutorial/images/explorer_meatball_copy.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_new_tab.png b/docs/source/tutorial/images/explorer_new_tab.png deleted file mode 100644 index 531fe29668..0000000000 Binary files a/docs/source/tutorial/images/explorer_new_tab.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_query_list.png b/docs/source/tutorial/images/explorer_query_list.png deleted file mode 100644 index ea68d9e93a..0000000000 Binary files a/docs/source/tutorial/images/explorer_query_list.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_rocket_back.png b/docs/source/tutorial/images/explorer_rocket_back.png deleted file mode 100644 index 6a95fd0da5..0000000000 Binary files a/docs/source/tutorial/images/explorer_rocket_back.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_rocket_drill_in.png b/docs/source/tutorial/images/explorer_rocket_drill_in.png deleted file mode 100644 index 9c7134d1b8..0000000000 Binary files a/docs/source/tutorial/images/explorer_rocket_drill_in.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_sandbox_open.png b/docs/source/tutorial/images/explorer_sandbox_open.png deleted file mode 100644 index fc9bdff6fd..0000000000 Binary files a/docs/source/tutorial/images/explorer_sandbox_open.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_submit_operation.png b/docs/source/tutorial/images/explorer_submit_operation.png deleted file mode 100644 index ab724262fb..0000000000 Binary files a/docs/source/tutorial/images/explorer_submit_operation.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_subscription_success.png b/docs/source/tutorial/images/explorer_subscription_success.png deleted file mode 100644 index 977afd795d..0000000000 Binary files a/docs/source/tutorial/images/explorer_subscription_success.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_subscriptions_listening.png b/docs/source/tutorial/images/explorer_subscriptions_listening.png deleted file mode 100644 index 0290c15f70..0000000000 Binary files a/docs/source/tutorial/images/explorer_subscriptions_listening.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_trip_cancelled.png b/docs/source/tutorial/images/explorer_trip_cancelled.png deleted file mode 100644 index e245d44287..0000000000 Binary files a/docs/source/tutorial/images/explorer_trip_cancelled.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_tripsbooked_initial.png b/docs/source/tutorial/images/explorer_tripsbooked_initial.png deleted file mode 100644 index 1a96d57f41..0000000000 Binary files a/docs/source/tutorial/images/explorer_tripsbooked_initial.png and /dev/null differ diff --git a/docs/source/tutorial/images/explorer_tripsbooked_renamed.png b/docs/source/tutorial/images/explorer_tripsbooked_renamed.png deleted file mode 100644 index 0cb482cee0..0000000000 Binary files a/docs/source/tutorial/images/explorer_tripsbooked_renamed.png and /dev/null differ diff --git a/docs/source/tutorial/images/installed_dependencies.png b/docs/source/tutorial/images/installed_dependencies.png deleted file mode 100644 index a437f5fc92..0000000000 Binary files a/docs/source/tutorial/images/installed_dependencies.png and /dev/null differ diff --git a/docs/source/tutorial/images/interceptor_breakpoint.png b/docs/source/tutorial/images/interceptor_breakpoint.png deleted file mode 100644 index 9047c92929..0000000000 Binary files a/docs/source/tutorial/images/interceptor_breakpoint.png and /dev/null differ diff --git a/docs/source/tutorial/images/launch_list_final.png b/docs/source/tutorial/images/launch_list_final.png deleted file mode 100644 index 98b4eb2a43..0000000000 Binary files a/docs/source/tutorial/images/launch_list_final.png and /dev/null differ diff --git a/docs/source/tutorial/images/launches_detail.png b/docs/source/tutorial/images/launches_detail.png deleted file mode 100644 index 8da6a63d98..0000000000 Binary files a/docs/source/tutorial/images/launches_detail.png and /dev/null differ diff --git a/docs/source/tutorial/images/list_all_loaded.png b/docs/source/tutorial/images/list_all_loaded.png deleted file mode 100644 index 87454187d3..0000000000 Binary files a/docs/source/tutorial/images/list_all_loaded.png and /dev/null differ diff --git a/docs/source/tutorial/images/list_sites_success.png b/docs/source/tutorial/images/list_sites_success.png deleted file mode 100644 index 132f6e2103..0000000000 Binary files a/docs/source/tutorial/images/list_sites_success.png and /dev/null differ diff --git a/docs/source/tutorial/images/login_mutation_email.png b/docs/source/tutorial/images/login_mutation_email.png deleted file mode 100644 index ef05d27baa..0000000000 Binary files a/docs/source/tutorial/images/login_mutation_email.png and /dev/null differ diff --git a/docs/source/tutorial/images/login_mutation_null.png b/docs/source/tutorial/images/login_mutation_null.png deleted file mode 100644 index 60f1623a7d..0000000000 Binary files a/docs/source/tutorial/images/login_mutation_null.png and /dev/null differ diff --git a/docs/source/tutorial/images/new_run_script_phase.png b/docs/source/tutorial/images/new_run_script_phase.png deleted file mode 100644 index 9f39140a28..0000000000 Binary files a/docs/source/tutorial/images/new_run_script_phase.png and /dev/null differ diff --git a/docs/source/tutorial/images/next_minor.png b/docs/source/tutorial/images/next_minor.png deleted file mode 100644 index f7966441fa..0000000000 Binary files a/docs/source/tutorial/images/next_minor.png and /dev/null differ diff --git a/docs/source/tutorial/images/open_in_explorer_launches.png b/docs/source/tutorial/images/open_in_explorer_launches.png deleted file mode 100644 index cedbafd1d8..0000000000 Binary files a/docs/source/tutorial/images/open_in_explorer_launches.png and /dev/null differ diff --git a/docs/source/tutorial/images/open_starter_project.png b/docs/source/tutorial/images/open_starter_project.png deleted file mode 100644 index 5a066ccb13..0000000000 Binary files a/docs/source/tutorial/images/open_starter_project.png and /dev/null differ diff --git a/docs/source/tutorial/images/placeholder_in_asset_catalog.png b/docs/source/tutorial/images/placeholder_in_asset_catalog.png deleted file mode 100644 index 23b19e65ed..0000000000 Binary files a/docs/source/tutorial/images/placeholder_in_asset_catalog.png and /dev/null differ diff --git a/docs/source/tutorial/images/placeholder_logo.png b/docs/source/tutorial/images/placeholder_logo.png deleted file mode 100644 index 3bade6d6d2..0000000000 Binary files a/docs/source/tutorial/images/placeholder_logo.png and /dev/null differ diff --git a/docs/source/tutorial/images/rename_run_script.png b/docs/source/tutorial/images/rename_run_script.png deleted file mode 100644 index 1dfe215821..0000000000 Binary files a/docs/source/tutorial/images/rename_run_script.png and /dev/null differ diff --git a/docs/source/tutorial/images/sandbox_green_dot.png b/docs/source/tutorial/images/sandbox_green_dot.png deleted file mode 100644 index 21db0c26a4..0000000000 Binary files a/docs/source/tutorial/images/sandbox_green_dot.png and /dev/null differ diff --git a/docs/source/tutorial/images/sandbox_landing.png b/docs/source/tutorial/images/sandbox_landing.png deleted file mode 100644 index 3fccf6e94a..0000000000 Binary files a/docs/source/tutorial/images/sandbox_landing.png and /dev/null differ diff --git a/docs/source/tutorial/images/sandbox_schema_book_trips.png b/docs/source/tutorial/images/sandbox_schema_book_trips.png deleted file mode 100644 index 1f0f16a02a..0000000000 Binary files a/docs/source/tutorial/images/sandbox_schema_book_trips.png and /dev/null differ diff --git a/docs/source/tutorial/images/sandbox_schema_mutations.png b/docs/source/tutorial/images/sandbox_schema_mutations.png deleted file mode 100644 index c43a0be03e..0000000000 Binary files a/docs/source/tutorial/images/sandbox_schema_mutations.png and /dev/null differ diff --git a/docs/source/tutorial/images/sandbox_schema_reference.png b/docs/source/tutorial/images/sandbox_schema_reference.png deleted file mode 100644 index 714cad3aec..0000000000 Binary files a/docs/source/tutorial/images/sandbox_schema_reference.png and /dev/null differ diff --git a/docs/source/tutorial/images/schema_icon.png b/docs/source/tutorial/images/schema_icon.png deleted file mode 100644 index a4697e535c..0000000000 Binary files a/docs/source/tutorial/images/schema_icon.png and /dev/null differ diff --git a/docs/source/tutorial/images/schema_login_definition.png b/docs/source/tutorial/images/schema_login_definition.png deleted file mode 100644 index 742777ffb6..0000000000 Binary files a/docs/source/tutorial/images/schema_login_definition.png and /dev/null differ diff --git a/docs/source/tutorial/images/schema_tripsBooked_definition.png b/docs/source/tutorial/images/schema_tripsBooked_definition.png deleted file mode 100644 index 6383070c53..0000000000 Binary files a/docs/source/tutorial/images/schema_tripsBooked_definition.png and /dev/null differ diff --git a/docs/source/tutorial/images/screenshot_trip_booked.png b/docs/source/tutorial/images/screenshot_trip_booked.png deleted file mode 100644 index 0ade3cf4d6..0000000000 Binary files a/docs/source/tutorial/images/screenshot_trip_booked.png and /dev/null differ diff --git a/docs/source/tutorial/images/select_libs.png b/docs/source/tutorial/images/select_libs.png deleted file mode 100644 index 7133c99287..0000000000 Binary files a/docs/source/tutorial/images/select_libs.png and /dev/null differ diff --git a/docs/source/tutorial/images/select_target.png b/docs/source/tutorial/images/select_target.png deleted file mode 100644 index bd59453efc..0000000000 Binary files a/docs/source/tutorial/images/select_target.png and /dev/null differ diff --git a/docs/source/tutorial/images/stock_detail_view.png b/docs/source/tutorial/images/stock_detail_view.png deleted file mode 100644 index 22eeec12f7..0000000000 Binary files a/docs/source/tutorial/images/stock_detail_view.png and /dev/null differ diff --git a/docs/source/tutorial/images/success_log_barf.png b/docs/source/tutorial/images/success_log_barf.png deleted file mode 100644 index 4af668b431..0000000000 Binary files a/docs/source/tutorial/images/success_log_barf.png and /dev/null differ diff --git a/docs/source/tutorial/images/tap_to_load_more.png b/docs/source/tutorial/images/tap_to_load_more.png deleted file mode 100644 index 464ed1dbcc..0000000000 Binary files a/docs/source/tutorial/images/tap_to_load_more.png and /dev/null differ diff --git a/docs/source/tutorial/tutorial-add-sdk.md b/docs/source/tutorial/tutorial-add-sdk.md deleted file mode 100644 index 31c6af76fd..0000000000 --- a/docs/source/tutorial/tutorial-add-sdk.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: "1. Add the Apollo SDK" ---- - -In this step, you'll add the Apollo iOS SDK to a new project. - -## Open the Xcode project - -In the files you've downloaded or checked out from [the tutorial repo](https://github.com/apollographql/iOSTutorial), there are `starter` and `final` folders. Open the `RocketReserver.xcodeproj` file located in the `starter` folder: - -Folder structure for opening project - -When the project opens, Swift Package Manager (SPM) will resolve two dependencies that you'll be using later in the project that are already set up. - -Next, it's time to add Apollo as a dependency. - -## Add the Apollo iOS SDK to your project - -1. Go to **File > Add Packages...**. The Add Package dialog appears, by default with Apple packages. In the upper left hand corner, paste `https://github.com/apollographql/apollo-ios` into the search bar in the upper right: - - The Xcode add package dialog, arrow pointing at search bar - -2. Hit **Return** to kick off the search. Xcode will then show you the `apollo-ios` package and allow you to select a version in the right hand panel. Select **Up to Next Minor** from the Version dropdown (because the Apollo iOS SDK is still a `0.x` release, breaking changes _can_ occur between minor versions): - - Select next minor in dropdown - - > NOTE: There's a bug in the initial release of Xcode 13 showing the most recent minor version as 0.3.0 instead of 0.49.0, which it was at the time of writing. Please consult the [releases page on the SDK repo](https://github.com/apollographql/apollo-ios/releases) to see what our latest version is until this bug is fixed. - -5. Click **Add Package**. Once SPM is done checking out the package, a list of framework targets included in the library appears. For this tutorial, select the main **Apollo** target and the **ApolloWebSocket** target: - - Select the first and last targets - - _Note: Do **not** select the `Apollo-Dynamic` target, this is only for use for projects linking to our library dynamically. Most projects, including this one, will not need to do this._ - -6. Click **Finish**. SPM fetches your dependencies. When it completes, you can see them in the project navigator: - - Screenshot of installed dependencies - -> **Note:** Because SPM has not yet implemented [Target-Based Dependency Resolution](https://github.com/apple/swift-evolution/blob/master/proposals/0226-package-manager-target-based-dep-resolution.md), you'll see the `SQLite` dependency even though you didn't select `ApolloSQLite`, the target which depends on it. - -## Learn what you need to generate code - -Now that you've got the SDK set up, there are two more pieces you need to actually generate code. - -The first is the **GraphQL Schema**, which you can generally get from your server or from Apollo Studio Sandbox. This is a list of all of the possible queries and data types that are available to you from your server. The schema can be thought of as a contract of what it's *possible* to ask for. - -The second is at least one operation, so that we know what you're *actually* asking for. Apollo generates code by taking your operations, validating that they are actually possible by comparing them to the schema, and then using data from the schema to generate all of the data structures necessary to create operations type-safely, and parse the responses from those operations type-safely. - -The most basic way to think about this is the following equation: - -**Schema + Operations = Code** - -If you don't have any operations, our code generator won't know what information you want to ask for, so it can't generate the code to send a request or parse a result. If you don't have a schema, our code generator won't know if what you want to ask for is possible, so it can't guarantee type safety. If you have both, the appropriate checks can be made and type-safe code can be generated. - -Now that you know what you need and why you need it, the next step is to [obtain a local copy of your GraphQL schema](./tutorial-obtain-schema). diff --git a/docs/source/tutorial/tutorial-authentication.md b/docs/source/tutorial/tutorial-authentication.md deleted file mode 100644 index 154e160123..0000000000 --- a/docs/source/tutorial/tutorial-authentication.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: 7. Enable authentication ---- - -In this section, you'll add the ability to log in to the example server and obtain a token that your client can use to make identified requests. - -> **Note**: The way you log in to this particular server might differ from the way you log in with your own server. Login is often handled by _middleware_, or a layer totally separate from GraphQL. -> -> Regardless of how you obtain the token from your server, you'll usually send it back to the server the same way as demonstrated in the next part of this tutorial. - -## Create a login mutation - -A **mutation** is an operation that changes state on your server. In this case, the mutation changes back-end state by creating a session tied to a particular user of your client. - -Open [your Sandbox Explorer](https://studio.apollographql.com/sandbox/explorer?endpoint=https%3A%2F%2Fapollo-fullstack-tutorial.herokuapp.com%2Fgraphql) and click on the plus symbol to add a new tab. Next, click on the Schema icon to get back to looking at your schema, and select "Mutation" to look at your list of mutations: - -The list of available mutations - -Scroll down to take a look at the `login` mutation: - -The definition of login in the schema - -Click the play button to the right to open that mutation in the Explorer tab. When it opens, click the plus sign to add the operation: - -The login mutation after initially being added - -Sandbox Explorer tries to be helpful by adding the word `Mutation` after the word `Login`, but the iOS SDK also does that for you - so you'd wind up with a `LoginMutationMutation`. Rename the operation `Login` instead: - -The renamed operation - -Notice that there are no brackets after the call to the `login` mutation - this is because the type returned by this mutation is `String`, which is known as a **scalar type**. This means it won't have properties the way an object would, so you don't need to specify what properties you want returned to you. - -You'll also notice that `email` wasn't automatically added as an argument even though it doesn't seem to have a default value: That's because `email` is of type `String` - which remember, in GraphQL, means that it's **not** required (although obviously you won't get too far without it). - -Click the plus sign next to the `email` argument to have that argument added: - -The operation with the email argument - -You'll also notice that Sandbox Explorer has added a variable to your "Variables" section to match the login email. - -Click the Submit Operation button your mutation. You'll see that since you sent `null` for the email address, you get back `null` for the login: - -Results of passing a null email - -Now, replace `null` in the Query Variables section with an actual email address: - -```json:title=(Sandbox%20Explorer) -{ "loginEmail": "me@example.com" } -``` - -Press the Submit Operation button, and this time you'll get an actual response: - -Results of passing an actual email - -Next, copy the operation, either manually or using the meatball menu's "Copy operation" option. - -Open Xcode, create a new empty file named `Login.graphql`, and paste the operation into it. Build your project to make sure the codegen adds the mutation to your `API.swift` file. - -## Define login logic - -Now it's time to actually log the user in, using `LoginViewController.swift`. You'll notice in the `IBAction` for `submitTapped`, we're doing some very basic validation that the user has actually entered an email address before submitting it. - -Still in `submitTapped`, replace the `TODO` with a call to perform the login mutation: - -```swift title="LoginViewController.swift" - Network.shared.apollo.perform(mutation: LoginMutation(loginEmail: email)) { [weak self] result in - defer { - // Re-enable the submit button when this scope exits - self?.enableSubmitButton(true) - } - - switch result { - case .failure(let error): - self?.showAlert(title: "Network Error", - message: error.localizedDescription) - case .success(let graphQLResult): - - if let token = graphQLResult.data?.login { - // TODO: Store the token securely - } - - if let errors = graphQLResult.errors { - let message = errors - .map { $0.localizedDescription } - .joined(separator: "\n") - self?.showAlert(title: "GraphQL Error(s)", - message: message) - } - } -} -``` - - -Next, you need to store the login credential that's returned by the server. Login credentials should always be stored in the Keychain, but interacting with it directly is challenging, so you'll be using the `KeychainSwift` library which has already been added as a Swift Package to this project. - -At the top of `LoginViewController.swift`, import the `KeychainSwift` library: - -```swift title="LoginViewController.swift" -import KeychainSwift -``` - -Next, note that there's a `static let` at the top of the view controller that will give you a value you can use to query the keychain for a login token. Because this is a `static let`, you can use it outside instances of `LoginViewController` (which you will do in a second). - -Replace the `TODO` after unwrapping the token with the following: - -```swift title="LoginViewController.swift" -let keychain = KeychainSwift() -keychain.set(token, forKey: LoginViewController.loginKeychainKey) -self?.dismiss(animated: true) -``` - -With this code, once you log in successfully, the token will be stored in the keychain, and then the `LoginViewController` will automatically dismiss (if it still exists). This will send you back to the `DetailViewController`. - -## Display the login screen - -Now, it's time to show the login view controller whenever someone attempts to book a trip without being logged in. - -At the top of `DetailViewController.swift`, import the `KeychainSwift` library: - -```swift title="DetailViewController.swift" -import KeychainSwift -``` - -Then, find the `isLoggedIn` method and replace its contents with the following: - -```swift title="DetailViewController.swift" -private func isLoggedIn() -> Bool { - let keychain = KeychainSwift() - return keychain.get(LoginViewController.loginKeychainKey) != nil -} -``` - -This code checks if there is any value stored in the keychain under the login keychain key. If there isn't, it determines the user isn't logged in. If there is, the user is logged in. - -Find the `bookOrCancelTapped` method and start by determining what to do if the user is logged in or not: - -```swift title="DetailViewController.swift" -@IBAction private func bookOrCancelTapped() { - guard self.isLoggedIn() else { - self.performSegue(withIdentifier: "showLogin", sender: self) - return - } - - // TODO: Book or cancel the trip -} -``` - -Then, replace the `TODO` in the above code with logic to figure out whether a trip on the current launched needs to be booked or cancelled: - -```swift title="DetailViewController.swift" -guard let launch = self.launch else { - // We don't have enough information yet to know - // if we're booking or cancelling, bail. - return -} - -if launch.isBooked { - print("Cancel trip!") -} else { - print("Book trip!") -} -``` - -Build and run the application, and select a launch from the list to view its detail screen. Now when you tap the "Book now!" button, the `LoginViewController` will appear. Use it to log yourself in. - -When the `DetailViewController` reappears, if you tap the "Book now!" button again, you'll see the print statement you added logging happily to the console: - -Console with book trip printed out - -In the next step, you'll [use your login token in a mutation to book yourself a trip](./tutorial-mutations)! diff --git a/docs/source/tutorial/tutorial-detail-view.md b/docs/source/tutorial/tutorial-detail-view.md deleted file mode 100644 index a7caf3d676..0000000000 --- a/docs/source/tutorial/tutorial-detail-view.md +++ /dev/null @@ -1,242 +0,0 @@ ---- -title: "6. Complete the detail view" ---- - -To get more information to show on the detail page, you have a couple of options: - -- You could request all the details you want to display for every single launch in the `LaunchList` query, and then pass that retrieved object on to the `DetailViewController`. -- You could provide the identifier of an individual launch to a _different_ query to request all the details you want to display. - -The first option *can* seem easier if there isn't a substantial difference in size between what you're requesting for the list versus the detail page. - -However, remember that one of the advantages of GraphQL is that you can query for _exactly_ the data you need to display on a page. If you're not going to be displaying additional information, you can save bandwidth, execution time, and battery life by not asking for data until you need it. - -This is especially true when you have a *much* larger query for your detail view than for your list view. Passing the identifier and then fetching based on that is considered a best practice. Even though the amount of data in this case doesn't differ greatly, you'll build out a query to help fetch details based on the ID so you'll know how to do it in the future. - -Create a new empty file and name it `LaunchDetails.graphql`. In this file, you'll add the details you want to display in the detail view. First, you'll want to go back to [your Sandbox](https://studio.apollographql.com/sandbox/explorer?endpoint=https%3A%2F%2Fapollo-fullstack-tutorial.herokuapp.com%2Fgraphql) and make sure that your query works! - -In the Explorer tab, start by clicking the "New Tab" button in the middle operations section: - -the new tab button - -A new tab will be added with nothing in it: - -The UI after adding a new tab - -In the left-hand column, click the word "Query" under "Documentation" to be brought to a list of possible queries: - -The list of possible queries - -Select the `launch` query by clicking the button next to it. Sandbox Explorer will automatically set up the query for you to use: - -What the launch query will look like immediately after adding it - -First, change the name of the operation from "Query" to "LaunchDetails" - that will then reflect in the tab name and make it easier to tell which query you're working with: - -The renamed query - -Let's go through what's been added here: - -- Again, we've added an operation, but this time it's got a parameter coming into it. This was added automatically by Sandbox Explorer because there is not a default value provided for the non-null `launchId` argument. -- The parameter is prefixed with a `$` for its name, and the type is indicated immediately after. Note that the `ID` type here has an exclamation point, meaning it can't be null. -- Within that operation, we make a call to the `launch` query. The `id` is the argument the query is expecting, and the `$launchId` is the name of the parameter we just passed in the line above. -- Again, there's blank space for you to add the fields you want to get details for on the returned object, which in this case is a `Launch`. -- Finally, at the bottom, the "Variables" section of the Operations panel has been expanded, and a dictionary has been added with a key of `"launchId"`. At runtime, this will be used to fill in the blank of the `$launchId` parameter. - - -> Note: GraphQL's assumptions about nullability are different from Swift's. In Swift, if you don't annotate a property's type with either a question mark or an exclamation point, that property is non-nullable. -> -> In GraphQL, if you don't annotate a field's type with an exclamation point, that field is considered *nullable*. This is because GraphQL fields are **nullable by default**. -> -> Keep this difference in mind when you switch between editing Swift and GraphQL files. - -Now, switch back to Sandbox Explorer. Start by using the checkboxes or typing to add the properties you're already requesting in the `LaunchList` query. One difference: Use `LARGE` for the mission patch size since the patch will be displayed in a much larger `ImageView`: - -```graphql:title=(Sandbox%20Explorer) -query LaunchDetails($id:ID!) { - launch(id: $id) { - id - site - mission { - name - missionPatch(size:LARGE) - } - } -} -``` - -Next, look in the left sidebar to see what other fields are available. Selecting `rocket` will add a set of brackets to request details about the rocket, and drill you into the `rocket` property, showing you the available fields on the `Rocket` type: - -The available properties for Rocket - -Click the buttons to check off `name` and `type`. Next, go back to `Launch` by clicking the back button next to the `Rocket` type in the left sidebar: - -The back button - -Finally, check off the `isBooked` property on the `Launch`. Your final query should look like this: - -```graphql:title=(Sandbox%20Explorer) -query LaunchDetails($launchId: ID!) { - launch(id: $launchId) { - id - site - mission { - name - missionPatch(size: LARGE) - } - rocket { - name - type - } - isBooked - } -} -``` - -At the bottom of the Operations section, update the Variables section to pass in an ID for a launch. In this case, it needs to be a string that contains a number: - -```json:title=(Sandbox%20Explorer) -{ "launchId": "25" } -``` - -This tells Sandbox Explorer to fill in the value of the `$launchId` variable with the value `"25"` when it runs the query. Press the big play button, and you should get some results back for the launch with ID 25: - -Detail request returning JSON - -Now that you've confirmed it worked, copy the query (either by selecting all the text or using the "Copy Operation" option from the meatball menu as before) and paste it into your `LaunchDetails.graphql` file. Build the application so that codegen picks up this new file and generates a new query type for it. - -Now that you know what you're planning to ask for, it's time to set up the UI for the detail screen. Go to `DetailViewController.swift`. First, add a place to hang on to the result of the query. Add the following property to the top of the class: - -```swift title="DetailViewController.swift" -private var launch: LaunchDetailsQuery.Data.Launch? -``` - -Next, update the `viewDidLoad` function to clear out anything from the storyboard before attempting to configure the view: - -```swift title="DetailViewController.swift" -override func viewDidLoad() { - super.viewDidLoad() - - self.missionNameLabel.text = "Loading..." - self.launchSiteLabel.text = nil - self.rocketNameLabel.text = nil - self.configureView() -} -``` - -Delete the existing contents of `configureView()`. In their place, start by adding a check that we have something to display, and a place to display it: - -```swift title="DetailViewController.swift" -guard - self.missionNameLabel != nil, - let launch = self.launch else { - return -} -``` - -Next, it's time to display all the information you've gotten from your GraphQL server. Remember that GraphQL properties are nullable by default, so you'll often need to provide handling for when a given property is `nil`. - -Add the following code below the `guard` statement you just added: - -```swift title="DetailViewController.swift" -self.missionNameLabel.text = launch.mission?.name -self.title = launch.mission?.name - -let placeholder = UIImage(named: "placeholder")! - -if let missionPatch = launch.mission?.missionPatch { - self.missionPatchImageView.sd_setImage(with: URL(string: missionPatch)!, placeholderImage: placeholder) -} else { - self.missionPatchImageView.image = placeholder -} - -if let site = launch.site { - self.launchSiteLabel.text = "Launching from \(site)" -} else { - self.launchSiteLabel.text = nil -} - -if - let rocketName = launch.rocket?.name , - let rocketType = launch.rocket?.type { - self.rocketNameLabel.text = "🚀 \(rocketName) (\(rocketType))" -} else { - self.rocketNameLabel.text = nil -} - -if launch.isBooked { - self.bookCancelButton.title = "Cancel trip" - self.bookCancelButton.tintColor = .red -} else { - self.bookCancelButton.title = "Book now!" - // Get the color from the main window rather than the view to prevent alerts from draining color - self.bookCancelButton.tintColor = UIApplication.shared.windows.first?.tintColor -} -``` - -Then, find the `loadLaunchDetails()` method. Replace the `TODO` with the following, which loads the details using the `LaunchDetailsQuery` you created earlier: - -```swift title="DetailViewController.swift" -private func loadLaunchDetails() { - guard - let launchID = self.launchID, - launchID != self.launch?.id else { - // This is the launch we're already displaying, or the ID is nil. - return - } - - Network.shared.apollo.fetch(query: LaunchDetailsQuery(launchId: launchID)) { [weak self] result in - guard let self = self else { - return - } - - switch result { - case .failure(let error): - self.showAlert(title: "Network Error", - message: error.localizedDescription) - case .success(let graphQLResult): - if let launch = graphQLResult.data?.launch { - self.launch = launch - } - - if let errors = graphQLResult.errors { - let message = errors - .map { $0.localizedDescription } - .joined(separator: "\n") - self.showAlert(title: "GraphQL Error(s)", - message: message) - } - } - } -} -``` - -Finally, update the `didSet` for `launchID` to load the launch details if we don't already have them: - -```swift title="DetailViewController.swift" -var launchID: GraphQLID? { - didSet { - self.loadLaunchDetails() - } -} -``` - -and add a `didSet` on the `launch` property to load the UI once the launch is actually loaded. - -```swift title="DetailViewController.swift" -private var launch: LaunchDetailsQuery.Data.Launch? { - didSet { - self.configureView() - } -} -``` - -Build and run the application. When you tap into the detail screen, you should now see the full details: - -Final display of the detail screen - -You'll notice that many of the more recent launches have a rocket type of `FT`. If you load more launches until you get to the end of the list, you'll get to some rockets that have different rocket types: - -Final display with different rocket type - -You may have noticed that the detail view includes a `Book Now!` button, but there's no way to book a seat yet. To fix that, let's [learn how to make changes to objects in your graph with mutations, including authentication](./tutorial-authentication). diff --git a/docs/source/tutorial/tutorial-execute-query.md b/docs/source/tutorial/tutorial-execute-query.md deleted file mode 100644 index 2c8e2ce97f..0000000000 --- a/docs/source/tutorial/tutorial-execute-query.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -title: "3. Execute your first query" ---- - -The most common GraphQL operation is the **query**, which requests data from your graph in a structure that conforms to your server's schema. If you return to [the Sandbox](https://studio.apollographql.com/sandbox/explorer?endpoint=https%3A%2F%2Fapollo-fullstack-tutorial.herokuapp.com/graphql%2Fgraphql) for your server, you can see available queries in the Schema Reference tab you opened earlier. - -Scroll down to the `launches` query to get details about it: - -Detail about launches query - -Here, you see both the query term itself, the return type, and information about parameters that can be passed to the query. You can use this information to write a query you'll eventually add to your app. - -To start working with this query in the Sandbox Explorer, select the "play" button to the right side of the information: - -Open in Explorer - -This brings you back into Sandbox's Explorer tab with the sidebar on the left showing documentation for the query you've selected: - -Docs open in the left sidebar - -Notice the small button next to the `launches` icon. Click this button to add the query to the middle "operations" panel: - -Click the button to add this query - -When the query is added, it will look like this: - -The query once it's been added to the Operations section - -Let's break down what you're seeing here: - -- The type of the operation, `query`, followed by the name of the operation, currently `Query` (we'll make that more specific in a second), is the outermost set of brackets. -- The actual query being called is the next set of brackets in. Since the `arguments` for this query both have default values, they are not automatically added to the query for you. -- An error in the empty space between the brackets, which is where you'll put the list of information you want back from each launch. - -The Apollo iOS SDK requires every query to have a name (even though this isn't required by the GraphQL spec). Since you're going to be creating more than one query, it's also a good idea to give this operation a specific name other than `Query`. Change the name of the operation to `LaunchList`: - -Renaming the query - -Next, on the left hand side, you can select what fields you want back in the returned object. Start by clicking the button next to the `cursor` field. It will mark that field as selected, then insert it into your operations: - -After adding the cursor field. - -This is probably the easiest way to add fields to your object, since it knows how everything is spelled and what type everything is. - -However, you can also use auto-complete to help you with this. Add a newline below `cursor` in the Operations panel and start typing `ha`. An autocomplete box pops up and shows you options based on what's in the schema: - -Example of autocomplete - -The Sandbox Explorer is a great tool for building and verifying queries so you don't have to repeatedly rebuild your project in Xcode to try out changes. - -As the schema indicates, the `launches` query returns a `LaunchConnection` object. This object includes a list of launches, along with fields related to pagination (`cursor` and `hasMore`). The query you've written so far indicates exactly which fields of this `LaunchConnection` object you want to be returned. - -Run this query by pressing the "Submit Operation" button, which should now have the name of your query, `LaunchList`: - -Submit the operation - -You'll quickly see the query returns results as a JSON object on the right-hand side of the page: - -Query JSON in Sandbox Explorer - -This query executes successfully, but it doesn't include any information about the `launches`! That's because we didn't include the necessary field in the query. - -Click the button next to the `launches` field at the bottom of the left column. It will add a set of braces for `launches` to the operations section, and then move the documentation to show information for the `Launch` type: - -Status after adding launches field - -The fields you add in this set of brackets will be fetched for every launch in the list. Click the buttons next to `id` and `site` properties to add those two fields. When you're done, your operation should look like this: - -```graphql:title=(Sandbox%20Explorer) -query LaunchList { - launches { - cursor - hasMore - launches { - id - site - } - } -} -``` - -Run the operation again, and you'll now see that in addition to the information you got back before, you're also getting a list of launches with their ID and site information: - -Updated query JSON in Sandbox Explorer - -## Adding your query to Xcode - -Now that your query is fetching the right data, head back to Xcode. - -1. Go to **File > New > File...** and select the **Empty** file template: - -Empty file template - -2. Click **Next** and name the file `LaunchList.graphql`. Make sure it's saved at the same level as your `schema.json` file. As previously, don't add it to any target. - -3. Copy your final operation from Sandbox Explorer by selecting the three dot (aka "meatball") menu to the right of your operation name and selecting "Copy Operation": - -Copy operation from Explorer Sandbox - -4. Paste the copied operation into `LaunchList.graphql` - -You're now ready to generate code from the combination of your saved query and schema. - -## Running code generation - -1. Return to your project's **Apollo** Run Script build phase. Comment out the line that you added to the bottom (that includes `schema:download`). The schema isn't changing between builds, which means you don't need to refetch it. - -2. _Uncomment_ the line you previously commented out (that includes `codegen:generate`). - -3. Build your project. When the build completes, an `API.swift` file appears in the same folder as `schema.json`. - -4. Drag the `API.swift` file into Xcode. This time, **do** check the **Add to target** box for the `RocketReserver` app. You include this file in your application's bundle to enable you to execute the query you defined. - -### The `API.swift` file - -Open the `API.swift` file. It defines a root class, `LaunchListQuery`, with many nested structs below it. If you compare the structs to the JSON data returned in Sandbox Explorer, you see that the structure matches. These structs include properties only for the fields that your query requests. - -Try commenting out the `id` property in `LaunchList.graphql` using a `#`, saving, then building again. When the build completes, the innermost `Launch` now only includes the built-in `__typename` and the requested `site` property. - -Uncomment `id` in `LaunchList.graphql` and rebuild to restore the property. - -Now that you've generated code and had a chance to see what's in there, it's time to get everything working end to end! - -## Running a test query - -To use the generated operations in `API.swift`, you first create an instance of `ApolloClient`. This instance takes your generated code and uses it to make network calls to your server. It's recommended that this instance is a singleton or static instance that's accessible from anywhere in your codebase. - -1. Create a new Swift file called `Network.swift` and copy the code from [Basic client creation](../initialization/#basic-client-creation) into it. Make sure to add `import Apollo` to the top of the file. - -2. Update the URL string to be `https://apollo-fullstack-tutorial.herokuapp.com/graphql` instead of the `localhost` URL in the example. - -3. To make sure your `ApolloClient` instance is communicating correctly with the server, add the following code to `AppDelegate.swift` in the `application:didFinishLaunchingWithOptions` method, above `return true`: - - ```swift title="AppDelegate.swift" - Network.shared.apollo.fetch(query: LaunchListQuery()) { result in - switch result { - case .success(let graphQLResult): - print("Success! Result: \(graphQLResult)") - case .failure(let error): - print("Failure! Error: \(error)") - } - } - ``` - -Build and run your application. The web host might take a few seconds to spin up your GraphQL server if nobody's been using it recently, but once it's up, you should see a response that resembles the following: - -Success log output - -You're now successfully fetching data from the network using generated code! Now it's time to move on to [displaying query results in your UI](./tutorial-query-ui). diff --git a/docs/source/tutorial/tutorial-introduction.md b/docs/source/tutorial/tutorial-introduction.md deleted file mode 100644 index f33760dfa2..0000000000 --- a/docs/source/tutorial/tutorial-introduction.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: "0. Introduction" ---- - -Welcome! This tutorial demonstrates adding the Apollo iOS SDK to an app to communicate with a GraphQL server. It is confirmed to work with the following tools: - -- Xcode 13.2 -- Swift 5.6 -- Apollo iOS SDK 0.50.0 - -The tutorial assumes that you're using a Mac with Xcode installed. It also assumes some prior experience with iOS development. - -> If you encounter any issues during the tutorial, feel free to ask questions by either [opening an issue on our GitHub repo](https://github.com/apollographql/apollo-ios/issues) or [stopping by our community forums for help](https://community.apollographql.com). - -## What are you building? - -This tutorial takes you through building an app to "book a seat" on any of the rockets that have been sent into space by [SpaceX](https://www.spacex.com/). Along the way, you'll build out functionality that uses the following features of the Apollo iOS SDK: - -* Schema downloading -* Code generation -* Queries and mutations -* Error handling -* Subscriptions - -A pre-built GraphQL server is provided for your app to execute operations against. - -Before you start, you should either check out or download the contents of the iOS tutorial repository at [https://github.com/apollographql/iOSTutorial](https://github.com/apollographql/iOSTutorial). There's a "starter" folder where you'll begin and a "final" folder that shows what the app will wind up looking like when it's complete. - -## Ready to start? - -[🚀 Let's go! 🚀](./tutorial-add-sdk) diff --git a/docs/source/tutorial/tutorial-mutations.md b/docs/source/tutorial/tutorial-mutations.md deleted file mode 100644 index 68e5f528e1..0000000000 --- a/docs/source/tutorial/tutorial-mutations.md +++ /dev/null @@ -1,352 +0,0 @@ ---- -title: 8. Define additional mutations ---- - -In this section, you'll learn how to build authenticated mutations and handle information returned from those mutations, enabling you to book and cancel trips in your app. - -## Add authentication handling - -Before you can book a trip, you need to be able to pass your authentication token along to the example server. To do that, let's dig a little deeper into how iOS's `ApolloClient` works. - -The `ApolloClient` uses something called a `NetworkTransport` under the hood. By default, the client creates a `RequestChainNetworkTransport` instance to handle talking over HTTP to your server. - -A `RequestChain` runs your request through an array of `ApolloInterceptor` objects which can mutate the request and/or check the cache before it hits the network, and then do additional work after a response is received from the network. - -The `RequestChainNetworkTransport` uses an object that conforms to the `InterceptorProvider` protocol in order to create that array of interceptors for each operation it executes. There are a couple of providers that are set up by default, which return a fairly standard array of interceptors. - -The nice thing is that you can also add your own interceptors to the chain anywhere you need to perform custom actions. In this case, you want to have an interceptor that will add your token. - -First, create the new interceptor. Go to **File > New > File...** and create a new **Swift File**. Name it **TokenAddingInterceptor.swift**, and make sure it's added to the **RocketReserver** target. Open that file, and add the following code: - -```swift title="TokenAddingInterceptor.swift" -import Foundation -import Apollo - -class TokenAddingInterceptor: ApolloInterceptor { - func interceptAsync( - chain: RequestChain, - request: HTTPRequest, - response: HTTPResponse?, - completion: @escaping (Result, Error>) -> Void) { - - // TODO - } -} -``` - -Next, import `KeychainSwift` at the top of the file so you can access the key you stored in the keychain in the last step of the tutorial: - -```swift title="TokenAddingInterceptor.swift" -import KeychainSwift -``` - -Then, replace the `TODO` within the `interceptAsync` method with code to get the token from the keychain, and add it to your headers if it exists: - -```swift title="TokenAddingInterceptor.swift" -let keychain = KeychainSwift() -if let token = keychain.get(LoginViewController.loginKeychainKey) { - request.addHeader(name: "Authorization", value: token) -} // else do nothing - -chain.proceedAsync(request: request, - response: response, - completion: completion) -``` - -An array of `ApolloInterceptor`s which are handed off to each request to perform in order is set up by an object conforming to the `InterceptorProvider` protocol. There's a `DefaultInterceptorProvider` which has an array with most of the Interceptors you'd want to use. - -You can also make your own object conforming to `InterceptorProvider` - or, in this case, since the interceptor only needs to be added to the beginning of the list to run before all the other interceptors, you can subclass the existing `DefaultInterceptorProvider`. - -Go to **File > New > File...** and create a new **Swift File**. Name it **NetworkInterceptorProvider.swift**, and make sure it's added to the **RocketReserver** target. Add code which inserts your `TokenAddingInterceptor` before the other interceptors provided by the `DefaultInterceptorProvider`: - -```swift title="NetworkInterceptorProvider.swift" -import Foundation -import Apollo - -class NetworkInterceptorProvider: DefaultInterceptorProvider { - override func interceptors(for operation: Operation) -> [ApolloInterceptor] { - var interceptors = super.interceptors(for: operation) - interceptors.insert(TokenAddingInterceptor(), at: 0) - return interceptors - } -} -``` - -> Another way to do this would be to copy and paste the list interceptors provided by the `DefaultInterceptorProvider` (which are all public), and then place your interceptors in the points in the array where you want them. However, since in this case we can run this interceptor first, it's simpler to subclass. - -Next, go back to your `Network` class. Replace the `ApolloClient` with an updated `lazy var` which creates the `RequestChainNetworkTransport` manually, using your custom interceptor provider: - -```swift title="Network.swift" -class Network { - static let shared = Network() - - private(set) lazy var apollo: ApolloClient = { - let client = URLSessionClient() - let cache = InMemoryNormalizedCache() - let store = ApolloStore(cache: cache) - let provider = NetworkInterceptorProvider(client: client, store: store) - let url = URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/graphql")! - let transport = RequestChainNetworkTransport(interceptorProvider: provider, - endpointURL: url) - return ApolloClient(networkTransport: transport, store: store) - }() -} -``` - -Now, go back to **TokenAddingInterceptor.swift**. -Click on the line numbers to add a breakpoint at the line where you're instantiating the `Keychain`: - -adding a breakpoint - -Build and run the application. Whenever a network request goes out, that breakpoint should now get hit. If you're logged in, your token will be sent to the server whenever you make a request! - -## Add the `BookTrip` mutation - -In [Sandbox](https://studio.apollographql.com/sandbox/explorer?endpoint=https%3A%2F%2Fapollo-fullstack-tutorial.herokuapp.com%2Fgraphql), open the Schema tab by clicking its icon, select the `Mutations`, and take a look at the `bookTrips` mutation: - -The docs for book trips - -Click the play button to the right to open this mutation in Explorer. Click the plus button to add the `bookTrips` mutation: - -The book trips operation immediately after adding it - -You can see in the left sidebar that this takes an argument of an array of IDs (which was added as `$bookTripsLaunchIds`), and the object returned from the operation has three properties: - -* A `success` boolean indicating whether the booking succeeded -* A `message` string to display to the user -* A list of `launches` the current user has booked - -Click the plus signs next to `success` and `message` to add those to your operation. - -In the "Variables" section of Sandbox Explorer, add an array of identifiers. In this case, we'll use a single identifier to book one trip: - -```json:title=(Sandbox%20Explorer) -{"bookTripsLaunchIds": ["25"]} -``` - -Next, directly next to the word "Variables", you'll see the word "Headers". Click that to bring up the headers section. Click the "New Header" button, and add "Authorization" in the header key text box and paste the token you got back in the last section for the value: - -The headers section - -Now, click the Submit Operation button to run your authorized query. You'll get back information regarding the trips (or in this case, trip) you've just booked. - -> Note: If you receive an error that says "Cannot read property 'id' of null", that means your user was not found based on the token you passed through. Make sure your authorization header is properly formatted and that you're actually logged in! - -Explorer showing the result of booking a trip with an array of IDs - -With a mutation written like this, you can book any number of trips you want at the same time. However, the booking mechanism in our application will only let you book one trip at a time. - -Luckily, there's an easy way to update the mutation so it's required to only take a single object. First, update the name of your operation in Explorer to the singular `BookTrip` (and remove `Mutation` since that will be added for us by code generation). Next, update the mutationto take a single `$id`, then pass an array containing that `$id` to the `bookTrips` mutation: - -```graphql:title=(Sandbox%20Explorer) -mutation BookTrip($id:ID!) { - bookTrips(launchIds:[$id]) { - success - message - } -} -``` - -This is helpful because the Swift code generation will now generate a method that only accepts a single `ID` instead of an array, but you'll still be calling the same mutation under the hood, without the backend needing to change anything. - -In the Variables section of Sandbox Explorer, update the JSON dictionary to use `id` as the key, and remove the array brackets from around the identifier: - -```json:title=(Sandbox%20Explorer) -{"id": "25"} -``` - -Click the Submit Operation button to run your updated query. The response you get back should be identical to the one you got earlier: - -The result of booking a trip with a single identifier - -Now that you've fleshed out your operation, it's time to put it into the app. Go to **File > New > File... > Empty**, and name this file `BookTrip.graphql`. Paste in the final query from the Sandbox Explorer. - -Build the application to run the code generation. Then, in `DetailViewController.swift`, fill in the `bookTrip` method with the code to book your trip based on the flight's ID: - -```swift title="DetailViewController.swift" -private func bookTrip(with id: GraphQLID) { - Network.shared.apollo.perform(mutation: BookTripMutation(id: id)) { [weak self] result in - guard let self = self else { - return - } - switch result { - case .success(let graphQLResult): - if let bookingResult = graphQLResult.data?.bookTrips { - // TODO - } - - if let errors = graphQLResult.errors { - // From UIViewController+Alert.swift - self.showAlertForErrors(errors) - } - case .failure(let error): - self.showAlert(title: "Network Error", - message: error.localizedDescription) - } - } -} -``` - - -Then, update the `cancelTrip` method print the ID of the flight being cancelled (you'll be adding the actual cancellation in the next step): - -```swift title="DetailViewController.swift" -private func cancelTrip(with id: GraphQLID) { - print("Cancel trip \(id)") - // TODO: Add code to cancel trip -} -``` - -Next, update the `bookOrCancelTapped` method to use the two methods you've just added instead of `print`ing: - -```swift title="DetailViewController.swift" -if launch.isBooked { - self.cancelTrip(with: launch.id) -} else { - self.bookTrip(with: launch.id) -} -``` - -In `bookTrip`, replace the `TODO` with code to handle what comes back in the `success` property: - -```swift title="DetailViewController.swift" -if bookingResult.success { - self.showAlert(title: "Success!", - message: bookingResult.message ?? "Trip booked successfully") -} else { - self.showAlert(title: "Could not book trip", - message: bookingResult.message ?? "Unknown failure.") -} -``` - -You've now got the code to book a trip. Before you run it, let's add the code to cancel a trip as well. - -## Add the `CancelTrip` mutation - -The process for the `CancelTrip` mutation is similar to the one for `BookTrip`. Go back to the Sandbox's Schema tab, select Mutations,e and look at the `cancelTrip` mutation's documentation: - -Documentation for the cancel trip mutation - -Click the play button to the right to open this operation in Explorer, add a new tab to Explorer for this new operation, then click the plus button to create your operation: - -Documentation for the cancel trip mutation - -Check off `success` and `message` again to add those properties to the list of ones you want to get back with your cancellation information. - -Again, Explorer's gotten a little verbose here, so update your operation's name and variables to be a little shorter: - -```graphql:title=(Sandbox%20Explorer) -mutation CancelTrip($id: ID!) { - cancelTrip(launchId: $id) { - success - message - } -} -``` - -One key difference from `bookTrips` is that you're only allowed to cancel one trip at a time because only one `ID!` is accepted as a parameter. - -In the Variables section of Sandbox Explorer, you can use the exact same JSON that you used for `BookTrip` (because it also used a single identifier called "id"): - -```json:title=(GraphiQL) -{"id": "25"} -``` - -Make sure that in the Headers section, you add your authorization token again (the token added to the tab with `BookTrip` won't carry over to this new tab): - -The headers section - -Click the Submit Operation button to cancel the trip, and you should see a successful request: - -Successful cancel trip request - -It works! Once again, go back to Xcode and create a new empty file, and name it `CancelTrip.graphql`. Paste in the final query from Sandbox Explorer. Build the application without running it to cause the code generation to see this new mutation and generate code for it. - -Next, go to the `cancelTrip(with id:)` method in `DetailViewController.swift`. Replace the `print` statement with code that makes the call to cancel the trip: - -```swift title="DetailViewController.swift" -Network.shared.apollo.perform(mutation: CancelTripMutation(id: id)) { [weak self] result in - guard let self = self else { - return - } - switch result { - case .success(let graphQLResult): - if let cancelResult = graphQLResult.data?.cancelTrip { - if cancelResult.success { - // TODO - } - } - - if let errors = graphQLResult.errors { - // From UIViewController+Alert.swift - self.showAlertForErrors(errors) - } - case .failure(let error): - self.showAlert(title: "Network Error", - message: error.localizedDescription) - } -} -``` - - -In `cancelTrip(with id:)`, replace the `TODO` with code to handle what comes back in that mutation's `success` property: - -```swift title="DetailViewController.swift" -if cancelResult.success { - self.showAlert(title: "Trip cancelled", - message: cancelResult.message ?? "Your trip has been officially cancelled.") -} else { - self.showAlert(title: "Could not cancel trip", - message: cancelResult.message ?? "Unknown failure.") -} -``` - -Build and run the application. Select any launch and try to book it. You'll get a success message, but you'll notice that the UI doesn't update, even if you go out of the detail view and back into it again. - -Why is that? Because the trip you've got stored locally in your cache still has the old value for `isBooked`. - -There are a number of ways to change this, a couple of which you'll learn in the next section. For now we'll focus on the one that requires the fewest changes to your code: re-fetching the booking info from the network. - -## Force a fetch from the network - -The `fetch` method of `ApolloClient` provides defaults for most of its parameters, so if you're using the default configuration, the only value you need to provide yourself is the `Query`. - -However, an important parameter to be aware of is the `cachePolicy`. By default, this has the value of `returnCacheDataElseFetch`, which does essentially what it says on the label: it looks in the current cache (by default an in-memory cache) for data, and fetches it from the network if it's not present. - -If the data *is* present, the default behavior is to return the local copy to prevent an unnecessary network fetch. However, this is sometimes not the desired behavior (especially after executing a mutation). - -There are [several different cache policies available to you](../caching/#specifying-a-cache-policy), but the easiest way to absolutely force a refresh from the network that still updates the cache is to use `fetchIgnoringCacheData`. This policy bypasses the cache when going to the network, but it also stores the results of the fetch in the cache for future use. - -Update the `loadLaunchDetails` method to take a parameter to determine if it should force reload. If it should force reload, update the cache policy from the default `.returnCacheDataElseFetch`, which will return data from the cache if it exists, to `.fetchIgnoringCacheData`: - -```swift title="DetailViewController.swift" -private func loadLaunchDetails(forceReload: Bool = false) { - guard - let launchID = self.launchID, - (forceReload || launchID != self.launch?.id) else { - // This is the launch we're already displaying, or the ID is nil. - return - } - - let cachePolicy: CachePolicy - if forceReload { - cachePolicy = .fetchIgnoringCacheData - } else { - cachePolicy = .returnCacheDataElseFetch - } - - Network.shared.apollo.fetch(query: LaunchDetailsQuery(launchId: launchID), cachePolicy: cachePolicy) { [weak self] result in - // (Handling of the network call's completion remains the same) - } -} -``` - -Next, add the following line to **both** the `bookingResult.success` and `cancelResult.success` branches in their respective methods before showing the alerts: - -```swift title="DetailViewController.swift" -self.loadLaunchDetails(forceReload: true) -``` - -Run the application. When you book or cancel a trip, the application will fetch the updated state and update the UI with the correct state. When you go out and back in, the cache will be updated with the most recent state, and the most recent state will display. - -In the next section, you'll learn how to use [subscriptions](./tutorial-subscriptions/) with the Apollo client. diff --git a/docs/source/tutorial/tutorial-obtain-schema.md b/docs/source/tutorial/tutorial-obtain-schema.md deleted file mode 100644 index 64462b4caf..0000000000 --- a/docs/source/tutorial/tutorial-obtain-schema.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: "2. Obtain your GraphQL schema" ---- - -This tutorial uses a modified version of the GraphQL server you build as part of [the Apollo full-stack tutorial](https://www.apollographql.com/docs/tutorial/introduction/). You can visit [that server's Apollo Studio Sandbox Explorer](https://studio.apollographql.com/sandbox/explorer?endpoint=https%3A%2F%2Fapollo-fullstack-tutorial.herokuapp.com%2Fgraphql) to explore its schema without needing to be logged in: - -The Sandbox query explorer - -You'll know that this Sandbox instance is pointed at our server because its URL, `https://apollo-fullstack-tutorial.herokuapp.com/graphql`, is in the box at the top left of the page. If Sandbox is properly connected, you'll see a green dot: - -A closeup of the URL box with a dot indicating it's connected - -The schema defines which GraphQL operations your server can execute. At the top left, click the schema icon to get an overview of your schema: - -The schema icon to click - -In the **Reference** tab, you can now see a list of all of the things available to you as a consumer of this API, along with available fields on all objects: - -Apollo sandbox showing the schema reference - -## Download your server's schema - -The Apollo iOS SDK needs a local copy of your server's schema to generate code from it. To accomplish this, the Apollo CLI includes a `schema:download` command that enables you to fetch the schema from a GraphQL server. - -To use the Apollo CLI from Xcode, add a **Run Script** build phase to your app: - -1. Select the `xcodeproj` file in the Project Navigator, and then select the `RocketReserver` application target: - - Selecting application target - -2. A list of tabs appears. Select the **Build Phases** tab: - - Build phases menu item - -3. Click the `+` button above the list of existing phases and select **New Run Script Phase**: - - Creating a new run script build phase - - This adds a new Run Script build phase to the bottom of your list of build phases. - -4. Drag the newly created phase up between "Dependencies" and "Compile Sources": - - Where to drag the run script - -5. Double-click the name of the build phase to rename it to **Apollo**: - - UI for renaming - -6. Expand the Apollo phase. Paste the **Swift Package Manager Run Script** from [Add a code generation build step](../installation/#5-add-a-code-generation-build-step) into the text area. This script uses your schema to generate the code that the Apollo iOS SDK uses to interact with your server. - -7. Before the script can generate code, it needs a local copy of your GraphQL server's schema. For now, using a `#`, **comment out the last line** of the script you pasted and add the following line below it: - - ``` - "${SCRIPT_PATH}"/run-bundled-codegen.sh schema:download --endpoint="https://apollo-fullstack-tutorial.herokuapp.com/graphql" - ``` - - This line runs the Apollo CLI's `schema:download` command, which downloads the schema to a `schema.json` file at the same level of your project as the `AppDelegate.swift` file. - -8. Build your project to execute the script. In Finder, navigate to the folder that contains your `AppDelegate.swift` file. The folder should now include the downloaded `schema.json` file. Drag this file from Finder into Xcode. When Xcode offers to add the schema file, make sure **all targets are unchecked** to reduce the size of your application bundle: - - All targets unchecked in dialog - - You don't need to add the schema to any targets, because it is only used to generate code which _is_ added to targets. - -Your server's schema is now available locally. Next, you'll [create your first operation against the schema](./tutorial-execute-query). diff --git a/docs/source/tutorial/tutorial-pagination.md b/docs/source/tutorial/tutorial-pagination.md deleted file mode 100644 index a82502e1cc..0000000000 --- a/docs/source/tutorial/tutorial-pagination.md +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: "5. Paginate results" ---- - -As mentioned earlier, the object returned from the `LaunchListQuery` is a `LaunchConnection`. This object has a list of launches, a pagination cursor, and a boolean to indicate whether more launches exist. - -When using a cursor-based pagination system, it's important to remember that the cursor gives you a place where you can get all results after a certain spot, regardless of whether more items have been added in the interim. - -You're going to use a second section in the TableView to allow your user to load more launches as long as they exist. But how will you know if they exist? First, you need to hang on to the most recently received `LaunchConnection` object. - -Add a variable to hold on to this object at the top of the `LaunchesViewController.swift` file near your `launches` variable: - -```swift title="LaunchesViewController.swift" -private var lastConnection: LaunchListQuery.Data.Launch? -``` - -Next, you're going to take advantage of a type from the Apollo library. Add the following to the top of the file: - -```swift title="LaunchesViewController.swift" -import Apollo -``` - -Then, below `lastConnection`, add a variable to hang on to the most recent request: - -```swift title="LaunchesViewController.swift" -private var activeRequest: Cancellable? -``` - -Next, add a second case to your `ListSection` enum: - -```swift title="LaunchesViewController.swift" -enum ListSection: Int, CaseIterable { - case launches - case loading -} -``` - -This allows loading state to be displayed and selected in a separate section, keeping your `launches` section tied to the `launches` variable. - -This will also cause a number of errors because you're no longer exhaustively handling all the cases in the enum - let's fix that. - -In `tableView(_:, numberOfRowsInSection:)`, add handling for the `.loading` case, which returns `0` if there are no more launches to load: - -```swift title="LaunchesViewController.swift" -case .loading: - if self.lastConnection?.hasMore == false { - return 0 - } else { - return 1 - } -``` - -Remember here that if `lastConnection` is nil, there *are* more launches to load, since we haven't even loaded a first connection. - -Next, add handling for the `.loading` case to `tableView(_, cellForRowAt:)`, showing a different message based on whether there's an active request or not: - -```swift title="LaunchesViewController.swift" -case .loading: - if self.activeRequest == nil { - cell.textLabel?.text = "Tap to load more" - } else { - cell.textLabel?.text = "Loading..." - } -``` - -Next, you'll need to provide the cursor to your `LaunchListQuery`. The good news is that the `launches` API takes an optional `after` parameter, which accepts a cursor. - -To pass a variable into a GraphQL query, you need to use syntax that defines that variable using a `$name` and its type. You can then pass the variable in as a parameter value to an API which takes a parameter. - -What does this look like in practice? Go to `LaunchList.graphql` and update just the first two lines to take and use the cursor as a parameter: - -```graphql title="LaunchList.graphql" -query LaunchList($cursor:String) { - launches(after:$cursor) { -``` - -Build the application so the code generation picks up on this new parameter. You'll still see one error for a non-exhaustive switch, but this is something we'll fix shortly. - -Next, go back to `LaunchesViewController.swift` and update `loadLaunches()` to be `loadMoreLaunches(from cursor: String?)`, hanging on to the active request (and nil'ing it out when it completes), and updating the last received connection: - -```swift title="LaunchesViewController.swift" -private func loadMoreLaunches(from cursor: String?) { - self.activeRequest = Network.shared.apollo.fetch(query: LaunchListQuery(cursor: cursor)) { [weak self] result in - guard let self = self else { - return - } - - self.activeRequest = nil - defer { - self.tableView.reloadData() - } - - switch result { - case .success(let graphQLResult): - if let launchConnection = graphQLResult.data?.launches { - self.lastConnection = launchConnection - self.launches.append(contentsOf: launchConnection.launches.compactMap { $0 }) - } - - if let errors = graphQLResult.errors { - let message = errors - .map { $0.localizedDescription } - .joined(separator: "\n") - self.showAlert(title: "GraphQL Error(s)", - message: message) - } - case .failure(let error): - self.showAlert(title: "Network Error", - message: error.localizedDescription) - } - } -} -``` - -Then, add a new method to figure out if new launches need to be loaded: - -```swift title="LaunchesViewController.swift" -private func loadMoreLaunchesIfTheyExist() { - guard let connection = self.lastConnection else { - // We don't have stored launch details, load from scratch - self.loadMoreLaunches(from: nil) - return - } - - guard connection.hasMore else { - // No more launches to fetch - return - } - - self.loadMoreLaunches(from: connection.cursor) -} -``` - -Update `viewDidLoad` to use this new method rather than calling `loadMoreLaunches(from:)` directly: - -```swift title="LaunchesViewController.swift" -override func viewDidLoad() { - super.viewDidLoad() - self.loadMoreLaunchesIfTheyExist() -} -``` - -Next, you need to add some handling when the cell is tapped. Normally that's handled by `prepare(for segue:)`, but because you're going to be reloading things in the current view controller, you won't want the segue to perform at all. - -Luckily, you can use `UIViewController`'s `shouldPerformSegue(withIdentifier:sender:)` method to say, "In this case, don't perform this segue, and take these other actions instead." - -This method was already overridden in the starter project. Update the code within it to perform the segue for anything in the `.launches` section and _not_ perform it (instead loading more launches if needed) for the `.loading` section. Replace the `TODO` and everything below it with: - - -```swift title="LaunchesViewController.swift" - guard let listSection = ListSection(rawValue: selectedIndexPath.section) else { - assertionFailure("Invalid section") - return false -} - -switch listSection { - case .launches: - return true - case .loading: - self.tableView.deselectRow(at: selectedIndexPath, animated: true) - - if self.activeRequest == nil { - self.loadMoreLaunchesIfTheyExist() - } // else, let the active request finish loading - - self.tableView.reloadRows(at: [selectedIndexPath], with: .automatic) - - // In either case, don't perform the segue - return false - } -} -``` - -Finally, even though you've told the segue system that you don't need to perform the segue for anything in the `.loading` case, the _compiler_ still doesn't know that, and it requires you to handle the `.loading` case in `prepare(for segue:)`. - -However, your code should theoretically never reach this point, so it's a good place to use an `assertionFailure` if you ever hit it during development. This both satisfies the compiler and warns you loudly and quickly if your assumption that something is handled in `shouldPerformSegue` is wrong. - -Add the following to the `switch` statement in `prepare(for segue:)` - -```swift title="LaunchesViewController.swift" -case .loading: - assertionFailure("Shouldn't have gotten here!") -``` - -Now, when you build and run and scroll down to the bottom of the list, you'll see a cell you can tap to load more rows: - -Screenshot with loading cell - - -When you tap that cell, the rows will load and then redisplay. If you tap it several times, it reaches a point where the loading cell is no longer displayed, and the last launch was SpaceX's original FalconSat launch from Kwajalien Atoll: - - -List with all launches loaded and no loading cell - - -Congratulations, you've loaded all of the possible launches! But when you tap one, you still get the same boring detail page. - -Next, you'll [make the detail page a lot more interesting](./tutorial-detail-view/) by taking the ID returned by one query and passing it to another. diff --git a/docs/source/tutorial/tutorial-query-ui.md b/docs/source/tutorial/tutorial-query-ui.md deleted file mode 100644 index 0f1fe73d86..0000000000 --- a/docs/source/tutorial/tutorial-query-ui.md +++ /dev/null @@ -1,300 +0,0 @@ ---- -title: "4. Connect your queries to your UI" ---- - -Now that your app can execute queries against a GraphQL server, you can reflect the results of those queries in your UI. - -## Display the list of launches - -Now let's add properties to display the results of the `LaunchListQuery` you built in the previous tutorial step. - -At the top of `LaunchesViewController.swift`, add a new property to store the launches that the query returns: - -```swift title="LaunchesViewController.swift" -var launches = [LaunchListQuery.Data.Launch.Launch]() -``` - -Why the long name? Each query returns its own nested object structure to ensure that when you use the result of a particular query, you can't ask for a property that isn't present. Because this screen will be populated by the results of the `LaunchListQuery`, you need to display subtypes of that particular query. - -Next, add an enum that helps handle dealing with sections (we'll add more items to the enum later): - -```swift title="LaunchesViewController.swift" -enum ListSection: Int, CaseIterable { - case launches -} -``` - -## Fill in required methods - -Now we can update the various `UITableViewDataSource` methods to use the result of our query. - -For `numberOfSections(in:)`, you can use the `allCases` property from `CaseIterable` to provide the appropriate number of sections: - -```swift title="LaunchesViewController.swift" -override func numberOfSections(in tableView: UITableView) -> Int { - return ListSection.allCases.count -} -``` - -For `tableView(_:numberOfRowsInSection:)`, you can try instantiating a `ListSection` enum object. If it doesn't work, that's an invalid section, and if it does, you can `switch` directly on the result. In this case, you'll want to return the count of launches: - -```swift title="LaunchesViewController.swift" -override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - guard let listSection = ListSection(rawValue: section) else { - assertionFailure("Invalid section") - return 0 - } - - switch listSection { - case .launches: - return self.launches.count - } -} -``` - -For `tableView(_:cellForRowAt:)`, you can use the existing cell dequeueing mechanism, the same section check as in `tableView(_:numberOfRowsInSection)`, and then configure the cell based on what section it's in. - -For this initial section, grab a launch out of the `launches` array at the index of `indexPath.row`, and update the `textLabel` to display the launch site: - -```swift title="LaunchesViewController.swift" -override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - - guard let listSection = ListSection(rawValue: indexPath.section) else { - assertionFailure("Invalid section") - return cell - } - - switch listSection { - case .launches: - let launch = self.launches[indexPath.row] - cell.textLabel?.text = launch.site - } - - return cell -} -``` - -Your table view has all the information it needs to populate itself when the `launches` array has contents. Now it's time to actually get those contents from the server. - -First, add a method to load the launches. You'll use a setup similar to the one you used to set this up in the `AppDelegate` earlier. - -However, you need to make sure that a call doesn't try to call back and use elements that are no longer there, so you'll check to make sure that the `LaunchesViewController` hasn't been deallocated out from under you by passing in `[weak self]` and unwrapping `self` before proceeding with updating the UI. - -Replace the `TODO` in `loadLaunches` with the following: - -```swift title="LaunchesViewController.swift" -private func loadLaunches() { - Network.shared.apollo - .fetch(query: LaunchListQuery()) { [weak self] result in - - guard let self = self else { - return - } - - defer { - self.tableView.reloadData() - } - - switch result { - case .success(let graphQLResult): - // TODO - case .failure(let error): - // From `UIViewController+Alert.swift` - self.showAlert(title: "Network Error", - message: error.localizedDescription) - } - } -} -``` - - -`GraphQLResult` has both a `data` property and an `errors` property. This is because GraphQL allows partial data to be returned if it's non-null. - -In the example we're working with now, we could theoretically obtain a list of launches, and then an error stating that a launch with a particular ID could not be retrieved. - -This is why when you get a `GraphQLResult`, you generally want to check both the `data` property (to display any results you got from the server) _and_ the `errors` property (to try to handle any errors you received from the server). - -Replace the `// TODO` in the code above with the following code to handle both data and errors: - -```swift title="LaunchesViewController.swift" -if let launchConnection = graphQLResult.data?.launches { - self.launches.append(contentsOf: launchConnection.launches.compactMap { $0 }) -} - -if let errors = graphQLResult.errors { - let message = errors - .map { $0.localizedDescription } - .joined(separator: "\n") - self.showAlert(title: "GraphQL Error(s)", - message: message) -} -``` - -Finally, you'd normally need to actually call the method you just added to kick off the call to the network when the view is first loaded. Take a look at your `viewDidLoad` and note that it's already set up to call `loadLaunches`: - -```swift title="LaunchesViewController.swift" -override func viewDidLoad() { - super.viewDidLoad() - self.loadLaunches() -} -``` - -Build and run the application. After the query completes, a list of launch sites appears: - -List of launch sites - -However, if you attempt to tap one of the rows, the app displays the detail view controller with the placeholder text you can see in the storyboard, instead of any actual information about the launch: - - -Placeholder detail content - - -To send that information through, you need to build out the `LaunchesViewController`'s `prepareForSegue` method, and have a way for that method to pass the `DetailViewController` information about the launch. - -## Pass information to the detail view - -Let's update the `DetailViewController` to be able to handle information about a launch. - -Open `DetailViewController.swift` and note that there's a property below the list of `IBOutlet`s: - -```swift title="DetailViewController.swift" -var launchID: GraphQLID? { - didSet { - self.loadLaunchDetails() - } -} -``` - -This settable property allows the `LaunchesViewController` to pass along the identifier for the selected launch. The identifier will be used later to load more details about the launch. - -For now, update the `configureView()` method to use this property (if it's there) to show the launch's identifier: - -```swift title="DetailViewController.swift" -func configureView() { - // Update the user interface for the detail item. - guard - let label = self.missionNameLabel, - let id = self.launchID else { - return - } - - label.text = "Launch \(id)" - // TODO: Adjust UI based on whether a trip is booked or not -} -``` - -> **Note**: You're also unwrapping the `missionNameLabel` because even though it's an Implicitly Unwrapped Optional, it won't be present if `configureView` is called before `viewDidLoad`. - -Next, back in `LaunchesViewController.swift`, update the `prepareForSegue` method to obtain the most recently selected row and pass its corresponding launch details to the detail view controller. Replace the `TODO` and below with the following: - -```swift title="LaunchesViewController.swift" -guard let selectedIndexPath = self.tableView.indexPathForSelectedRow else { - // Nothing is selected, nothing to do - return -} - -guard let listSection = ListSection(rawValue: selectedIndexPath.section) else { - assertionFailure("Invalid section") - return -} - -switch listSection { -case .launches: - guard - let destination = segue.destination as? UINavigationController, - let detail = destination.topViewController as? DetailViewController else { - assertionFailure("Wrong kind of destination") - return - } - - let launch = self.launches[selectedIndexPath.row] - detail.launchID = launch.id - self.detailViewController = detail -} -``` - -Build and run, and tap on any of the launches. You'll now see the launch ID for the selected launch when you land on the page: - -Empty screen with launch ID - -The app is working! However, it doesn't provide much useful information. Let's fix that. - -## Add more info to the list view - -Go back to `LaunchList.graphql`. Your query is already fetching most of the information you want to display, but it would be nice to display both the name of the mission and an image of the patch. - -Looking at the schema in Sandbox Explorer , you can see that `Launch` has a property of `mission`, which allows you to get details of the mission. A mission has both a `name` and a `missionPatch` property, and the `missionPatch` can optionally take a parameter about what size something needs to be. - -Because loading a table view with large images can impact performance, ask for the name and a `SMALL` mission patch. Update your query to look like the following: - -```graphql title="LaunchList.graphql" -query LaunchList { - launches { - hasMore - cursor - launches { - id - site - mission { - name - missionPatch(size: SMALL) - } - } - } -} -``` - -When you recompile, if you look in `API.swift`, you'll see a new nested type, `Mission`, with the two properties you requested. - -Go back to `LaunchesViewController.swift` and add the following import of one of the libraries that was already in your project to the top of the file: - -```swift title="LaunchesViewController.swift" -import SDWebImage -``` - -You'll use this shortly to load an image based on a URL. - -Next, open up your Asset your Asset Catalog, `Assets.xcassets`. You'll see an image named "Placeholder": - -image in asset catalog - -You'll use this image as a placeholder to show while the mission patch images are loading. - -Now go back to `LaunchesViewController.swift`. In `tableView(cellForRowAt:)`, once the cell is loaded, add the following code to help make sure that before the cell is configured, it clears out any stale data: - -```swift title="LaunchesViewController.swift" -cell.imageView?.image = nil -cell.textLabel?.text = nil -cell.detailTextLabel?.text = nil -``` - -> **Note**: In a custom `UITableViewCell`, you'd do this by overriding `prepareForReuse` rather than resetting directly in the data source. However, since you're using a stock cell, you have to do it here. - -Next, in the same method, go down to where you're setting up the cell based on the section. Update the code to use the launch mission name as the primary text label, the launch site as the detail text label, and to load the mission patch if it exists: - -```swift title="LaunchesViewController.swift" -switch listSection { -case .launches: - let launch = self.launches[indexPath.row] - cell.textLabel?.text = launch.mission?.name - cell.detailTextLabel?.text = launch.site - - let placeholder = UIImage(named: "placeholder")! - - if let missionPatch = launch.mission?.missionPatch { - cell.imageView?.sd_setImage(with: URL(string: missionPatch)!, placeholderImage: placeholder) - } else { - cell.imageView?.image = placeholder - } -} -``` - -Build and run the application, and you will see all the information for current launches populate: - - -Final launch list - -If you scroll down, you'll see the list includes only about 20 launches. This is because the list of launches is **paginated**, and you've only fetched the first page. - -Now it's time to learn [how to use a cursor-based loading system to load the entire list of launches](./tutorial-pagination/). diff --git a/docs/source/tutorial/tutorial-subscriptions.md b/docs/source/tutorial/tutorial-subscriptions.md deleted file mode 100644 index aae3a7039f..0000000000 --- a/docs/source/tutorial/tutorial-subscriptions.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: "9. Write your first subscription" ---- - -In this section, you will use subscriptions to get notified whenever someone books a flight 🚀! [Subscriptions](https://graphql.org/blog/subscriptions-in-graphql-and-relay/) allow you to be notified in real time whenever an event happens on your server. The [fullstack backend](https://apollo-fullstack-tutorial.herokuapp.com/graphql) supports subscriptions based on [WebSockets](https://en.wikipedia.org/wiki/WebSocket). - - -## Write your subscription - -Open your [Sandbox](https://studio.apollographql.com/sandbox/explorer?endpoint=https%3A%2F%2Fapollo-fullstack-tutorial.herokuapp.com%2Fgraphql) back up, click on the Schema tab at the far left. In addition to `queries` and `mutations`, you will see a third type of operations, `subscriptions`. Click on subscriptions to see the `tripsBooked` subscription: - -The definition of tripsBooked in the schema - -This subscription doesn't take any argument and returns a single scalar named `tripsBooked`. Since you can book multiple trips at once, `tripsBooked` is an `Int`. It will contain the number of trips booked at once or -1 if a trip has been cancelled. - -Click the play button to the far right of `tripsBooked` to open the subscription in Explorer. Open a new tab, then check the `tripsBooked` button to have the subscription added: - -The initial definition of the TripsBooked subscription - -Again, rename your subscription so it's easier to find: - -The subscription after rename - -Click the Submit Operation button, and your subscription will start listening to events. You can tell it's up and running because a panel will pop up at the lower left where subscription data will come in: - -The UI showing that it's listening for subscription updates - -## Test your subscription - -Open a new tab in Explorer. In this new tab, add code to book a trip like on [step 8](tutorial-mutations), but with a hard-coded ID: - -```graphql -mutation BookTrip { - bookTrips(launchIds: ["93"]){ - message - } -} -``` - -Do not forget to include the authentication header. At the bottom of the Sandbox Explorer pane where you add operations, there's a `Headers` section: - -Adding a login token to explorer - -Click the Submit Operation button. If everything went well, you just booked a trip! At the top of the right panel, you'll see the success JSON for your your `BookTrip` mutation, and below it, updated JSON for the `TripsBooked` subscription: - -Subscription success in Explorer - -Continue booking and/or canceling trips, you will see events coming in the subscription panel in real time. After some time, the server might close the connection and you'll have to restart your subscription to keep receiving events. - -## Add the subscription to the project - -Now that your subscription is working, add it to your project. Create an empty file named `TripsBooked.graphql` next to your other GraphQL files and paste the contents of the subscription. The process is similar to what you've already done for queries and mutations: - -```graphql title="TripsBooked.graphql" -subscription TripsBooked { - tripsBooked -} -``` - -Build your project, and the subscription will be picked up and added to your `API.swift` file. - -## Configure your ApolloClient to use subscriptions - -> This tutorial uses the [`graphql-ws`](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md) protocol, implemented by the [`subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws) library. **That library is no longer actively maintained.** We recommend using the [`graphql-ws`](https://www.npmjs.com/package/graphql-ws) library instead, which implements its own WebSocket subprotocol, `graphql-transport-ws`. Note that the two libraries do not use the same WebSocket subprotocol and you need to ensure that your servers, clients, and tools use the **same library and subprotocol**. For more information and examples, see [GraphQL over WebSocket protocols](../subscriptions#graphql-over-websocket-protocols). - -In `Network.swift`, you'll need to set up a transport which supports subscriptions in addition to general network usage. In practice, this means adding a `WebSocketTransport` which will allow real-time communication with your server. - -First, at the top of the file, add an import for the **ApolloWebSocket** framework to get access to the classes you'll need: - -```swift title="Network.swift" -import ApolloWebSocket -``` - -Next, in the lazy declaration of the `apollo` variable, immediately after `transport` is declared, set up what you need to add subscription support to your client: - -```swift title="Network.swift" -// 1 -let webSocket = WebSocket( - url: URL(string: "wss://apollo-fullstack-tutorial.herokuapp.com/graphql")!, - protocol: .graphql_ws -) - -// 2 -let webSocketTransport = WebSocketTransport(websocket: webSocket) - -// 3 -let splitTransport = SplitNetworkTransport( - uploadingNetworkTransport: transport, - webSocketNetworkTransport: webSocketTransport -) - -// 4 -return ApolloClient(networkTransport: splitTransport, store: store) -``` - -What's happening here? - -1. You've created a web socket with the server's web socket URL - `wss://` is the protocol for a secure web socket. -2. You've created a `WebSocketTransport`, which allows the Apollo SDK to communicate with the web socket. -3. You've created a `SplitNetworkTransport`, which can decide whether to use a web socket or not automatically, with both the `RequestChainNetworkTransport` you had previously set up, and the `WebSocketTransport` you just set up. -4. You're now passing the `splitTransport` into the `ApolloClient`, so that it's the main transport being used in your `ApolloClient`. - -Now, you're ready to actually use your subscription! - -## Display a view when a trip is booked/cancelled - -In `LaunchesViewController`, add a new variable just below `activeRequest` to hang on to a reference to your subscription so it doesn't get hammered by ARC as soon as it goes out of scope: - -```swift title="LaunchesViewController.swift" -private var activeSubscription: Cancellable? -``` - -Next, just above the code for handling Segues, add code for starting and handling the result of a subscription: - -```swift title="LaunchesViewController.swift" -// MARK: - Subscriptions - -private func startSubscription() { - activeSubscription = Network.shared.apollo.subscribe(subscription: TripsBookedSubscription()) { result in - switch result { - case .failure(let error): - self.showAlert(title: "NetworkError", - message: error.localizedDescription) - case .success(let graphQLResult): - if let errors = graphQLResult.errors { - self.showAlertForErrors(errors) - } else if let tripsBooked = graphQLResult.data?.tripsBooked { - self.handleTripsBooked(value: tripsBooked) - } else { - // There was no data and there were no errors, do nothing. - } - } - } - } -} - -private func handleSubscriptionEvent() { - print("Trips booked: \(value)") -} -``` - -Finally, add a line to `viewDidLoad` which actually starts the subscription: - -```swift title="LaunchesViewController.swift" -override func viewDidLoad() { - super.viewDidLoad() - self.startSubscription() - self.loadMoreLaunchesIfTheyExist() -} -``` - -Build and run your app and go back to Sandbox Explorer, and select the tab where you set up the `BookTrip` mutation. Book a new trip while your app is open, you'll see a log print out: - -``` -Trips booked: 1 -``` - -Cancel that same trip, and you'll see another log: - -``` -Trips booked: -1 -``` - -Now, let's display that information in a view! Replace the `print` statement in `handleTripsBooked` with code to use the included `NotificationView` to show a brief alert at the bottom of the screen with information about a trip being booked or cancelled: - -```swift title="LaunchesViewController.swift" -private func handleTripsBooked(value: Int) { - var message: String - switch value { - case 1: - message = "A new trip was booked! 🚀" - case -1: - message = "A trip was cancelled! 😭" - default: - self.showAlert(title: "Unexpected value", - message: " Subscription returned unexpected value: \(value)") - return - } - - NotificationView.show(in: self.navigationController!.view, - with: message, - for: 4.0) - } -``` - -Build and run the application to your simulator, then use Studio to send bookings and cancellations again, and your iOS app should see some shiny new notifications pop up: - -A new trip was booked (rocket) - -And you've done it! You've completed the tutorial. - -## More resources - -There are way more things you can do with the Apollo iOS SDK, and the rest of this documentation includes info on more advanced topics like: - -- Using [fragments](../fragments/) -- Working with [custom scalars](../fetching-queries/#notes-on-working-with-custom-scalars) -- [Caching](../caching/) - -Feel free to ask questions by either [opening an issue on our GitHub repo](https://github.com/apollographql/apollo-ios/issues), or [joining the community](http://community.apollographql.com/new-topic?category=Help&tags=mobile,client). - -And if you want dig more and see GraphQL in real-world apps, you can take a look at these open source projects using Apollo iOS: - -* https://github.com/GitHawkApp/GitHawk -* [open a PR if you have an example app that should be here!] diff --git a/docs/source/watching-queries.md b/docs/source/watching-queries.md deleted file mode 100644 index bc22e92139..0000000000 --- a/docs/source/watching-queries.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Watching queries ---- - -[This information is now included in the Caching documentation.](./caching/) - diff --git a/makefile b/makefile new file mode 100644 index 0000000000..e5ff361020 --- /dev/null +++ b/makefile @@ -0,0 +1,5 @@ +default: unpack-cli + +unpack-cli: + (cd CLI && tar -xvf apollo-ios-cli.tar.gz -C ../) + chmod +x apollo-ios-cli diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 93c1071b76..0000000000 --- a/netlify.toml +++ /dev/null @@ -1,19 +0,0 @@ -[build] - ignore = "exit 0" - -[build.environment] - NODE_VERSION = "16" - -[context.deploy-preview.build] - base = "docs" - ignore = "git diff --quiet HEAD^ HEAD ." - command = """\ - cd ../ - rm -rf monodocs - git clone https://github.com/apollographql/docs --branch main --single-branch monodocs - cd monodocs - npm i - cp -r ../docs local - DOCS_LOCAL=true npm run build \ - """ - publish = "../monodocs/public" diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 8ddf24ba19..0000000000 --- a/renovate.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "packageFiles": ["docs/package.json"], - "extends": [ - "apollo-docs" - ], - "labels": ["dependency-management"] -} diff --git a/screenshots/xcode-code-completion.png b/screenshots/xcode-code-completion.png deleted file mode 100644 index 5da9ea7e25..0000000000 Binary files a/screenshots/xcode-code-completion.png and /dev/null differ diff --git a/screenshots/xcode-data-access-error.png b/screenshots/xcode-data-access-error.png deleted file mode 100644 index b64ab2d265..0000000000 Binary files a/screenshots/xcode-data-access-error.png and /dev/null differ diff --git a/screenshots/xcode-query-validation.png b/screenshots/xcode-query-validation.png deleted file mode 100644 index 6056317c80..0000000000 Binary files a/screenshots/xcode-query-validation.png and /dev/null differ diff --git a/scripts/carthage-build-workaround.sh b/scripts/carthage-build-workaround.sh deleted file mode 100755 index c3efa3fa16..0000000000 --- a/scripts/carthage-build-workaround.sh +++ /dev/null @@ -1,24 +0,0 @@ -# carthage-build.sh -# Usage example: ./carthage-build-workaround.sh --platform iOS - -set -euo pipefail - -cd .. # apollo-ios -cd .. # Checkouts -cd .. # Carthage -cd .. # your project - -xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX) -trap 'rm -f "$xcconfig"' INT TERM HUP EXIT - -# For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise -# the build will fail on lipo due to duplicate architectures. - -CURRENT_XCODE_VERSION=$(xcodebuild -version | grep "Build version" | cut -d' ' -f3) -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$CURRENT_XCODE_VERSION = arm64 arm64e armv7 armv7s armv6 armv8" >> $xcconfig - -echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig -echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig - -export XCODE_XCCONFIG_FILE="$xcconfig" -carthage update diff --git a/scripts/download-cli.sh b/scripts/download-cli.sh new file mode 100644 index 0000000000..f3f8df6640 --- /dev/null +++ b/scripts/download-cli.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# This script is intended for use only with the "InstallCLI" SPM plugin provided by Apollo iOS + +directory=$(dirname "$0") +projectDir="$1" + +if [ -z "$projectDir" ]; +then + echo "Missing project directory path." >&2 + exit 1 +fi + +APOLLO_VERSION=$(sh "$directory/get-version.sh") +DOWNLOAD_URL="https://www.github.com/apollographql/apollo-ios/releases/download/$APOLLO_VERSION/apollo-ios-cli.tar.gz" +FILE_PATH="$projectDir/apollo-ios-cli.tar.gz" +curl -L "$DOWNLOAD_URL" -s -o "$FILE_PATH" +tar -xvf "$FILE_PATH" +rm -f "$FILE_PATH" diff --git a/scripts/ensure-no-build-settings-in-pbxproj.sh b/scripts/ensure-no-build-settings-in-pbxproj.sh deleted file mode 100755 index eb21028de0..0000000000 --- a/scripts/ensure-no-build-settings-in-pbxproj.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -PROJECT_PATH=${1} -if [ -z "${PROJECT_PATH}" ]; then - echo "Project path not specified." - exit 1 -fi - -PROJECT_FILE_PATH="${PROJECT_PATH}/project.pbxproj" -NUMBER_OF_BUILD_SETTINGS=`grep "buildSettings" "$PROJECT_FILE_PATH" | wc -l` -NUMBER_OF_EMPTY_BUILD_SETTINGS=`grep -B 0 -A 1 "buildSettings" "$PROJECT_FILE_PATH" | grep "};" | wc -l` - -if [ $NUMBER_OF_BUILD_SETTINGS != $NUMBER_OF_EMPTY_BUILD_SETTINGS ]; then - NUMBER_WITH_SETTINGS=`expr $NUMBER_OF_BUILD_SETTINGS - $NUMBER_OF_EMPTY_BUILD_SETTINGS` - - echo "${PROJECT_PATH}: error: Found ${NUMBER_WITH_SETTINGS} build settings in Xcode project file. Build settings should only be defined in .xcconfig files." - exit 1 -fi diff --git a/scripts/get-version.sh b/scripts/get-version.sh index 7bead58d8e..1648206ef9 100755 --- a/scripts/get-version.sh +++ b/scripts/get-version.sh @@ -1,7 +1,8 @@ #!/bin/bash -source "$(dirname "$0")/version-constants.sh" +directory=$(dirname "$0") +source "$directory/version-constants.sh" -prefix="$VERSION_CONFIG_VAR = " -version_config=$(cat $VERSION_CONFIG_FILE) -echo "${version_config:${#prefix}}" +constantsFile=$(cat "$directory/../$APOLLO_CONSTANTS_FILE") +currentVersion=$(echo $constantsFile | sed 's/^.*ApolloVersion: String = "\([^"]*\).*/\1/') +echo $currentVersion diff --git a/scripts/install-apollo-server-docs-example-server.sh b/scripts/install-apollo-server-docs-example-server.sh deleted file mode 100755 index db81cfc94c..0000000000 --- a/scripts/install-apollo-server-docs-example-server.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd $(dirname "$0")/../.. - -git clone https://github.com/apollographql/docs-examples.git - -cd docs-examples/apollo-server/v3/subscriptions-graphql-ws - -npm install diff --git a/scripts/install-node-v12.sh b/scripts/install-node-v12.sh deleted file mode 100755 index f815510b29..0000000000 --- a/scripts/install-node-v12.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -touch $BASH_ENV -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash -echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV -echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV -echo nvm install v12.22.10 >> $BASH_ENV -echo nvm use v16.15.1 >> $BASH_ENV \ No newline at end of file diff --git a/scripts/install-or-update-starwars-server.sh b/scripts/install-or-update-starwars-server.sh deleted file mode 100755 index 8e1678134a..0000000000 --- a/scripts/install-or-update-starwars-server.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -cd $(dirname "$0")/../.. - -git -C starwars-server pull || git clone https://github.com/apollographql/starwars-server - -cd starwars-server - -npm install -npm prune diff --git a/scripts/run-bundled-codegen.sh b/scripts/run-bundled-codegen.sh deleted file mode 100755 index aa0fcfe0bc..0000000000 --- a/scripts/run-bundled-codegen.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env bash - -# Exit on all errors, undeclared variables and pipefailures. -set -euo pipefail - -# Advertisement! -echo "Have you tried our new Swift Package Manager wrapper around codegen? It's now out of beta and ready to go! See docs at https://www.apollographql.com/docs/ios/swift-scripting/. This Bash script will be deprecated soon, so give it a try today!" - -# Get the path to the script directory -SCRIPT_DIR="$(dirname "$0")" - -# Get the SHASUM of the tarball -ZIP_FILE="${SCRIPT_DIR}/apollo.tar.gz" -ZIP_FILE_DOWNLOAD_URL="https://install.apollographql.com/legacy-cli/darwin/2.33.9" -SHASUM_FILE="${SCRIPT_DIR}/apollo/.shasum" -APOLLO_DIR="${SCRIPT_DIR}"/apollo -IS_RETRY="false" -SHASUM="" - -# Helper functions -download_apollo_cli_if_needed() { - echo "Checking if CLI needs to be downloaded..." - if [ -f "${ZIP_FILE}" ]; then - echo "Zip file already downloaded!" - else - download_cli - fi -} - -download_cli() { - echo "Downloading zip file with the CLI..." - curl --silent --retry 3 --fail --show-error -L "${ZIP_FILE_DOWNLOAD_URL}" -o "${ZIP_FILE}" -} - -force_cli_download() { - rm -r "${ZIP_FILE}" - remove_existing_apollo - download_cli - IS_RETRY="true" - validate_codegen_and_extract_if_needed -} - -update_shasum() { - SHASUM="$(/usr/bin/shasum -a 256 "${ZIP_FILE}" | /usr/bin/awk '{ print $1 }')" -} - -remove_existing_apollo() { - if [[ -f "${APOLLO_DIR}" ]]; then - rm -r "${APOLLO_DIR}" - fi -} - -extract_cli() { - tar xzf "${SCRIPT_DIR}"/apollo.tar.gz -C "${SCRIPT_DIR}" - - echo "${SHASUM}" | tee "${SHASUM_FILE}" -} - -validate_codegen_and_extract_if_needed() { - # Make sure the SHASUM matches the release for this version - EXPECTED_SHASUM="cb73089deb2a720a7d2f5a39ad449e1cfbdc22771130cd6e2a405aaa887c343e" - update_shasum - - if [[ ${SHASUM} = ${EXPECTED_SHASUM}* ]]; then - echo "Correct version of the CLI tarball is downloaded locally, checking if it's already been extracted..." - else - if [[ "${IS_RETRY}" == "true" ]]; then - #This was a retry, and the SHASUM still doesn't match. - echo "Error: The SHASUM of this zip file does not match the official released version from Apollo! This may present security issues. Terminating code generation." >&2 - exit 1 - else - # This was the first attempt, the version may have changed. - echo "Incorrect version of the CLI tarball is downloaded locally, redownloading the zip from the server." - force_cli_download - fi - fi - - # Check if the SHASUM file has already been written for this version - if [ -f "${SHASUM_FILE}" ]; then - # The file exists, let's see if it's the same SHASUM - FILE_CONTENTS="$(cat "${SHASUM_FILE}")" - if [[ ${FILE_CONTENTS} = ${EXPECTED_SHASUM}* ]]; then - echo "Current version of CLI is already extracted!" - else - echo "Extracting updated version of the Apollo CLI. This may take a minute..." - remove_existing_apollo - extract_cli - fi - else - # The file doesn't exist, unzip the CLI - echo "Extracting the Apollo CLI. This may take a minute..." - extract_cli - fi -} - -# Download the current version of the CLI if it doesn't exist -download_apollo_cli_if_needed - -# Make sure we're using an up-to-date and valid version of the Apollo CLI -validate_codegen_and_extract_if_needed - -# Add the binary directory to the beginning of PATH so included binary version of node is used. -PATH="${SCRIPT_DIR}/apollo/bin:${PATH}" - -# Use the bundled executable of the Apollo CLI to generate code -APOLLO_CLI="${SCRIPT_DIR}/apollo/bin/run" - -# Print version -echo "Apollo CLI Information: $("${APOLLO_CLI}" --version)" - -# Print commands before executing them (useful for troubleshooting) -set -x -"$APOLLO_CLI" "$@" diff --git a/scripts/set-version.sh b/scripts/set-version.sh deleted file mode 100755 index 61bdfa2b32..0000000000 --- a/scripts/set-version.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -source "$(dirname "$0")/version-constants.sh" - -NEW_VERSION="$1" - - if [[ -z "NEW_VERSION" ]]; then - echo "You must specify a version." - exit 1 - fi - -echo "$VERSION_CONFIG_VAR = $NEW_VERSION" > $VERSION_CONFIG_FILE - -git add -A && git commit -m "$NEW_VERSION" -git tag "$NEW_VERSION" diff --git a/scripts/version-constants.sh b/scripts/version-constants.sh index ca550b7c2d..eaedbb262e 100644 --- a/scripts/version-constants.sh +++ b/scripts/version-constants.sh @@ -1,2 +1 @@ -VERSION_CONFIG_VAR="CURRENT_PROJECT_VERSION" -VERSION_CONFIG_FILE="Configuration/Shared/Project-Version.xcconfig" +APOLLO_CONSTANTS_FILE="Sources/Apollo/Constants.swift"