[
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing\n\nPlease note the following guidelines before submitting pull requests:\n\n- All new features must be covered by unit tests\n- Always create pull requests to the *main* branch\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n### What did you do?\n\n### What did you expect to happen?\n\n### What actually happened?\n\n### What version of this project are you using?\n\nPlease include code that reproduces the issue. The best reproductions are self-contained scripts with minimal dependencies.\n\n```php\ncode goes here\n```\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is.\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "(Please read the [guidelines](.github/CONTRIBUTING.md) before creating PRs.)\n\nFixes #.\n\nChanges proposed in this pull request:\n * \n * \n * \n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non: [push, pull_request, workflow_dispatch]\n\nenv:\n  FORCE_COLOR: 1\n\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        php-version: [\"7.1\", \"7.2\", \"7.3\", \"7.4\"]\n        os: [ubuntu-latest]\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - name: Set up PHP ${{ matrix.php-version }}\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php-version }}\n          coverage: xdebug\n\n      - name: Install dependencies\n        run: |\n          composer self-update\n          composer install\n\n      - name: Tests\n        run: |\n          composer ci\n\n      - name: Upload coverage results to Coveralls\n        env:\n          COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          wget https://github.com/php-coveralls/php-coveralls/releases/download/v1.0.1/coveralls.phar -O coveralls.phar\n          php coveralls.phar -v\n"
  },
  {
    "path": ".gitignore",
    "content": "/.idea/dictionaries\n/.idea/deployment.xml\n/.idea/webServers.xml\n/.idea/workspace.xml\n/.idea/php-test-framework.xml\n/coverage/\n/vendor/\nclover.xml\ncomposer.lock\ncachegrind.out.*\nphpunit.xml\n\n# TODO: Remove this once the printer has been implemented.\nsrc/Language/Printer*\n"
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <option name=\"WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN\" value=\"true\" />\n    <PHPCodeStyleSettings>\n      <option name=\"ALIGN_KEY_VALUE_PAIRS\" value=\"true\" />\n      <option name=\"ALIGN_PHPDOC_PARAM_NAMES\" value=\"true\" />\n      <option name=\"ALIGN_ASSIGNMENTS\" value=\"true\" />\n      <option name=\"LOWER_CASE_BOOLEAN_CONST\" value=\"true\" />\n      <option name=\"LOWER_CASE_NULL_CONST\" value=\"true\" />\n      <option name=\"ELSE_IF_STYLE\" value=\"COMBINE\" />\n      <option name=\"KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE\" value=\"true\" />\n      <option name=\"ALIGN_CLASS_CONSTANTS\" value=\"true\" />\n    </PHPCodeStyleSettings>\n    <codeStyleSettings language=\"GraphQL\">\n      <indentOptions>\n        <option name=\"INDENT_SIZE\" value=\"2\" />\n      </indentOptions>\n    </codeStyleSettings>\n    <codeStyleSettings language=\"PHP\">\n      <option name=\"BLANK_LINES_AFTER_PACKAGE\" value=\"1\" />\n      <option name=\"ALIGN_MULTILINE_PARAMETERS\" value=\"false\" />\n      <option name=\"CALL_PARAMETERS_WRAP\" value=\"1\" />\n      <option name=\"METHOD_PARAMETERS_WRAP\" value=\"5\" />\n      <option name=\"METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE\" value=\"true\" />\n      <option name=\"METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE\" value=\"true\" />\n      <option name=\"ARRAY_INITIALIZER_WRAP\" value=\"5\" />\n      <option name=\"ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE\" value=\"true\" />\n      <option name=\"ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE\" value=\"true\" />\n      <option name=\"IF_BRACE_FORCE\" value=\"3\" />\n      <option name=\"DOWHILE_BRACE_FORCE\" value=\"3\" />\n      <option name=\"WHILE_BRACE_FORCE\" value=\"3\" />\n      <option name=\"FOR_BRACE_FORCE\" value=\"3\" />\n    </codeStyleSettings>\n  </code_scheme>\n</component>"
  },
  {
    "path": ".idea/codeStyles/codeStyleConfig.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <state>\n    <option name=\"USE_PER_PROJECT_SETTINGS\" value=\"true\" />\n  </state>\n</component>"
  },
  {
    "path": ".idea/graphql-php.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"WEB_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\">\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/src\" isTestSource=\"false\" packagePrefix=\"Digia\\GraphQL\\\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/tests\" isTestSource=\"true\" packagePrefix=\"Digia\\GraphQL\\Test\\\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/composer\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/doctrine/instantiator\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/myclabs/deep-copy\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phar-io/manifest\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phar-io/version\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpdocumentor/reflection-common\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpdocumentor/reflection-docblock\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpspec/prophecy\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpunit/php-code-coverage\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpunit/php-file-iterator\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpunit/php-text-template\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpunit/php-timer\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpunit/php-token-stream\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/phpunit/phpunit\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/react/promise\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/comparator\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/diff\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/environment\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/exporter\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/global-state\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/object-enumerator\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/object-reflector\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/recursion-context\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/resource-operations\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/sebastian/version\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/theseer/tokenizer\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/vendor/webmozart/assert\" />\n    </content>\n    <orderEntry type=\"inheritedJdk\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n  </component>\n</module>"
  },
  {
    "path": ".idea/inspectionProfiles/Project_Default.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <profile version=\"1.0\">\n    <option name=\"myName\" value=\"Project Default\" />\n    <inspection_tool class=\"ForgottenDebugOutputInspection\" enabled=\"true\" level=\"ERROR\" enabled_by_default=\"true\">\n      <option name=\"configuration\">\n        <list>\n          <option value=\"\\Codeception\\Util\\Debug::debug\" />\n          <option value=\"\\Codeception\\Util\\Debug::pause\" />\n          <option value=\"\\Doctrine\\Common\\Util\\Debug::dump\" />\n          <option value=\"\\Doctrine\\Common\\Util\\Debug::export\" />\n          <option value=\"\\Illuminate\\Support\\Debug\\Dumper::dump\" />\n          <option value=\"\\Symfony\\Component\\Debug\\Debug::enable\" />\n          <option value=\"\\Symfony\\Component\\Debug\\DebugClassLoader::enable\" />\n          <option value=\"\\Symfony\\Component\\Debug\\ErrorHandler::register\" />\n          <option value=\"\\Symfony\\Component\\Debug\\ExceptionHandler::register\" />\n          <option value=\"\\TYPO3\\CMS\\Core\\Utility\\DebugUtility::debug\" />\n          <option value=\"\\Zend\\Debug\\Debug::dump\" />\n          <option value=\"\\Zend\\Di\\Display\\Console::export\" />\n          <option value=\"dd\" />\n          <option value=\"debug_print_backtrace\" />\n          <option value=\"debug_zval_dump\" />\n          <option value=\"dpm\" />\n          <option value=\"dpq\" />\n          <option value=\"dsm\" />\n          <option value=\"dvm\" />\n          <option value=\"error_log\" />\n          <option value=\"kpr\" />\n          <option value=\"phpinfo\" />\n          <option value=\"print_r\" />\n          <option value=\"var_dump\" />\n          <option value=\"var_export\" />\n          <option value=\"xdebug_break\" />\n          <option value=\"xdebug_call_class\" />\n          <option value=\"xdebug_call_file\" />\n          <option value=\"xdebug_call_function\" />\n          <option value=\"xdebug_call_line\" />\n          <option value=\"xdebug_code_coverage_started\" />\n          <option value=\"xdebug_debug_zval\" />\n          <option value=\"xdebug_debug_zval_stdout\" />\n          <option value=\"xdebug_dump_superglobals\" />\n          <option value=\"xdebug_enable\" />\n          <option value=\"xdebug_get_code_coverage\" />\n          <option value=\"xdebug_get_collected_errors\" />\n          <option value=\"xdebug_get_declared_vars\" />\n          <option value=\"xdebug_get_function_stack\" />\n          <option value=\"xdebug_get_headers\" />\n          <option value=\"xdebug_get_monitored_functions\" />\n          <option value=\"xdebug_get_profiler_filename\" />\n          <option value=\"xdebug_get_stack_depth\" />\n          <option value=\"xdebug_get_tracefile_name\" />\n          <option value=\"xdebug_is_enabled\" />\n          <option value=\"xdebug_memory_usage\" />\n          <option value=\"xdebug_peak_memory_usage\" />\n          <option value=\"xdebug_print_function_stack\" />\n          <option value=\"xdebug_start_code_coverage\" />\n          <option value=\"xdebug_start_error_collection\" />\n          <option value=\"xdebug_start_function_monitor\" />\n          <option value=\"xdebug_start_trace\" />\n          <option value=\"xdebug_stop_code_coverage\" />\n          <option value=\"xdebug_stop_error_collection\" />\n          <option value=\"xdebug_stop_function_monitor\" />\n          <option value=\"xdebug_stop_trace\" />\n          <option value=\"xdebug_time_index\" />\n          <option value=\"xdebug_var_dump\" />\n        </list>\n      </option>\n      <option name=\"migratedIntoUserSpace\" value=\"true\" />\n    </inspection_tool>\n    <inspection_tool class=\"MoreThanThreeArgumentsInspection\" enabled=\"false\" level=\"WARNING\" enabled_by_default=\"false\" />\n    <inspection_tool class=\"PhpFullyQualifiedNameUsageInspection\" enabled=\"false\" level=\"WARNING\" enabled_by_default=\"false\" />\n    <inspection_tool class=\"SecurityAdvisoriesInspection\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\">\n      <option name=\"optionConfiguration\">\n        <list>\n          <option value=\"behat/behat\" />\n          <option value=\"brianium/paratest\" />\n          <option value=\"codeception/codeception\" />\n          <option value=\"composer/composer\" />\n          <option value=\"filp/whoops\" />\n          <option value=\"friendsofphp/php-cs-fixer\" />\n          <option value=\"humbug/humbug\" />\n          <option value=\"infection/infection\" />\n          <option value=\"jakub-onderka/php-parallel-lint\" />\n          <option value=\"johnkary/phpunit-speedtrap\" />\n          <option value=\"mikey179/vfsStream\" />\n          <option value=\"mockery/mockery\" />\n          <option value=\"pdepend/pdepend\" />\n          <option value=\"phan/phan\" />\n          <option value=\"phing/phing\" />\n          <option value=\"phpmd/phpmd\" />\n          <option value=\"phpro/grumphp\" />\n          <option value=\"phpspec/phpspec\" />\n          <option value=\"phpspec/prophecy\" />\n          <option value=\"phpstan/phpstan\" />\n          <option value=\"phpunit/dbunit\" />\n          <option value=\"phpunit/phpunit\" />\n          <option value=\"povils/phpmnd\" />\n          <option value=\"satooshi/php-coveralls\" />\n          <option value=\"sebastian/phpcpd\" />\n          <option value=\"slevomat/coding-standard\" />\n          <option value=\"squizlabs/php_codesniffer\" />\n          <option value=\"symfony/debug\" />\n          <option value=\"symfony/phpunit-bridge\" />\n          <option value=\"symfony/var-dumper\" />\n          <option value=\"vimeo/psalm\" />\n          <option value=\"yiisoft/yii2-debug\" />\n          <option value=\"yiisoft/yii2-gii\" />\n          <option value=\"zendframework/zend-debug\" />\n          <option value=\"zendframework/zend-test\" />\n        </list>\n      </option>\n      <option name=\"optionConfigurationMigrated\" value=\"true\" />\n    </inspection_tool>\n  </profile>\n</component>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/graphql-php.iml\" filepath=\"$PROJECT_DIR$/.idea/graphql-php.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/php.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"PhpIncludePathManager\">\n    <include_path>\n      <path value=\"$PROJECT_DIR$/vendor/composer\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/recursion-context\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/resource-operations\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/version\" />\n      <path value=\"$PROJECT_DIR$/vendor/theseer/tokenizer\" />\n      <path value=\"$PROJECT_DIR$/vendor/doctrine/instantiator\" />\n      <path value=\"$PROJECT_DIR$/vendor/webmozart/assert\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpdocumentor/type-resolver\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpdocumentor/reflection-common\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/object-enumerator\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/global-state\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/object-reflector\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/diff\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/comparator\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/environment\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup\" />\n      <path value=\"$PROJECT_DIR$/vendor/sebastian/exporter\" />\n      <path value=\"$PROJECT_DIR$/vendor/myclabs/deep-copy\" />\n      <path value=\"$PROJECT_DIR$/vendor/phar-io/manifest\" />\n      <path value=\"$PROJECT_DIR$/vendor/phar-io/version\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpspec/prophecy\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpunit/php-timer\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpunit/php-file-iterator\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpunit/php-text-template\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpunit/php-token-stream\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpunit/php-code-coverage\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpunit/phpunit\" />\n      <path value=\"$PROJECT_DIR$/vendor/container-interop/container-interop\" />\n      <path value=\"$PROJECT_DIR$/vendor/league/container\" />\n      <path value=\"$PROJECT_DIR$/vendor/psr/container\" />\n      <path value=\"$PROJECT_DIR$/vendor/psr/simple-cache\" />\n      <path value=\"$PROJECT_DIR$/vendor/symfony/finder\" />\n      <path value=\"$PROJECT_DIR$/vendor/symfony/polyfill-mbstring\" />\n      <path value=\"$PROJECT_DIR$/vendor/ocramius/package-versions\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpstan/phpstan\" />\n      <path value=\"$PROJECT_DIR$/vendor/symfony/console\" />\n      <path value=\"$PROJECT_DIR$/vendor/phpstan/phpdoc-parser\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/php-generator\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/finder\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/bootstrap\" />\n      <path value=\"$PROJECT_DIR$/vendor/jean85/pretty-package-versions\" />\n      <path value=\"$PROJECT_DIR$/vendor/nikic/php-parser\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/di\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/robot-loader\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/utils\" />\n      <path value=\"$PROJECT_DIR$/vendor/nette/neon\" />\n      <path value=\"$PROJECT_DIR$/vendor/react/promise\" />\n    </include_path>\n  </component>\n  <component name=\"PhpProjectSharedConfiguration\" php_language_level=\"7.1\" />\n  <component name=\"PhpUnit\">\n    <phpunit_settings>\n      <PhpUnitSettings load_method=\"CUSTOM_LOADER\" custom_loader_path=\"$PROJECT_DIR$/vendor/autoload.php\" phpunit_phar_path=\"\" />\n    </phpunit_settings>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change log\n\n## 1.1.0\n\n* Add initial support for execution strategies\n* Add support for error handling middleware \n* Fix some bugs in the error handling\n* Fix some type-hint issues\n* Run Travis CI tests on PHP 7.3 too, improve build times by caching\n\n## 1.0.3\n\n* Drastically reduce the number of container `make()` ([#332](https://github.com/digiaonline/graphql-php/pull/332))\n\n## 1.0.2\n\n* Expanded the README table of contents somewhat ([#329](https://github.com/digiaonline/graphql-php/pull/329))\n* Don't validate the schema again while validating the query against it ([#328](https://github.com/digiaonline/graphql-php/pull/328))\n* Fix some incorrect type-hints in `ExecutionResult` ([#327](https://github.com/digiaonline/graphql-php/pull/327))\n* Fix resolver example in the README ([#313](https://github.com/digiaonline/graphql-php/pull/313))\n\n## 1.0.1\n\n* Fix a bug where you could not use `false` as value for `Boolean!` input types ([#311](https://github.com/digiaonline/graphql-php/pull/311))\n* Add a code of conduct ([#312](https://github.com/digiaonline/graphql-php/pull/312))\n* Fix resolver middleware example ([#309](https://github.com/digiaonline/graphql-php/pull/309))\n* Introduce `VisitorInfo` concept ([#308](https://github.com/digiaonline/graphql-php/pull/308))\n\n## 1.0.0\n\n* Initial release\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at christofferniska@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Digia\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# GraphQL\n\n[![GitHub Actions status](https://github.com/digiaonline/graphql-php/workflows/Test/badge.svg)](https://github.com/digiaonline/graphql-php/actions)\n[![Coverage Status](https://coveralls.io/repos/github/digiaonline/graphql-php/badge.svg?branch=main)](https://coveralls.io/github/digiaonline/graphql-php?branch=main)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/digiaonline/graphql-php/badges/quality-score.png?b=main)](https://scrutinizer-ci.com/g/digiaonline/graphql-php/?branch=main)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/digiaonline/graphql-php/main/LICENSE)\n[![Backers on Open Collective](https://opencollective.com/graphql-php/backers/badge.svg)](#backers) \n[![Sponsors on Open Collective](https://opencollective.com/graphql-php/sponsors/badge.svg)](#sponsors) \n\nThis is a PHP implementation of the [GraphQL specification](https://facebook.github.io/graphql/) based on the \nJavaScript [reference implementation](https://github.com/graphql/graphql-js).\n\n## Related projects\n\n- [DateTime scalar](https://github.com/digiaonline/graphql-datetime-scalar-php)\n- [Relay support](https://github.com/digiaonline/graphql-relay-php)\n\n## Requirements\n\n- PHP version >= 7.1\n- ext-mbstring\n\n## Table of contents\n\n- [Installation](#installation)\n- [Example](#example)\n- [Creating a schema](#creating-a-schema)\n  - [Resolver registry](#resolver-registry)\n  - [Resolver middleware](#resolver-middleware)\n- [Execution](#execution)\n  - [Queries](#queries)\n  - [Resolvers](#resolvers)\n    - [The N+1 problem](#the-n1-problem)\n  - [Variables](#variables)\n  - [Context](#context)\n- [Scalars](#scalars)\n  - [Custom scalars](#custom-scalars)\n- [Advanced usage](#advanced-usage)\n- [Integration](#integration)\n  - [Laravel](#laravel)\n\n## Installation\n\nRun the following command to install the package through Composer:\n\n```sh\ncomposer require digiaonline/graphql\n```\n\n## Example\n\nHere is a simple example that demonstrates how to build an executable schema from a GraphQL schema file that contains \nthe Schema Definition Language (SDL) for a Star Wars-themed schema (for the schema definition itself, see below). In \nthis example we use that SDL to build an executable schema and use it to query for the name of the hero. The result \nof that query is an associative array with a structure that resembles the query we ran.\n\n```php\nuse Digia\\GraphQL\\Language\\FileSourceBuilder;\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\graphql;\n\n$sourceBuilder = new FileSourceBuilder(__DIR__ . '/star-wars.graphqls');\n\n$schema = buildSchema($sourceBuilder->build(), [\n    'Query' => [\n        'hero' => function ($rootValue, $arguments) {\n            return getHero($arguments['episode'] ?? null);\n        },\n    ],\n]);\n\n$result = graphql($schema, '\nquery HeroNameQuery {\n  hero {\n    name\n  }\n}');\n\n\\print_r($result);\n```\n\nThe script above produces the following output:\n\n```php\nArray\n(\n    [data] => Array\n    (\n        [hero] => Array\n        (\n            [name] => \"R2-D2\"\n        )\n        \n    )\n    \n)\n```\n\nThe GraphQL schema file used in this example contains the following:\n\n```graphql schema\nschema {\n    query: Query\n}\n\ntype Query {\n    hero(episode: Episode): Character\n    human(id: String!): Human\n    droid(id: String!): Droid\n}\n\ninterface Character {\n    id: String!\n    name: String\n    friends: [Character]\n    appearsIn: [Episode]\n}\n\ntype Human implements Character {\n    id: String!\n    name: String\n    friends: [Character]\n    appearsIn: [Episode]\n    homePlanet: String\n}\n\ntype Droid implements Character {\n    id: String!\n    name: String\n    friends: [Character]\n    appearsIn: [Episode]\n    primaryFunction: String\n}\n\nenum Episode { NEWHOPE, EMPIRE, JEDI }\n```\n\n## Creating a schema\n\nIn order to execute queries against your GraphQL API, you first need to define the structure of your API. This is done\nby creating a schema. There are two ways to do this, you can either do it using SDL or you can do it programmatically. \nHowever, we strongly encourage you to use SDL, because it is easier to work with. To make an executable schema from \nSDL you need to call the `buildSchema` function.\n \nThe `buildSchema` function takes three arguments:\n\n- `$source` The schema definition (SDL) as a `Source` instance\n- `$resolverRegistry` An associative array or a `ResolverRegistry` instance that contains all resolvers\n- `$options` The options for building the schema, which also includes custom types and directives\n\nTo create the `Source` instance you can use the provided `FileSourceBuilder` or `MultiFileSourceBuilder` classes.\n\n### Resolver registry\n\nThe resolver registry is essentially a flat map with the type names as its keys and their corresponding resolver \ninstances as its values. For smaller projects you can use an associative array and lambda functions to define your \nresolver registry. However, in larger projects we suggest that you implement your own resolvers instead. You can read \nmore about resolvers under the [Resolvers](#resolvers) section.\n\nAssociative array example:\n\n```php\n$schema = buildSchema($source, [\n    'Query' => [\n        'hero' => function ($rootValue, $arguments) {\n            return getHero($arguments['episode'] ?? null);\n        },\n    ],\n]);\n```\n\nResolver class example:\n\n```php\n$schema = buildSchema($source, [\n    'Query' => [\n        'hero' => new HeroResolver(),\n    ],\n]);\n```\n\n### Resolver middleware\n\nIf you find yourself writing the same logic in multiple resolvers you should consider using middleware. Resolver \nmiddleware allow you to efficiently manage functionality across multiple resolvers.\n\nBefore middleware example:\n\n```php\n$resolverRegistry = new ResolverRegristry([\n    'Query' => [\n        'hero' => function ($rootValue, $arguments) {\n            return getHero($arguments['episode'] ?? null);\n        },\n    ],\n], [\n    'middleware' => [new BeforeMiddleware()],\n]);\n$schema = buildSchema($source, $resolverRegistry);\n```\n\n```php\nclass BeforeMiddleware implements ResolverMiddlewareInterface\n{\n    public function resolve(callable $resolveCallback, $rootValue, array $arguments, $context, ResolveInfo $info) {\n        $newRootValue = $this->doSomethingBefore();\n        return $resolveCallback($newRootValue, $arguments, $context, $info);\n    }\n}\n```\n\nAfter middleware example:\n\n```php\n$resolverRegistry = new ResolverRegristry([\n    'Query' => [\n        'hero' => function ($rootValue, $arguments) {\n            return getHero($arguments['episode'] ?? null);\n        },\n    ],\n], [\n    'middleware' => [new AfterMiddleware()],\n]);\n$schema = buildSchema($source, $resolverRegistry);\n```\n\n```php\nclass AfterMiddleware implements ResolverMiddlewareInterface\n{\n    public function resolve(callable $resolveCallback, $rootValue, array $arguments, $context, ResolveInfo $info) {\n        $result = $resolveCallback($rootValue, $arguments, $context, $info);\n        $this->doSomethingAfter();\n        return $result;\n    }\n}\n```\n\nResolver middleware can be useful for a number of things; such as logging, input sanitization, performance \nmeasurement, authorization and caching.\n\nIf you want to learn more about schemas you can refer to the [specification](https://graphql.org/learn/schema/).\n\n## Execution\n\n### Queries\n\nTo execute a query against your schema you need to call the `graphql` function and pass it your schema and the query \nyou wish to execute. You can also run _mutations_ and _subscriptions_ by changing your query.\n\n```php\n$query = '\nquery HeroNameQuery {\n  hero {\n    name\n  }\n}';\n\n$result = graphql($schema, $query);\n```\n\nIf you want to learn more about queries you can refer to the [specification](https://graphql.org/learn/queries/).\n\n### Resolvers\n\nEach type in a schema has a resolver associated with it that allows for resolving the actual value. However, most \ntypes do not need a custom resolver, because they can be resolved using the default resolver. Usually these resolvers \nare lambda functions, but you can also define your own resolvers by extending `AbstractTypeResolver` or `AbstractFieldResolver`. Alternatively you can also implement the `ResolverInterface` directly.\n\nA resolver function receives four arguments:\n\n- `$rootValue` The parent object, which can also be `null` in some cases\n- `$arguments` The arguments provided to the field in the query\n- `$context` A value that is passed to every resolver that can hold important contextual information\n- `$info` A value which holds field-specific information relevant to the current query\n\nLambda function example:\n\n```php\nfunction ($rootValue, array $arguments, $context, ResolveInfo $info): string {\n    return [\n        'type'       => 'Human',\n        'id'         => '1000',\n        'name'       => 'Luke Skywalker',\n        'friends'    => ['1002', '1003', '2000', '2001'],\n        'appearsIn'  => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n        'homePlanet' => 'Tatooine',\n    ];\n}\n``` \n\nType resolver example:\n\n```php\nclass HumanResolver extends AbstractTypeResolver\n{\n    public function resolveName($rootValue, array $arguments, $context, ResolveInfo $info): string\n    {\n        return $rootValue['name'];\n    }\n}\n```\n\nField resolver example:\n\n```php\nclass NameResolver extends AbstractFieldResolver\n{\n    public function resolve($rootValue, array $arguments, $context, ResolveInfo $info): string\n    {\n       return $rootValue['name'];\n    }\n}\n```\n\n#### The N+1 problem\n\nThe resolver function can return a value, a [promise](https://github.com/reactphp/promise) or an array of promises. \nThis resolver function below illustrates how to use promise to solve the N+1 problem, the full example can be found in \nthis [test case](/tests/Functional/Execution/DeferredResolverTest.php).\n\n```php\n$movieType = newObjectType([\n    'fields' => [\n        'title'    => ['type' => stringType()],\n        'director' => [\n            'type'    => $directorType,\n            'resolve' => function ($movie, $args) {\n                DirectorBuffer::add($movie['directorId']);\n                \n                return new Promise(function (callable $resolve, callable $reject) use ($movie) {\n                    DirectorBuffer::loadBuffered();\n                    $resolve(DirectorBuffer::get($movie['directorId']));\n                });\n            }\n        ]\n    ]\n]);\n```\n\n### Variables\n\nYou can pass in variables when executing a query by passing them to the `graphql` function.\n\n```php\n$query = '\nquery HeroNameQuery($id: ID!) {\n  hero(id: $id) {\n    name\n  }\n}';\n\n$variables = ['id' => '1000'];\n\n$result = graphql($schema, $query, null, null, $variables);\n```\n\n### Context\n\nIn case you need to pass in some important contextual information to your queries you can use the `$contextValues` \nargument on `graphql` to do so. This data will be passed to all of your resolvers as the `$context` argument.\n\n```php\n$contextValues = [\n    'currentlyLoggedInUser' => $currentlyLoggedInUser,\n];\n\n$result = graphql($schema, $query, null, $contextValues, $variables);\n```\n\n## Scalars\n\nThe leaf nodes in a schema are called scalars and each scalar resolves to some concrete data. The built-in, or \nspecified scalars in GraphQL are the following:\n\n- Boolean\n- Float\n- Int\n- ID\n- String\n\n### Custom scalars\n\nIn addition to the specified scalars you can also define your own custom scalars and let your schema know about \nthem by passing them to the `buildSchema` function as part of its `$options` argument. \n\nCustom Date scalar type example:\n\n```php\n$dateType = newScalarType([\n    'name'         => 'Date',\n    'serialize'    => function ($value) {\n        if ($value instanceof DateTime) {\n            return $value->format('Y-m-d');\n        }\n        return null;\n    },\n    'parseValue'   => function ($value) {\n        if (\\is_string($value)){\n            return new DateTime($value);\n        }\n        return null;\n    },\n    'parseLiteral' => function ($node) {\n        if ($node instanceof StringValueNode) {\n            return new DateTime($node->getValue());\n        }\n        return null;\n    },\n]);\n\n$schema = buildSchema($source, [\n    'Query' => QueryResolver::class,\n    [\n        'types' => [$dateType],\n    ],\n]);\n```\n\nEvery scalar has to be coerced, which is done by three different functions. The `serialize` function converts a \nPHP value into the corresponding output value. The`parseValue` function converts a variable input value into the\ncorresponding PHP value and the `parseLiteral` function converts an AST literal into the corresponding PHP value.\n\n## Advanced usage\n\nIf you are looking for something that isn't yet covered by this documentation your best bet is to take a look at the \n[tests](./tests) in this project. You'll be surprised how many examples you'll find there.\n\n## Integration\n\n### Laravel\n\nHere is an example that demonstrates how you can use this library in your Laravel project. You need an application \nservice to expose this library to your application, a service provider to register that service, a controller and a \nroute for handling the GraphQL POST requests.\n\n**app/GraphQL/GraphQLService.php**\n```php\nclass GraphQLService\n{\n    private $schema;\n\n    public function __construct(Schema $schema)\n    {\n        $this->schema = $schema;\n    }\n\n    public function executeQuery(string $query, array $variables, ?string $operationName): array\n    {\n        return graphql($this->schema, $query, null, null, $variables, $operationName);\n    }\n}\n```\n\n**app/GraphQL/GraphQLServiceProvider.php**\n```php\nclass GraphQLServiceProvider\n{\n    public function register()\n    {\n        $this->app->singleton(GraphQLService::class, function () {\n            $schemaDef = \\file_get_contents(__DIR__ . '/schema.graphqls');\n\n            $executableSchema = buildSchema($schemaDef, [\n                'Query' => QueryResolver::class,\n            ]);\n\n            return new GraphQLService($executableSchema);\n        });\n    }\n}\n```\n\n**app/GraphQL/GraphQLController.php**\n```php\nclass GraphQLController extends Controller\n{\n    private $graphqlService;\n\n    public function __construct(GraphQLService $graphqlService)\n    {\n        $this->graphqlService = $graphqlService;\n    }\n\n    public function handle(Request $request): JsonResponse\n    {\n        $query         = $request->get('query');\n        $variables     = $request->get('variables') ?? [];\n        $operationName = $request->get('operationName');\n\n        $result = $this->graphqlService->executeQuery($query, $variables, $operationName);\n\n        return response()->json($result);\n    }\n}\n```\n\n**routes/api.php**\n```php\nRoute::post('/graphql', 'app\\GraphQL\\GraphQLController@handle');\n```\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. [Contribute](.github/CONTRIBUTING.md).\n\n<a href=\"graphs/contributors\"><img src=\"https://opencollective.com/graphql-php/contributors.svg?width=890&button=false\" /></a>\n\n\n## Backers\n\nThank you to all our backers! 🙏 [Become a backer](https://opencollective.com/graphql-php#backer)\n\n<a href=\"https://opencollective.com/graphql-php#backers\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/backers.svg?width=890\"></a>\n\n## Sponsors\n\nSupport this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/graphql-php#sponsor)\n\n<a href=\"https://opencollective.com/graphql-php/sponsor/0/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/0/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/1/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/1/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/2/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/2/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/3/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/3/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/4/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/4/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/5/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/5/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/6/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/6/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/7/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/7/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/8/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/8/avatar.svg\"></a>\n<a href=\"https://opencollective.com/graphql-php/sponsor/9/website\" target=\"_blank\"><img src=\"https://opencollective.com/graphql-php/sponsor/9/avatar.svg\"></a>\n\n## License\n\nSee [LICENCE](LICENSE).\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"digiaonline/graphql\",\n    \"description\": \"A PHP7 implementation of the GraphQL specifications.\",\n    \"type\": \"library\",\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Christoffer Niska\",\n            \"email\": \"christofferniska@gmail.com\"\n        },\n        {\n            \"name\": \"Hung Nguyen\",\n            \"email\": \"hungneox@gmail.com\"\n        },\n        {\n            \"name\": \"Sam Stenvall\",\n            \"email\": \"sam.stenvall@digia.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=7.1\",\n        \"ext-mbstring\": \"*\",\n        \"league/container\": \"^3.2\",\n        \"react/promise\": \"^2.5\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^7.0\",\n        \"phpstan/phpstan\": \"^0.9.2\"\n    },\n    \"autoload\": {\n        \"files\": [\n            \"./src/Error/helpers.php\",\n            \"./src/Language/blockStringValue.php\",\n            \"./src/Language/utils.php\",\n            \"./src/Schema/utils.php\",\n            \"./src/Type/definition.php\",\n            \"./src/Type/directives.php\",\n            \"./src/Type/introspection.php\",\n            \"./src/Type/scalars.php\",\n            \"./src/Util/utils.php\",\n            \"./src/Validation/messages.php\",\n            \"./src/api.php\"\n        ],\n        \"psr-4\": {\n            \"Digia\\\\GraphQL\\\\\": \"./src\"\n        }\n    },\n    \"scripts\": {\n        \"test\": [\n            \"phpunit\",\n            \"phpstan analyse -l 4 src/\"\n        ],\n        \"ci\": [\n            \"phpunit --coverage-clover build/logs/clover.xml\",\n            \"phpstan analyse -l 4 src/\"\n        ]\n    },\n    \"autoload-dev\": {\n        \"files\": [\n            \"./tests/Functional/Execution/testClasses.php\",\n            \"./tests/Functional/Validation/errors.php\",\n            \"./tests/Functional/Validation/harness.php\",\n            \"./tests/Functional/starWarsData.php\",\n            \"./tests/Functional/starWarsSchema.php\",\n            \"./tests/utils.php\"\n        ],\n        \"psr-4\": {\n            \"Digia\\\\GraphQL\\\\Test\\\\\": \"./tests\"\n        }\n    }\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/7.0/phpunit.xsd\"\n         bootstrap=\"vendor/autoload.php\"\n         forceCoversAnnotation=\"false\"\n         beStrictAboutCoversAnnotation=\"true\"\n         beStrictAboutOutputDuringTests=\"true\"\n         beStrictAboutTodoAnnotatedTests=\"true\"\n         verbose=\"true\">\n    <testsuite name=\"default\">\n        <directory suffix=\"Test.php\">tests</directory>\n    </testsuite>\n\n    <filter>\n        <whitelist processUncoveredFilesFromWhitelist=\"true\">\n            <directory suffix=\".php\">src</directory>\n        </whitelist>\n    </filter>\n</phpunit>\n"
  },
  {
    "path": "src/Error/AbstractException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error;\n\n/**\n * Class AbstractException\n * @package Digia\\GraphQL\\Error\n */\nabstract class AbstractException extends \\Exception\n{\n\n}\n"
  },
  {
    "path": "src/Error/FileNotFoundException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error;\n\n/**\n * Class FileNotFoundException\n * @package Digia\\GraphQL\\Error\n */\nclass FileNotFoundException extends AbstractException\n{\n\n}\n"
  },
  {
    "path": "src/Error/GraphQLException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Language\\SourceLocation;\nuse Digia\\GraphQL\\Util\\ArrayToJsonTrait;\nuse Digia\\GraphQL\\Util\\SerializationInterface;\n\n/**\n * An GraphQLException describes an exception thrown during the execute\n * phase 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 */\nclass GraphQLException extends AbstractException implements SerializationInterface\n{\n    use ArrayToJsonTrait;\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     * @var array|null\n     */\n    protected $locations;\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     * @var string[]|null\n     */\n    protected $path;\n\n    /**\n     * An array of GraphQL AST Nodes corresponding to this error.\n     *\n     * @var NodeInterface[]|null\n     */\n    protected $nodes;\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     * @var Source|null\n     */\n    protected $source;\n\n    /**\n     * An array of character offsets within the source GraphQL document\n     * which correspond to this error.\n     *\n     * @var int[]|null\n     */\n    protected $positions;\n\n    /**\n     * Extension fields to add to the formatted error.\n     *\n     * @var array|null\n     */\n    protected $extensions;\n\n    /**\n     * @var null|\\Throwable\n     */\n    protected $originalException;\n\n    /**\n     * ExecutionException constructor.\n     *\n     * @param string          $message\n     * @param array|null      $nodes\n     * @param Source|null     $source\n     * @param array|null      $positions\n     * @param array|null      $path\n     * @param array|null      $extensions\n     * @param \\Throwable|null $originalException\n     */\n    public function __construct(\n        string $message,\n        ?array $nodes = null,\n        ?Source $source = null,\n        ?array $positions = null,\n        ?array $path = null,\n        ?array $extensions = null,\n        ?\\Throwable $originalException = null\n    ) {\n        parent::__construct($message);\n\n        $this->resolveNodes($nodes);\n        $this->resolveSource($source);\n        $this->resolvePositions($positions);\n        $this->resolveLocations($positions, $source);\n\n        $this->path              = $path;\n        $this->extensions        = $extensions;\n        $this->originalException = $originalException;\n    }\n\n    /**\n     * @return NodeInterface[]\n     */\n    public function getNodes(): ?array\n    {\n        return $this->nodes;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasSource(): bool\n    {\n        return null !== $this->source;\n    }\n\n    /**\n     * @return Source|null\n     */\n    public function getSource(): ?Source\n    {\n        return $this->source;\n    }\n\n    /**\n     * @return int[]|null\n     */\n    public function getPositions(): ?array\n    {\n        return $this->positions;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasLocations(): bool\n    {\n        return !empty($this->locations);\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getLocations(): ?array\n    {\n        return $this->locations;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getLocationsAsArray(): ?array\n    {\n        return !empty($this->locations) ? \\array_map(function (SourceLocation $location) {\n            return $location->toArray();\n        }, $this->locations) : null;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getPath(): ?array\n    {\n        return $this->path;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getExtensions(): ?array\n    {\n        return $this->extensions;\n    }\n\n    /**\n     * @param array|null $extensions\n     * @return self\n     */\n    public function setExtensions(?array $extensions): self\n    {\n        $this->extensions = $extensions;\n        return $this;\n    }\n\n    /**\n     * @return \\Throwable|null\n     */\n    public function getOriginalException(): ?\\Throwable\n    {\n        return $this->originalException;\n    }\n\n    /**\n     * @return null|string\n     */\n    public function getOriginalErrorMessage(): ?string\n    {\n        return null !== $this->originalException ? $this->originalException->getMessage() : null;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toArray(): array\n    {\n        $result = [\n            'message'   => $this->message,\n            // TODO: Do not include `locations` if `null` (similar to `path` and `extensions`).\n            'locations' => $this->getLocationsAsArray(),\n        ];\n\n        if (null !== $this->path) {\n            $result['path'] = $this->path;\n        }\n\n        if (null !== $this->extensions) {\n            $result['extensions'] = $this->extensions;\n        }\n\n        return $result;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return printError($this);\n    }\n\n    /**\n     * @param array|null $nodes\n     * @return $this\n     */\n    protected function resolveNodes(?array $nodes): self\n    {\n        if (\\is_array($nodes)) {\n            $nodes = !empty($nodes) ? $nodes : [];\n        } else {\n            $nodes = [$nodes];\n        }\n\n        $this->nodes = \\array_filter($nodes, function ($node) {\n            return null !== $node;\n        });\n\n        return $this;\n    }\n\n    /**\n     * @param Source|null $source\n     * @return $this\n     */\n    protected function resolveSource(?Source $source): self\n    {\n        if (null === $source && !empty($this->nodes)) {\n            $firstNode = $this->nodes[0] ?? null;\n            $location  = null !== $firstNode ? $firstNode->getLocation() : null;\n            $source    = null !== $location ? $location->getSource() : null;\n        }\n\n        $this->source = $source;\n\n        return $this;\n    }\n\n    /**\n     * @param array|null $positions\n     * @return $this\n     */\n    protected function resolvePositions(?array $positions): self\n    {\n        if (null === $positions && !empty($this->nodes)) {\n            $positions = \\array_reduce($this->nodes, function (array $list, ?NodeInterface $node) {\n                if (null !== $node) {\n                    $location = $node->getLocation();\n                    if (null !== $location) {\n                        $list[] = $location->getStart();\n                    }\n                }\n                return $list;\n            }, []);\n        }\n\n        if (null !== $positions && empty($positions)) {\n            $positions = null;\n        }\n\n        $this->positions = $positions;\n\n        return $this;\n    }\n\n    /**\n     * @param array|null  $positions\n     * @param Source|null $source\n     * @return $this\n     */\n    protected function resolveLocations(?array $positions, ?Source $source): self\n    {\n        $locations = null;\n\n        if (null !== $positions && null !== $source) {\n            $locations = \\array_map(function ($position) use ($source) {\n                return SourceLocation::fromSource($source, $position);\n            }, $positions);\n        } elseif (!empty($this->nodes)) {\n            $locations = \\array_reduce($this->nodes, function (array $list, NodeInterface $node) {\n                $location = $node->getLocation();\n                if (null !== $location) {\n                    $list[] = SourceLocation::fromSource($location->getSource(), $location->getStart());\n                }\n                return $list;\n            }, []);\n        }\n\n        if ($locations !== null) {\n            $this->locations = $locations;\n        }\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Error/Handler/AbstractErrorMiddleware.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error\\Handler;\n\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\n\nabstract class AbstractErrorMiddleware implements ErrorMiddlewareInterface\n{\n    /**\n     * @inheritdoc\n     */\n    public function handleError(\\Throwable $exception, callable $next)\n    {\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context, callable $next)\n    {\n    }\n}\n"
  },
  {
    "path": "src/Error/Handler/CallableMiddleware.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error\\Handler;\n\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\n\nclass CallableMiddleware extends AbstractErrorMiddleware\n{\n    /**\n     * @var callable\n     */\n    protected $handleCallback;\n\n    /**\n     * CallableMiddleware constructor.\n     * @param callable $handleCallback\n     */\n    public function __construct(callable $handleCallback)\n    {\n        $this->handleCallback = $handleCallback;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context, callable $next)\n    {\n        \\call_user_func($this->handleCallback, $exception, $context, $next);\n    }\n}\n"
  },
  {
    "path": "src/Error/Handler/ErrorHandler.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error\\Handler;\n\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\n\nclass ErrorHandler implements ErrorHandlerInterface\n{\n    /**\n     * @var ErrorMiddlewareInterface[]\n     */\n    protected $middleware = [];\n\n    /**\n     * ErrorHandler constructor.\n     * @param ErrorMiddlewareInterface[] $middleware\n     */\n    public function __construct(array $middleware)\n    {\n        foreach ($middleware as $mw) {\n            $this->addMiddleware($mw);\n        }\n    }\n\n    /**\n     * @param \\Throwable $exception\n     */\n    public function handleError(\\Throwable $exception): void\n    {\n        $next = function () {\n            // NO-OP\n        };\n\n        foreach ($this->middleware as $middleware) {\n            $next = function (\\Throwable $exception) use ($middleware, $next) {\n                return $middleware->handleError($exception, $next);\n            };\n        }\n\n        $next($exception);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context): void\n    {\n        $next = function () {\n            // NO-OP\n        };\n\n        foreach ($this->middleware as $middleware) {\n            $next = function (ExecutionException $exception, ExecutionContext $context) use ($middleware, $next) {\n                return $middleware->handleExecutionError($exception, $context, $next);\n            };\n        }\n\n        $next($exception, $context);\n    }\n\n    /**\n     * @param ErrorMiddlewareInterface $middleware\n     */\n    protected function addMiddleware(ErrorMiddlewareInterface $middleware): void\n    {\n        \\array_unshift($this->middleware, $middleware);\n    }\n}\n"
  },
  {
    "path": "src/Error/Handler/ErrorHandlerInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error\\Handler;\n\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\n\ninterface ErrorHandlerInterface\n{\n    /**\n     * @param \\Throwable $exception\n     */\n    public function handleError(\\Throwable $exception): void;\n\n    /**\n     * @param ExecutionException    $exception\n     * @param ExecutionContext $context\n     */\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context): void;\n}\n"
  },
  {
    "path": "src/Error/Handler/ErrorMiddlewareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error\\Handler;\n\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\n\ninterface ErrorMiddlewareInterface\n{\n    /**\n     * @param \\Throwable $exception\n     * @param callable   $next\n     * @return mixed\n     */\n    public function handleError(\\Throwable $exception, callable $next);\n\n    /**\n     * @param ExecutionException $exception\n     * @param ExecutionContext   $context\n     * @param callable           $next\n     * @return mixed\n     */\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context, callable $next);\n}\n"
  },
  {
    "path": "src/Error/InvalidTypeException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error;\n\nclass InvalidTypeException extends GraphQLException\n{\n}\n"
  },
  {
    "path": "src/Error/InvariantException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error;\n\n/**\n * Class InvariantException\n * @package Digia\\GraphQL\\Error\n */\nclass InvariantException extends AbstractException\n{\n\n}\n"
  },
  {
    "path": "src/Error/helpers.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Error;\n\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Language\\SourceLocation;\n\n// Format error\n\n/**\n * @param GraphQLException|null $error\n * @return array\n * @throws InvariantException\n */\nfunction formatError(?GraphQLException $error): array\n{\n    if (null === $error) {\n        throw new InvariantException('Received null error.');\n    }\n\n    return [\n        'message'   => $error->getMessage(),\n        'locations' => $error->getLocationsAsArray(),\n        'path'      => $error->getPath(),\n    ];\n}\n\n// Print error\n\n/**\n * @param GraphQLException $error\n * @return string\n */\nfunction printError(GraphQLException $error): string\n{\n    $printedLocations = [];\n    $nodes            = $error->getNodes();\n\n    if (!empty($nodes)) {\n        foreach ($nodes as $node) {\n            $location = $node->getLocation();\n            if (null !== $location) {\n                $printedLocations[] = highlightSourceAtLocation(\n                    $location->getSource(),\n                    SourceLocation::fromSource($location->getSource(), $location->getStart())\n                );\n            }\n        }\n    } elseif ($error->hasSource() && $error->hasLocations()) {\n        foreach ($error->getLocations() as $location) {\n            $printedLocations[] = highlightSourceAtLocation($error->getSource(), $location);\n        }\n    }\n\n    return empty($printedLocations)\n        ? $error->getMessage()\n        : \\implode(\"\\n\\n\", \\array_merge([$error->getMessage()], $printedLocations)) . \"\\n\";\n}\n\n/**\n * @param Source         $source\n * @param SourceLocation $location\n * @return string\n */\nfunction highlightSourceAtLocation(Source $source, SourceLocation $location): string\n{\n    $line           = $location->getLine();\n    $locationOffset = $source->getLocationOffset();\n    $lineOffset     = $locationOffset->getLine() - 1;\n    $columnOffset   = getColumnOffset($source, $location);\n    $contextLine    = $line + $lineOffset;\n    $contextColumn  = $location->getColumn() + $columnOffset;\n    $prevLineNum    = (string)($contextLine - 1);\n    $lineNum        = (string)$contextLine;\n    $nextLineNum    = (string)($contextLine + 1);\n    $padLen         = \\mb_strlen($nextLineNum);\n    $lines          = \\preg_split(\"/\\r\\n|[\\n\\r]/\", $source->getBody());\n    $lines          = false === $lines ? [] : $lines;\n    $lines[0]       = whitespace($locationOffset->getColumn() - 1) . $lines[0];\n    $outputLines    = [\n        \\sprintf('%s (%s:%s)', $source->getName(), $contextLine, $contextColumn),\n        $line >= 2 ? leftPad($padLen, $prevLineNum) . ': ' . $lines[$line - 2] : null,\n        leftPad($padLen, $lineNum) . ': ' . $lines[$line - 1],\n        whitespace(2 + $padLen + $contextColumn - 1) . '^',\n        $line < \\count($lines) ? leftPad($padLen, $nextLineNum) . ': ' . $lines[$line] : null,\n    ];\n\n    return \\implode(\"\\n\", \\array_filter($outputLines, function ($line) {\n        return null !== $line;\n    }));\n}\n\n/**\n * @param Source         $source\n * @param SourceLocation $location\n * @return int\n */\nfunction getColumnOffset(Source $source, SourceLocation $location): int\n{\n    return $location->getLine() === 1 ? $source->getLocationOffset()->getColumn() - 1 : 0;\n}\n\n/**\n * @param int $length\n * @return string\n */\nfunction whitespace(int $length): string\n{\n    return \\str_repeat(' ', $length);\n}\n\n/**\n * @param int    $length\n * @param string $str\n * @return string\n */\nfunction leftPad(int $length, string $str): string\n{\n    return whitespace($length - \\mb_strlen($str)) . $str;\n}\n"
  },
  {
    "path": "src/Execution/CoercedValue.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass CoercedValue\n{\n    /**\n     * @var GraphQLException[]\n     */\n    private $errors;\n\n    /**\n     * @var mixed\n     */\n    private $value;\n\n    /**\n     * CoercedValue constructor.\n     * @param mixed $value\n     * @param array $errors\n     */\n    public function __construct($value, array $errors = [])\n    {\n        $this->errors = $errors;\n        $this->value  = $value;\n    }\n\n    /**\n     * @return GraphQLException[]\n     */\n    public function getErrors(): array\n    {\n        return $this->errors;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasErrors(): bool\n    {\n        return !empty($this->errors);\n    }\n\n    /**\n     * @param GraphQLException[] $errors\n     */\n    public function setErrors(array $errors): void\n    {\n        $this->errors = $errors;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * @param mixed $value\n     */\n    public function setValue($value): void\n    {\n        $this->value = $value;\n    }\n}\n"
  },
  {
    "path": "src/Execution/Execution.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\Handler\\ErrorHandlerInterface;\nuse Digia\\GraphQL\\Execution\\Strategy\\FieldCollector;\nuse Digia\\GraphQL\\Execution\\Strategy\\ParallelExecutionStrategy;\nuse Digia\\GraphQL\\Execution\\Strategy\\SerialExecutionStrategy;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse React\\Promise\\PromiseInterface;\nuse function React\\Promise\\resolve;\n\nclass Execution implements ExecutionInterface\n{\n    /**\n     * @inheritdoc\n     */\n    public function execute(\n        Schema $schema,\n        DocumentNode $documentNode,\n        $rootValue = null,\n        $contextValue = null,\n        array $variableValues = [],\n        ?string $operationName = null,\n        ?callable $fieldResolver = null,\n        ?ErrorHandlerInterface $errorHandler = null\n    ): PromiseInterface {\n        try {\n            $context = $this->createContext(\n                $schema,\n                $documentNode,\n                $rootValue,\n                $contextValue,\n                $variableValues,\n                $operationName,\n                $fieldResolver\n            );\n\n            // Return early errors if execution context failed.\n            if (!empty($context->getErrors())) {\n                return resolve(new ExecutionResult(null, $context->getErrors()));\n            }\n        } catch (ExecutionException $error) {\n            return resolve(new ExecutionResult(null, [$error]));\n        }\n\n        $fieldCollector = new FieldCollector($context);\n\n        $data = $this->executeOperation($operationName, $context, $fieldCollector);\n\n        if ($data instanceof PromiseInterface) {\n            return $data->then(function ($resolvedData) use ($context) {\n                return new ExecutionResult($resolvedData, $context->getErrors());\n            });\n        }\n\n        if (null !== $errorHandler) {\n            foreach ($context->getErrors() as $error) {\n                $errorHandler->handleExecutionError($error, $context);\n            }\n        }\n\n        return resolve(new ExecutionResult($data, $context->getErrors()));\n    }\n\n    /**\n     * @param null|string      $operationName\n     * @param ExecutionContext $context\n     * @param FieldCollector   $fieldCollector\n     * @return array|mixed|null|PromiseInterface\n     */\n    protected function executeOperation(\n        ?string $operationName,\n        ExecutionContext $context,\n        FieldCollector $fieldCollector\n    ) {\n        $strategy = $operationName === 'mutation'\n            ? new SerialExecutionStrategy($context, $fieldCollector)\n            : new ParallelExecutionStrategy($context, $fieldCollector);\n\n        $result = null;\n\n        try {\n            $result = $strategy->execute();\n        } catch (ExecutionException $exception) {\n            $context->addError($exception);\n        } catch (\\Throwable $exception) {\n            $context->addError(\n                new ExecutionException($exception->getMessage(), null, null, null, null, null, $exception)\n            );\n        }\n\n        if ($result instanceof PromiseInterface) {\n            return $result->then(null, function (ExecutionException $exception) use ($context) {\n                $context->addError($exception);\n                return resolve(null);\n            });\n        }\n\n        return $result;\n    }\n\n    /**\n     * @param Schema        $schema\n     * @param DocumentNode  $documentNode\n     * @param mixed         $rootValue\n     * @param mixed         $contextValue\n     * @param mixed         $rawVariableValues\n     * @param null|string   $operationName\n     * @param callable|null $fieldResolver\n     * @return ExecutionContext\n     * @throws ExecutionException\n     */\n    protected function createContext(\n        Schema $schema,\n        DocumentNode $documentNode,\n        $rootValue,\n        $contextValue,\n        $rawVariableValues,\n        ?string $operationName = null,\n        ?callable $fieldResolver = null\n    ): ExecutionContext {\n        $errors    = [];\n        $fragments = [];\n        $operation = null;\n\n        foreach ($documentNode->getDefinitions() as $definition) {\n            if ($definition instanceof OperationDefinitionNode) {\n                if (null === $operationName && null !== $operation) {\n                    throw new ExecutionException(\n                        'Must provide operation name if query contains multiple operations.'\n                    );\n                }\n\n                if (null === $operationName || $definition->getNameValue() === $operationName) {\n                    $operation = $definition;\n                }\n\n                continue;\n            }\n\n            if ($definition instanceof FragmentDefinitionNode || $definition instanceof FragmentSpreadNode) {\n                $fragments[$definition->getNameValue()] = $definition;\n\n                continue;\n            }\n        }\n\n        if (null === $operation) {\n            if (null !== $operationName) {\n                throw new ExecutionException(sprintf('Unknown operation named \"%s\".', $operationName));\n            }\n\n            throw new ExecutionException('Must provide an operation.');\n        }\n\n        $coercedVariableValues = ValuesResolver::coerceVariableValues(\n            $schema,\n            $operation->getVariableDefinitions(),\n            $rawVariableValues\n        );\n\n        $variableValues = $coercedVariableValues->getValue();\n\n        if ($coercedVariableValues->hasErrors()) {\n            $errors = $coercedVariableValues->getErrors();\n        }\n\n        return new ExecutionContext(\n            $schema,\n            $fragments,\n            $rootValue,\n            $contextValue,\n            $variableValues,\n            $fieldResolver,\n            $operation,\n            $errors\n        );\n    }\n}\n"
  },
  {
    "path": "src/Execution/ExecutionContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Schema\\Schema;\n\nclass ExecutionContext\n{\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @var FragmentDefinitionNode[]\n     */\n    protected $fragments;\n\n    /**\n     * @var mixed\n     */\n    protected $rootValue;\n\n    /**\n     * @var mixed\n     */\n    protected $contextValue;\n\n    /**\n     * @var mixed\n     */\n    protected $variableValues;\n\n    /**\n     * @var callable|null\n     */\n    protected $fieldResolver;\n\n    /**\n     * @var OperationDefinitionNode\n     */\n    protected $operation;\n\n    /**\n     * @var ExecutionException[]\n     */\n    protected $errors;\n\n    /**\n     * ExecutionContext constructor.\n     *\n     * @param Schema                   $schema\n     * @param FragmentDefinitionNode[] $fragments\n     * @param mixed                    $rootValue\n     * @param mixed                    $contextValue\n     * @param mixed                    $variableValues\n     * @param callable|null            $fieldResolver\n     * @param OperationDefinitionNode  $operation\n     * @param array                    $errors\n     */\n    public function __construct(\n        Schema $schema,\n        array $fragments,\n        $rootValue,\n        $contextValue,\n        $variableValues,\n        ?callable $fieldResolver,\n        OperationDefinitionNode $operation,\n        array $errors\n    ) {\n        $this->schema         = $schema;\n        $this->fragments      = $fragments;\n        $this->rootValue      = $rootValue;\n        $this->contextValue   = $contextValue;\n        $this->variableValues = $variableValues;\n        $this->fieldResolver  = $fieldResolver;\n        $this->operation      = $operation;\n        $this->errors         = $errors;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getRootValue()\n    {\n        return $this->rootValue;\n    }\n\n    /**\n     * @param mixed $rootValue\n     * @return ExecutionContext\n     */\n    public function setRootValue($rootValue): ExecutionContext\n    {\n        $this->rootValue = $rootValue;\n        return $this;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getContextValue()\n    {\n        return $this->contextValue ?? [];\n    }\n\n    /**\n     * @param mixed $contextValue\n     * @return ExecutionContext\n     */\n    public function setContextValue($contextValue): ExecutionContext\n    {\n        $this->contextValue = $contextValue;\n        return $this;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getVariableValues()\n    {\n        return $this->variableValues;\n    }\n\n    /**\n     * @param mixed $variableValues\n     * @return ExecutionContext\n     */\n    public function setVariableValues($variableValues): ExecutionContext\n    {\n        $this->variableValues = $variableValues;\n        return $this;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasFieldResolver(): bool\n    {\n        return null !== $this->fieldResolver;\n    }\n\n    /**\n     * @return callable|null\n     */\n    public function getFieldResolver(): ?callable\n    {\n        return $this->fieldResolver;\n    }\n\n    /**\n     * @param callable|null $fieldResolver\n     * @return ExecutionContext\n     */\n    public function setFieldResolver(?callable $fieldResolver): ExecutionContext\n    {\n        $this->fieldResolver = $fieldResolver;\n        return $this;\n    }\n\n\n    /**\n     * @return OperationDefinitionNode\n     */\n    public function getOperation(): OperationDefinitionNode\n    {\n        return $this->operation;\n    }\n\n    /**\n     * @return Schema\n     */\n    public function getSchema(): Schema\n    {\n        return $this->schema;\n    }\n\n    /**\n     * @return FragmentDefinitionNode[]\n     */\n    public function getFragments(): array\n    {\n        return $this->fragments;\n    }\n\n    /**\n     * @param ExecutionException $error\n     * @return ExecutionContext\n     */\n    public function addError(ExecutionException $error): ExecutionContext\n    {\n        $this->errors[] = $error;\n        return $this;\n    }\n\n    /**\n     * @return ExecutionException[]\n     */\n    public function getErrors(): array\n    {\n        return $this->errors;\n    }\n}\n"
  },
  {
    "path": "src/Execution/ExecutionException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass ExecutionException extends GraphQLException\n{\n}\n"
  },
  {
    "path": "src/Execution/ExecutionInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\Handler\\ErrorHandlerInterface;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse React\\Promise\\PromiseInterface;\n\ninterface ExecutionInterface\n{\n    /**\n     * @param Schema                     $schema\n     * @param DocumentNode               $documentNode\n     * @param mixed                      $rootValue\n     * @param mixed                      $contextValue\n     * @param array                      $variableValues\n     * @param string|null                $operationName\n     * @param callable|null              $fieldResolver\n     * @param ErrorHandlerInterface|null $errorHandler\n     * @return PromiseInterface\n     */\n    public function execute(\n        Schema $schema,\n        DocumentNode $documentNode,\n        $rootValue = null,\n        $contextValue = null,\n        array $variableValues = [],\n        string $operationName = null,\n        callable $fieldResolver = null,\n        ?ErrorHandlerInterface $errorHandler = null\n    ): PromiseInterface;\n}\n"
  },
  {
    "path": "src/Execution/ExecutionProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass ExecutionProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        ExecutionInterface::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->share(ExecutionInterface::class, Execution::class);\n    }\n}\n"
  },
  {
    "path": "src/Execution/ExecutionResult.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Util\\ArrayToJsonTrait;\nuse Digia\\GraphQL\\Util\\SerializationInterface;\n\nclass ExecutionResult implements SerializationInterface\n{\n    use ArrayToJsonTrait;\n\n    /**\n     * @var array|null\n     */\n    protected $data;\n\n    /**\n     * @var GraphQLException[]\n     */\n    protected $errors;\n\n    /**\n     * ExecutionResult constructor.\n     * @param array|null         $data\n     * @param GraphQLException[] $errors\n     */\n    public function __construct(?array $data, array $errors)\n    {\n        $this->data   = $data;\n        $this->errors = $errors;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getData(): ?array\n    {\n        return $this->data;\n    }\n\n    /**\n     * @return GraphQLException[]\n     */\n    public function getErrors(): array\n    {\n        return $this->errors;\n    }\n\n    /**\n     * @param GraphQLException $error\n     * @return ExecutionResult\n     */\n    public function addError(GraphQLException $error): ExecutionResult\n    {\n        $this->errors[] = $error;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toArray(): array\n    {\n        $array = [];\n\n        if (!empty($this->errors)) {\n            $array['errors'] = \\array_map(function (GraphQLException $error) {\n                return $error->toArray();\n            }, $this->errors);\n        }\n\n        $array['data'] = $this->data;\n\n        return $array;\n    }\n}\n"
  },
  {
    "path": "src/Execution/InvalidReturnTypeException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass InvalidReturnTypeException extends GraphQLException\n{\n\n    /**\n     * InvalidReturnTypeException constructor.\n     *\n     * @param TypeInterface $returnType\n     * @param mixed         $result\n     * @param array         $fieldNodes\n     */\n    public function __construct(TypeInterface $returnType, $result, array $fieldNodes = [])\n    {\n        parent::__construct(\n            \\sprintf('Expected value of type \"%s\" but got: %s.', (string)$returnType, toString($result)),\n            $fieldNodes\n        );\n    }\n}\n"
  },
  {
    "path": "src/Execution/Path.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nclass Path\n{\n    /**\n     * @var Path|null\n     */\n    protected $previous;\n\n    /**\n     * @var string|mixed\n     */\n    protected $key;\n\n    /**\n     * Path constructor.\n     * @param Path|null    $previous\n     * @param string|mixed $key\n     */\n    public function __construct(?Path $previous, $key)\n    {\n        $this->previous = $previous;\n        $this->key      = $key;\n    }\n\n    /**\n     * @return Path|null\n     */\n    public function getPrevious(): ?Path\n    {\n        return $this->previous;\n    }\n\n    /**\n     * @return string|mixed\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n}\n"
  },
  {
    "path": "src/Execution/ResolveInfo.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\nclass ResolveInfo\n{\n    /**\n     * @var string\n     */\n    protected $fieldName;\n\n    /**\n     * @var FieldNode[]\n     */\n    protected $fieldNodes;\n\n    /**\n     * @var TypeInterface\n     */\n    protected $returnType;\n\n    /**\n     * @var ObjectType\n     */\n    protected $parentType;\n\n    /**\n     * @var array|null\n     */\n    protected $path;\n\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @var array\n     */\n    protected $fragments;\n\n    /**\n     * @var mixed\n     */\n    protected $rootValue;\n\n    /**\n     * @var OperationDefinitionNode\n     */\n    protected $operation;\n\n    /**\n     * @var array\n     */\n    protected $variableValues;\n\n    /**\n     * ResolveInfo constructor.\n     * @param string                  $fieldName\n     * @param FieldNode[]             $fieldNodes\n     * @param TypeInterface           $returnType\n     * @param ObjectType              $parentType\n     * @param array|null              $path\n     * @param Schema                  $schema\n     * @param array                   $fragments\n     * @param mixed                   $rootValue\n     * @param OperationDefinitionNode $operation\n     * @param array                   $variableValues\n     */\n    public function __construct(\n        string $fieldName,\n        ?array $fieldNodes,\n        TypeInterface $returnType,\n        ObjectType $parentType,\n        ?array $path,\n        Schema $schema,\n        array $fragments,\n        $rootValue,\n        OperationDefinitionNode $operation,\n        array $variableValues\n    ) {\n        $this->fieldName      = $fieldName;\n        $this->fieldNodes     = $fieldNodes;\n        $this->returnType     = $returnType;\n        $this->parentType     = $parentType;\n        $this->path           = $path;\n        $this->schema         = $schema;\n        $this->fragments      = $fragments;\n        $this->rootValue      = $rootValue;\n        $this->operation      = $operation;\n        $this->variableValues = $variableValues;\n    }\n\n\n    /**\n     * @return string\n     */\n    public function getFieldName(): string\n    {\n        return $this->fieldName;\n    }\n\n    /**\n     * @return FieldNode[]\n     */\n    public function getFieldNodes(): array\n    {\n        return $this->fieldNodes;\n    }\n\n    /**\n     * @return TypeInterface\n     */\n    public function getReturnType(): TypeInterface\n    {\n        return $this->returnType;\n    }\n\n    /**\n     * @return ObjectType\n     */\n    public function getParentType(): ObjectType\n    {\n        return $this->parentType;\n    }\n\n    /**\n     * @return array\n     */\n    public function getPath(): ?array\n    {\n        return $this->path;\n    }\n\n    /**\n     * @return Schema\n     */\n    public function getSchema(): Schema\n    {\n        return $this->schema;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFragments(): array\n    {\n        return $this->fragments;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getRootValue()\n    {\n        return $this->rootValue;\n    }\n\n    /**\n     * @return OperationDefinitionNode\n     */\n    public function getOperation(): OperationDefinitionNode\n    {\n        return $this->operation;\n    }\n\n    /**\n     * @return array\n     */\n    public function getVariableValues(): array\n    {\n        return $this->variableValues;\n    }\n}\n"
  },
  {
    "path": "src/Execution/Strategy/AbstractExecutionStrategy.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution\\Strategy;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Execution\\InvalidReturnTypeException;\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\nuse Digia\\GraphQL\\Execution\\UndefinedFieldException;\nuse Digia\\GraphQL\\Execution\\ValuesResolver;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\AbstractTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\LeafTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\SerializableTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse React\\Promise\\PromiseInterface;\nuse function Digia\\GraphQL\\Type\\SchemaMetaFieldDefinition;\nuse function Digia\\GraphQL\\Type\\TypeMetaFieldDefinition;\nuse function Digia\\GraphQL\\Type\\TypeNameMetaFieldDefinition;\n\nabstract class AbstractExecutionStrategy implements ExecutionStrategyInterface\n{\n    /**\n     * @var ExecutionContext\n     */\n    protected $context;\n\n    /**\n     * @var FieldCollector\n     */\n    protected $fieldCollector;\n\n    /**\n     * @var callable\n     */\n    protected $typeResolverCallback;\n\n    /**\n     * @var callable\n     */\n    protected $fieldResolverCallback;\n\n    /**\n     * @param ObjectType $parentType\n     * @param mixed      $rootValue\n     * @param array      $path\n     * @param array      $fields\n     * @return array|PromiseInterface\n     * @throws \\Throwable\n     * @throws ExecutionException\n     */\n    abstract public function executeFields(ObjectType $parentType, $rootValue, array $path, array $fields);\n\n    /**\n     * AbstractExecutionStrategy constructor.\n     *\n     * @param ExecutionContext $context\n     * @param FieldCollector   $fieldCollector\n     * @param callable|null    $typeResolverCallback\n     * @param callable|null    $fieldResolverCallback\n     */\n    public function __construct(\n        ExecutionContext $context,\n        FieldCollector $fieldCollector,\n        ?callable $typeResolverCallback = null,\n        ?callable $fieldResolverCallback = null\n    ) {\n        $this->context               = $context;\n        $this->fieldCollector        = $fieldCollector;\n        $this->typeResolverCallback  = $typeResolverCallback ?? [$this, 'defaultTypeResolver'];\n        $this->fieldResolverCallback = $fieldResolverCallback ?? [$this, 'defaultFieldResolver'];\n    }\n\n    /**\n     * @inheritdoc\n     * @throws ExecutionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     * @throws \\Throwable\n     */\n    public function execute()\n    {\n        $schema    = $this->context->getSchema();\n        $operation = $this->context->getOperation();\n        $rootValue = $this->context->getRootValue();\n\n        $objectType = $this->getOperationType($schema, $operation);\n\n        $fields               = [];\n        $visitedFragmentNames = [];\n        $path                 = [];\n\n        $fields = $this->fieldCollector->collectFields(\n            $objectType,\n            $operation->getSelectionSet(),\n            $fields,\n            $visitedFragmentNames\n        );\n\n        // Errors from sub-fields of a NonNull type may propagate to the top level,\n        // at which point we still log the error and null the parent field, which\n        // in this case is the entire response.\n        try {\n            $result = $this->executeFields($objectType, $rootValue, $path, $fields);\n        } catch (ExecutionException $exception) {\n            $this->context->addError($exception);\n            return null;\n        } catch (\\Throwable $exception) {\n            $exception = !$exception instanceof ExecutionException\n                ? $this->normalizeException($exception, $fields, $path)\n                : $exception;\n\n            $this->context->addError($exception);\n\n            return null;\n        }\n\n        return $result;\n    }\n\n    /**\n     * @param Schema                  $schema\n     * @param OperationDefinitionNode $operation\n     *\n     * @return ObjectType|null\n     * @throws ExecutionException\n     */\n    protected function getOperationType(Schema $schema, OperationDefinitionNode $operation): ?ObjectType\n    {\n        switch ($operation->getOperation()) {\n            case 'query':\n                return $schema->getQueryType();\n            case 'mutation':\n                $mutationType = $schema->getMutationType();\n\n                if (null === $mutationType) {\n                    throw new ExecutionException('Schema is not configured for mutations.', [$operation]);\n                }\n\n                return $mutationType;\n            case 'subscription':\n                $subscriptionType = $schema->getSubscriptionType();\n\n                if (null === $subscriptionType) {\n                    throw new ExecutionException('Schema is not configured for subscriptions.', [$operation]);\n                }\n\n                return $subscriptionType;\n            default:\n                throw new ExecutionException('Can only execute queries, mutations and subscriptions.', [$operation]);\n        }\n    }\n\n    /**\n     * Resolves the field on the given source object. In particular, this\n     * figures out the value that the field returns by calling its resolve function,\n     * then calls completeValue to complete promises, serialize scalars, or execute\n     * the sub-selection-set for objects.\n     *\n     * @param ObjectType  $parentType\n     * @param mixed       $rootValue\n     * @param FieldNode[] $fieldNodes\n     * @param string[]    $path\n     *\n     * @return mixed\n     * @throws \\Throwable\n     * @throws UndefinedFieldException\n     */\n    protected function resolveField(ObjectType $parentType, $rootValue, array $fieldNodes, array $path)\n    {\n        $fieldNode = $fieldNodes[0];\n\n        $fieldName = $fieldNode->getNameValue();\n        $field     = $this->getFieldDefinition($this->context->getSchema(), $parentType, $fieldName);\n\n        if (null === $field) {\n            throw new UndefinedFieldException($fieldName);\n        }\n\n        $info = $this->createResolveInfo($fieldNodes, $fieldNode, $field, $parentType, $path, $this->context);\n\n        $resolveCallback = $this->determineResolveCallback($field, $parentType);\n\n        $result = $this->resolveFieldValueOrError(\n            $field,\n            $fieldNode,\n            $resolveCallback,\n            $rootValue,\n            $this->context,\n            $info\n        );\n\n        $result = $this->completeValueCatchingError(\n            $field->getType(),\n            $fieldNodes,\n            $info,\n            $path,\n            $result\n        );\n\n        return $result;\n    }\n\n    /**\n     * @param Field            $field\n     * @param FieldNode        $fieldNode\n     * @param callable         $resolveCallback\n     * @param mixed            $rootValue\n     * @param ExecutionContext $context\n     * @param ResolveInfo      $info\n     *\n     * @return array|\\Throwable\n     */\n    protected function resolveFieldValueOrError(\n        Field $field,\n        FieldNode $fieldNode,\n        ?callable $resolveCallback,\n        $rootValue,\n        ExecutionContext $context,\n        ResolveInfo $info\n    ) {\n        try {\n            // Build an associative array of arguments from the field.arguments AST, using the\n            // variables scope to fulfill any variable references.\n            $result = $resolveCallback(\n                $rootValue,\n                ValuesResolver::coerceArgumentValues($field, $fieldNode, $context->getVariableValues()),\n                $context->getContextValue(),\n                $info\n            );\n\n            if ($result instanceof PromiseInterface) {\n                return $result->then(null, function ($exception) use ($fieldNode, $info) {\n                    return !$exception instanceof ExecutionException\n                        ? $this->normalizeException($exception, [$fieldNode], $info->getPath())\n                        : $exception;\n                });\n            }\n\n            return $result;\n        } catch (\\Throwable $exception) {\n            return $exception;\n        }\n    }\n\n    /**\n     * Normalizes exceptions which are usually a \\Throwable,\n     * but can even be a string or null when resolving promises.\n     *\n     * @param mixed           $exception\n     * @param NodeInterface[] $nodes\n     * @param array           $path\n     * @return ExecutionException\n     */\n    protected function normalizeException($exception, array $nodes, array $path = []): ExecutionException\n    {\n        if ($exception instanceof \\Throwable) {\n            return new ExecutionException(\n                $exception->getMessage(),\n                $nodes,\n                null,\n                null,\n                $path,\n                null,\n                $exception\n            );\n        }\n\n        if (\\is_string($exception)) {\n            return new ExecutionException(\n                $exception,\n                $nodes,\n                null,\n                null,\n                $path\n            );\n        }\n\n        return new ExecutionException(\n            '',\n            $nodes,\n            null,\n            null,\n            $path\n        );\n    }\n\n    /**\n     * This is a small wrapper around completeValue which detects and logs error in the execution context.\n     *\n     * @param TypeInterface $returnType\n     * @param FieldNode[]   $fieldNodes\n     * @param ResolveInfo   $info\n     * @param array         $path\n     * @param mixed         $result\n     *\n     * @return array|null|PromiseInterface\n     * @throws \\Throwable\n     */\n    public function completeValueCatchingError(\n        TypeInterface $returnType,\n        array $fieldNodes,\n        ResolveInfo $info,\n        array $path,\n        &$result\n    ) {\n        try {\n            $completed = $result instanceof PromiseInterface\n                ? $result->then(function ($resolvedResult) use ($returnType, $fieldNodes, $info, $path) {\n                    return $this->completeValue($returnType, $fieldNodes, $info, $path, $resolvedResult);\n                })\n                : $this->completeValue($returnType, $fieldNodes, $info, $path, $result);\n\n            if ($completed instanceof PromiseInterface) {\n                // Note: we don't rely on a `catch` method, but we do expect \"thenable\"\n                // to take a second callback for the error case.\n                return $completed->then(null, function ($exception) use ($fieldNodes, $path, $returnType) {\n                    $this->handleFieldError($exception, $fieldNodes, $path, $returnType);\n                });\n            }\n\n            return $completed;\n        } catch (\\Throwable $exception) {\n            $this->handleFieldError($exception, $fieldNodes, $path, $returnType);\n            return null;\n        }\n    }\n\n    /**\n     * Implements the instructions for completeValue as defined in the\n     * \"Field entries\" section of the spec.\n     *\n     * If the field type is Non-Null, then this recursively completes the value\n     * for the inner type. It throws a field error if that completion returns null,\n     * as per the \"Nullability\" section of the spec.\n     *\n     * If the field type is a List, then this recursively completes the value\n     * for the inner type on each item in the list.\n     *\n     * If the field type is a Scalar or Enum, ensures the completed value is a legal\n     * value of the type by calling the `serialize` method of GraphQL type\n     * definition.\n     *\n     * If the field is an abstract type, determine the runtime type of the value\n     * and then complete based on that type\n     *\n     * Otherwise, the field type expects a sub-selection set, and will complete the\n     * value by evaluating all sub-selections.\n     *\n     * @param TypeInterface $returnType\n     * @param FieldNode[]   $fieldNodes\n     * @param ResolveInfo   $info\n     * @param array         $path\n     * @param mixed         $result\n     *\n     * @return array|null|PromiseInterface\n     * @throws \\Throwable\n     */\n    protected function completeValue(\n        TypeInterface $returnType,\n        array $fieldNodes,\n        ResolveInfo $info,\n        array $path,\n        &$result\n    ) {\n        // If result is an Error, throw a located error.\n        if ($result instanceof \\Throwable) {\n            throw $result;\n        }\n\n        // If field type is NonNull, complete for inner type, and throw field error if result is null.\n        if ($returnType instanceof NonNullType) {\n            $completed = $this->completeValue(\n                $returnType->getOfType(),\n                $fieldNodes,\n                $info,\n                $path,\n                $result\n            );\n\n            if (null !== $completed) {\n                return $completed;\n            }\n\n            throw new ExecutionException(\n                \\sprintf(\n                    'Cannot return null for non-nullable field %s.%s.',\n                    (string)$info->getParentType(),\n                    $info->getFieldName()\n                )\n            );\n        }\n\n        // If result is null, return null.\n        if (null === $result) {\n            return null;\n        }\n\n        // If field type is a leaf type, Scalar or Enum, serialize to a valid value,\n        // returning null if serialization is not possible.\n        if ($returnType instanceof ListType) {\n            return $this->completeListValue($returnType, $fieldNodes, $info, $path, $result);\n        }\n\n        // If field type is Scalar or Enum, serialize to a valid value, returning\n        // null if serialization is not possible.\n        if ($returnType instanceof LeafTypeInterface) {\n            return $this->completeLeafValue($returnType, $result);\n        }\n\n        // If field type is an abstract type, Interface or Union, determine the\n        // runtime Object type and complete for that type.\n        if ($returnType instanceof AbstractTypeInterface) {\n            return $this->completeAbstractValue($returnType, $fieldNodes, $info, $path, $result);\n        }\n\n        // If field type is Object, execute and complete all sub-selections.\n        if ($returnType instanceof ObjectType) {\n            return $this->completeObjectValue($returnType, $fieldNodes, $info, $path, $result);\n        }\n\n        throw new ExecutionException(\\sprintf('Cannot complete value of unexpected type \"%s\".', (string)$returnType));\n    }\n\n    /**\n     * @param ListType    $returnType\n     * @param FieldNode[] $fieldNodes\n     * @param ResolveInfo $info\n     * @param array       $path\n     * @param mixed       $result\n     *\n     * @return array|PromiseInterface\n     * @throws \\Throwable\n     */\n    protected function completeListValue(\n        ListType $returnType,\n        array $fieldNodes,\n        ResolveInfo $info,\n        array $path,\n        &$result\n    ) {\n        if (!\\is_array($result) && !$result instanceof \\Traversable) {\n            throw new InvariantException(\n                \\sprintf(\n                    'Expected Array or Traversable, but did not find one for field %s.%s.',\n                    (string)$info->getParentType(),\n                    $info->getFieldName()\n                )\n            );\n        }\n\n        $itemType           = $returnType->getOfType();\n        $completedItems     = [];\n        $containsPromise = false;\n\n        foreach ($result as $key => $item) {\n            $fieldPath          = $path;\n            $fieldPath[]        = $key;\n            $completedItem      = $this->completeValueCatchingError($itemType, $fieldNodes, $info, $fieldPath, $item);\n            $completedItems[]   = $completedItem;\n            $containsPromise = $containsPromise || $completedItem instanceof PromiseInterface;\n        }\n\n        return $containsPromise\n            ? \\React\\Promise\\all($completedItems)\n            : $completedItems;\n    }\n\n    /**\n     * @param LeafTypeInterface|SerializableTypeInterface $returnType\n     * @param mixed                                       $result\n     *\n     * @return array|PromiseInterface\n     * @throws InvalidReturnTypeException\n     */\n    protected function completeLeafValue($returnType, &$result)\n    {\n        $result = $returnType->serialize($result);\n\n        if (null === $result) {\n            throw new InvalidReturnTypeException($returnType, $result);\n        }\n\n        return $result;\n    }\n\n    /**\n     * @param AbstractTypeInterface $returnType\n     * @param FieldNode[]           $fieldNodes\n     * @param ResolveInfo           $info\n     * @param string[]              $path\n     * @param mixed                 $result\n     *\n     * @return array|PromiseInterface\n     * @throws \\Throwable\n     */\n    protected function completeAbstractValue(\n        AbstractTypeInterface $returnType,\n        array $fieldNodes,\n        ResolveInfo $info,\n        array $path,\n        &$result\n    ) {\n        $runtimeType = $returnType->hasResolveTypeCallback()\n            ? $returnType->resolveType($result, $this->context->getContextValue(), $info)\n            : \\call_user_func(\n                $this->typeResolverCallback,\n                $result,\n                $this->context->getContextValue(),\n                $info,\n                $returnType\n            );\n\n        if ($runtimeType instanceof PromiseInterface) {\n            return $runtimeType->then(function ($resolvedRuntimeType) use (\n                $returnType,\n                $fieldNodes,\n                $info,\n                $path,\n                &$result\n            ) {\n                return $this->completeObjectValue(\n                    $this->ensureValidRuntimeType($resolvedRuntimeType, $returnType, $info, $result),\n                    $fieldNodes,\n                    $info,\n                    $path,\n                    $result\n                );\n            });\n        }\n\n        $returnType = $this->ensureValidRuntimeType($runtimeType, $returnType, $info, $result);\n\n        return $this->completeObjectValue(\n            $returnType,\n            $fieldNodes,\n            $info,\n            $path,\n            $result\n        );\n    }\n\n    /**\n     * @param ObjectType  $returnType\n     * @param array       $fieldNodes\n     * @param ResolveInfo $info\n     * @param array       $path\n     * @param mixed       $result\n     *\n     * @return array|PromiseInterface\n     * @throws ExecutionException\n     * @throws InvalidReturnTypeException\n     * @throws \\Throwable\n     */\n    protected function completeObjectValue(\n        ObjectType $returnType,\n        array $fieldNodes,\n        ResolveInfo $info,\n        array $path,\n        &$result\n    ) {\n        // If there is an isTypeOfCallback predicate function, call it with the\n        // current result. If isTypeOfCallback returns false, then raise an error rather\n        // than continuing execution.\n        if ($returnType->hasIsTypeOfCallback()) {\n            $isTypeOf = $returnType->isTypeOf($result, $this->context->getContextValue(), $info);\n\n            if ($isTypeOf instanceof PromiseInterface) {\n                return $isTypeOf->then(function ($resolvedIsTypeOf) use ($returnType, $result, $fieldNodes, $path) {\n                    if (true === $resolvedIsTypeOf) {\n                        return $this->executeSubFields($returnType, $fieldNodes, $path, $result);\n                    }\n\n                    throw new InvalidReturnTypeException($returnType, $result, $fieldNodes);\n                });\n            }\n\n            if (false === $isTypeOf) {\n                throw new InvalidReturnTypeException($returnType, $result, $fieldNodes);\n            }\n        }\n\n        return $this->executeSubFields($returnType, $fieldNodes, $path, $result);\n    }\n\n    /**\n     * @param ObjectType  $returnType\n     * @param FieldNode[] $fieldNodes\n     * @param array       $path\n     * @param mixed       $result\n     *\n     * @return array|PromiseInterface\n     * @throws \\Throwable\n     */\n    protected function executeSubFields(ObjectType $returnType, array $fieldNodes, array $path, &$result)\n    {\n        $subFields            = [];\n        $visitedFragmentNames = [];\n\n        foreach ($fieldNodes as $fieldNode) {\n            if (null !== $fieldNode->getSelectionSet()) {\n                $subFields = $this->fieldCollector->collectFields(\n                    $returnType,\n                    $fieldNode->getSelectionSet(),\n                    $subFields,\n                    $visitedFragmentNames\n                );\n            }\n        }\n\n        if (!empty($subFields)) {\n            return $this->executeFields($returnType, $result, $path, $subFields);\n        }\n\n        return $result;\n    }\n\n    /**\n     * @param NamedTypeInterface|string $runtimeTypeOrName\n     * @param NamedTypeInterface        $returnType\n     * @param ResolveInfo               $info\n     * @param mixed                     $result\n     *\n     * @return TypeInterface|ObjectType|null\n     * @throws ExecutionException\n     * @throws InvariantException\n     */\n    protected function ensureValidRuntimeType(\n        $runtimeTypeOrName,\n        NamedTypeInterface $returnType,\n        ResolveInfo $info,\n        &$result\n    ) {\n        /** @var NamedTypeInterface $runtimeType */\n        $runtimeType = \\is_string($runtimeTypeOrName)\n            ? $this->context->getSchema()->getType($runtimeTypeOrName)\n            : $runtimeTypeOrName;\n\n        $runtimeTypeName = $runtimeType->getName();\n        $returnTypeName  = $returnType->getName();\n\n        if (!$runtimeType instanceof ObjectType) {\n            $parentTypeName = $info->getParentType()->getName();\n            $fieldName      = $info->getFieldName();\n\n            throw new ExecutionException(\n                \\sprintf(\n                    'Abstract type %s must resolve to an Object type at runtime for field %s.%s ' .\n                    'with value \"%s\", received \"%s\".',\n                    $returnTypeName,\n                    $parentTypeName,\n                    $fieldName,\n                    $result,\n                    $runtimeTypeName\n                )\n            );\n        }\n\n        if (!$this->context->getSchema()->isPossibleType($returnType, $runtimeType)) {\n            throw new ExecutionException(\n                \\sprintf('Runtime Object type \"%s\" is not a possible type for \"%s\".', $runtimeTypeName, $returnTypeName)\n            );\n        }\n\n        if ($runtimeType !== $this->context->getSchema()->getType($runtimeType->getName())) {\n            throw new ExecutionException(\n                \\sprintf(\n                    'Schema must contain unique named types but contains multiple types named \"%s\". ' .\n                    'Make sure that `resolveType` function of abstract type \"%s\" returns the same ' .\n                    'type instance as referenced anywhere else within the schema.',\n                    $runtimeTypeName,\n                    $returnTypeName\n                )\n            );\n        }\n\n        return $runtimeType;\n    }\n\n    /**\n     * @param Schema     $schema\n     * @param ObjectType $parentType\n     * @param string     $fieldName\n     *\n     * @return Field|null\n     * @throws InvariantException\n     */\n    public function getFieldDefinition(Schema $schema, ObjectType $parentType, string $fieldName): ?Field\n    {\n        if ($fieldName === '__schema' && $schema->getQueryType() === $parentType) {\n            return SchemaMetaFieldDefinition();\n        }\n\n        if ($fieldName === '__type' && $schema->getQueryType() === $parentType) {\n            return TypeMetaFieldDefinition();\n        }\n\n        if ($fieldName === '__typename') {\n            return TypeNameMetaFieldDefinition();\n        }\n\n        $fields = $parentType->getFields();\n\n        return $fields[$fieldName] ?? null;\n    }\n\n    /**\n     * @param Field      $field\n     * @param ObjectType $parentType\n     *\n     * @return callable\n     */\n    protected function determineResolveCallback(Field $field, ObjectType $parentType): callable\n    {\n        if ($field->hasResolveCallback()) {\n            return $field->getResolveCallback();\n        }\n\n        if ($parentType->hasResolveCallback()) {\n            return $parentType->getResolveCallback();\n        }\n\n        if ($this->context->hasFieldResolver()) {\n            return $this->context->getFieldResolver();\n        }\n\n        return $this->fieldResolverCallback;\n    }\n\n    /**\n     * @param \\Throwable    $originalException\n     * @param array         $fieldNodes\n     * @param array         $path\n     * @param TypeInterface $returnType\n     * @throws ExecutionException\n     */\n    protected function handleFieldError(\n        \\Throwable $originalException,\n        array $fieldNodes,\n        array $path,\n        TypeInterface $returnType\n    ): void {\n        $exception = $this->buildLocatedError($originalException, $fieldNodes, $path);\n\n        // If the field type is non-nullable, then it is resolved without any\n        // protection from errors, however it still properly locates the error.\n        if ($returnType instanceof NonNullType) {\n            throw $exception;\n        }\n\n        // Otherwise, error protection is applied, logging the error and resolving\n        // a null value for this field if one is encountered.\n        $this->context->addError($exception);\n    }\n\n    /**\n     * @param \\Throwable      $originalException\n     * @param NodeInterface[] $nodes\n     * @param string[]        $path\n     *\n     * @return ExecutionException\n     */\n    protected function buildLocatedError(\n        \\Throwable $originalException,\n        array $nodes = [],\n        array $path = []\n    ): ExecutionException {\n        return new ExecutionException(\n            $originalException->getMessage(),\n            $originalException instanceof GraphQLException\n                ? $originalException->getNodes()\n                : $nodes,\n            $originalException instanceof GraphQLException\n                ? $originalException->getSource()\n                : null,\n            $originalException instanceof GraphQLException\n                ? $originalException->getPositions()\n                : null,\n            $originalException instanceof GraphQLException\n                ? ($originalException->getPath() ?? $path)\n                : $path,\n            null,\n            $originalException\n        );\n    }\n\n    /**\n     * @param FieldNode[]      $fieldNodes\n     * @param FieldNode        $fieldNode\n     * @param Field            $field\n     * @param ObjectType       $parentType\n     * @param array|null       $path\n     * @param ExecutionContext $context\n     *\n     * @return ResolveInfo\n     */\n    protected function createResolveInfo(\n        array $fieldNodes,\n        FieldNode $fieldNode,\n        Field $field,\n        ObjectType $parentType,\n        ?array $path,\n        ExecutionContext $context\n    ): ResolveInfo {\n        return new ResolveInfo(\n            $fieldNode->getNameValue(),\n            $fieldNodes,\n            $field->getType(),\n            $parentType,\n            $path,\n            $context->getSchema(),\n            $context->getFragments(),\n            $context->getRootValue(),\n            $context->getOperation(),\n            $context->getVariableValues()\n        );\n    }\n\n    /**\n     * @param mixed                 $value\n     * @param mixed                 $context\n     * @param ResolveInfo           $info\n     * @param AbstractTypeInterface $abstractType\n     *\n     * @return mixed\n     * @throws InvariantException\n     */\n    public static function defaultTypeResolver(\n        $value,\n        $context,\n        ResolveInfo $info,\n        AbstractTypeInterface $abstractType\n    ) {\n        // First, look for `__typename`.\n        if (\\is_array($value) && isset($value['__typename'])) {\n            return $value['__typename'];\n        }\n\n        // Otherwise, test each possible type.\n\n        /** @var ObjectType[] $possibleTypes */\n        $possibleTypes = $info->getSchema()->getPossibleTypes($abstractType);\n        $promises      = [];\n\n        foreach ($possibleTypes as $index => $type) {\n            $isTypeOf = $type->isTypeOf($value, $context, $info);\n\n            if ($isTypeOf instanceof PromiseInterface) {\n                $promises[$index] = $isTypeOf;\n            }\n\n            if (true === $isTypeOf) {\n                return $type;\n            }\n        }\n\n        if (!empty($promises)) {\n            return \\React\\Promise\\all($promises)->then(function ($resolvedPromises) use ($possibleTypes) {\n                foreach ($resolvedPromises as $index => $result) {\n                    if (true === $result) {\n                        return $possibleTypes[$index];\n                    }\n                }\n\n                return null;\n            });\n        }\n\n        return null;\n    }\n\n    /**\n     * Try to resolve a field without any field resolver function.\n     *\n     * @param array|object $rootValue\n     * @param array        $arguments\n     * @param mixed        $contextValues\n     * @param ResolveInfo  $info\n     *\n     * @return mixed|null\n     */\n    public static function defaultFieldResolver($rootValue, array $arguments, $contextValues, ResolveInfo $info)\n    {\n        $fieldName = $info->getFieldName();\n        $property  = null;\n\n        if (\\is_array($rootValue) && isset($rootValue[$fieldName])) {\n            $property = $rootValue[$fieldName];\n        }\n\n        if (\\is_object($rootValue)) {\n            $getter = 'get' . \\ucfirst($fieldName);\n            if (\\method_exists($rootValue, $getter)) {\n                $property = $rootValue->{$getter}();\n            } elseif (\\method_exists($rootValue, $fieldName)) {\n                $property = $rootValue->{$fieldName}($rootValue, $arguments, $contextValues, $info);\n            } elseif (\\property_exists($rootValue, $fieldName)) {\n                $property = $rootValue->{$fieldName};\n            }\n        }\n\n        return $property instanceof \\Closure\n            ? $property($rootValue, $arguments, $contextValues, $info)\n            : $property;\n    }\n}\n"
  },
  {
    "path": "src/Execution/Strategy/ExecutionStrategyInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution\\Strategy;\n\ninterface ExecutionStrategyInterface\n{\n    /**\n     * @return mixed\n     */\n    public function execute();\n}\n"
  },
  {
    "path": "src/Execution/Strategy/FieldCollector.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution\\Strategy;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Execution\\ValuesResolver;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Type\\Definition\\AbstractTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\n\nclass FieldCollector\n{\n    /**\n     * @var ExecutionContext\n     */\n    protected $context;\n\n    /**\n     * @var Directive\n     */\n    protected $skipDirective;\n\n    /**\n     * @var Directive\n     */\n    protected $includeDirective;\n\n    /**\n     * FieldCollector constructor.\n     * @param ExecutionContext $context\n     */\n    public function __construct(ExecutionContext $context)\n    {\n        $this->context          = $context;\n        $this->skipDirective    = SkipDirective();\n        $this->includeDirective = IncludeDirective();\n    }\n\n    /**\n     * @param ObjectType       $runtimeType\n     * @param SelectionSetNode $selectionSet\n     * @param array            $fields\n     * @param array            $visitedFragmentNames\n     * @return array\n     * @throws InvalidTypeException\n     * @throws ExecutionException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    public function collectFields(\n        ObjectType $runtimeType,\n        SelectionSetNode $selectionSet,\n        array &$fields,\n        array &$visitedFragmentNames\n    ): array {\n        foreach ($selectionSet->getSelections() as $selection) {\n            // Check if this Node should be included first\n            if (!$this->shouldIncludeNode($selection)) {\n                continue;\n            }\n\n            // Collect fields\n            if ($selection instanceof FieldNode) {\n                $fieldName = $selection->getAliasOrNameValue();\n\n                if (!isset($fields[$fieldName])) {\n                    $fields[$fieldName] = [];\n                }\n\n                $fields[$fieldName][] = $selection;\n\n                continue;\n            }\n\n            if ($selection instanceof InlineFragmentNode) {\n                if (!$this->doesFragmentConditionMatch($selection, $runtimeType)) {\n                    continue;\n                }\n\n                $this->collectFields($runtimeType, $selection->getSelectionSet(), $fields, $visitedFragmentNames);\n\n                continue;\n            }\n\n            if ($selection instanceof FragmentSpreadNode) {\n                $fragmentName = $selection->getNameValue();\n\n                if (isset($visitedFragmentNames[$fragmentName])) {\n                    continue;\n                }\n\n                $visitedFragmentNames[$fragmentName] = true;\n\n                $fragment = $this->context->getFragments()[$fragmentName];\n\n                $this->collectFields($runtimeType, $fragment->getSelectionSet(), $fields, $visitedFragmentNames);\n\n                continue;\n            }\n        }\n\n        return $fields;\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return bool\n     * @throws ExecutionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function shouldIncludeNode(NodeInterface $node): bool\n    {\n        $contextVariables = $this->context->getVariableValues();\n\n        $skip = ValuesResolver::coerceDirectiveValues($this->skipDirective, $node, $contextVariables);\n\n        if ($skip && $skip['if'] === true) {\n            return false;\n        }\n\n        $include = ValuesResolver::coerceDirectiveValues($this->includeDirective, $node, $contextVariables);\n\n        if ($include && $include['if'] === false) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * @param FragmentDefinitionNode|InlineFragmentNode $fragment\n     * @param ObjectType                                $type\n     * @return bool\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected function doesFragmentConditionMatch($fragment, ObjectType $type): bool\n    {\n        $typeConditionNode = $fragment->getTypeCondition();\n\n        if (null === $typeConditionNode) {\n            return true;\n        }\n\n        $conditionalType = TypeASTConverter::convert($this->context->getSchema(), $typeConditionNode);\n\n        if ($type === $conditionalType) {\n            return true;\n        }\n\n        if ($conditionalType instanceof AbstractTypeInterface) {\n            return $this->context->getSchema()->isPossibleType($conditionalType, $type);\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Execution/Strategy/ParallelExecutionStrategy.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution\\Strategy;\n\nuse Digia\\GraphQL\\Execution\\UndefinedFieldException;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse React\\Promise\\PromiseInterface;\nuse function Digia\\GraphQL\\Util\\promiseForMap;\n\n/**\n * Implements the \"Evaluating selection sets\" section of the spec\n * for \"read\" mode.\n *\n * Class ParallelExecutionStrategy\n * @package Digia\\GraphQL\\Execution\\Strategy\n */\nclass ParallelExecutionStrategy extends AbstractExecutionStrategy\n{\n    /**\n     * @inheritdoc\n     */\n    public function executeFields(ObjectType $parentType, $rootValue, array $path, array $fields)\n    {\n        $results            = [];\n        $containsPromise = false;\n\n        foreach ($fields as $fieldName => $fieldNodes) {\n            $fieldPath   = $path;\n            $fieldPath[] = $fieldName;\n\n            try {\n                $result = $this->resolveField($parentType, $rootValue, $fieldNodes, $fieldPath);\n            } catch (UndefinedFieldException $exception) {\n                continue;\n            }\n\n            $containsPromise  = $containsPromise || $result instanceof PromiseInterface;\n            $results[$fieldName] = $result;\n        }\n\n        if (!$containsPromise) {\n            return $results;\n        }\n\n        // Otherwise, results is a map from field name to the result of resolving that\n        // field, which is possibly a promise. Return a promise that will return this\n        // same map, but with any promises replaced with the values they resolved to.\n        return promiseForMap($results);\n    }\n}\n"
  },
  {
    "path": "src/Execution/Strategy/SerialExecutionStrategy.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution\\Strategy;\n\nuse Digia\\GraphQL\\Execution\\UndefinedFieldException;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse React\\Promise\\PromiseInterface;\nuse function Digia\\GraphQL\\Util\\promiseReduce;\n\n/**\n * Implements the \"Evaluating selection sets\" section of the spec\n * for \"write\" mode.\n *\n * Class SerialExecutionStrategy\n * @package Digia\\GraphQL\\Execution\\Strategy\n */\nclass SerialExecutionStrategy extends AbstractExecutionStrategy\n{\n    /**\n     * @inheritdoc\n     */\n    public function executeFields(ObjectType $parentType, $rootValue, array $path, array $fields)\n    {\n        return promiseReduce(\n            \\array_keys($fields),\n            function ($results, $fieldName) use ($parentType, $rootValue, $path, $fields) {\n                $fieldNodes  = $fields[$fieldName];\n                $fieldPath   = $path;\n                $fieldPath[] = $fieldName;\n\n                try {\n                    $result = $this->resolveField($parentType, $rootValue, $fieldNodes, $fieldPath);\n                } catch (UndefinedFieldException $exception) {\n                    return null;\n                }\n\n                if ($result instanceof PromiseInterface) {\n                    return $result->then(function ($resolvedResult) use ($fieldName, $results) {\n                        $results[$fieldName] = $resolvedResult;\n                        return $results;\n                    });\n                }\n\n                $results[$fieldName] = $result;\n\n                return $results;\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "src/Execution/UndefinedFieldException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\AbstractException;\n\nclass UndefinedFieldException extends AbstractException\n{\n    /**\n     * UndefinedFieldDefinitionException constructor.\n     */\n    public function __construct(string $fieldName)\n    {\n        parent::__construct(\\sprintf('Undefined field \"%s\".', $fieldName));\n    }\n}\n"
  },
  {
    "path": "src/Execution/ValuesResolver.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Execution;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentsAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Coercer\\CoercingException;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\EnumValue;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\WrappingTypeInterface;\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Util\\ValueASTConverter;\nuse function Digia\\GraphQL\\Test\\jsonEncode;\nuse function Digia\\GraphQL\\Util\\find;\nuse function Digia\\GraphQL\\Util\\invariant;\nuse function Digia\\GraphQL\\Util\\keyMap;\nuse function Digia\\GraphQL\\Util\\suggestionList;\n\nclass ValuesResolver\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     * @see https://facebook.github.io/graphql/October2016/#CoerceArgumentValues()\n     *\n     * @param Field|Directive         $definition\n     * @param ArgumentsAwareInterface $node\n     * @param array                   $variableValues\n     * @return array\n     * @throws ExecutionException\n     * @throws InvariantException\n     */\n    public static function coerceArgumentValues(\n        $definition,\n        ArgumentsAwareInterface $node,\n        array $variableValues = []\n    ): array {\n        $coercedValues       = [];\n        $argumentDefinitions = $definition->getArguments();\n        $argumentNodes       = $node->getArguments();\n\n        if (empty($argumentDefinitions)) {\n            return $coercedValues;\n        }\n\n        /** @var ArgumentNode[] $argumentNodeMap */\n        $argumentNodeMap = keyMap($argumentNodes, function (ArgumentNode $value) {\n            return $value->getNameValue();\n        });\n\n        foreach ($argumentDefinitions as $argumentDefinition) {\n            $argumentName  = $argumentDefinition->getName();\n            $argumentType  = $argumentDefinition->getType();\n            $argumentNode  = $argumentNodeMap[$argumentName] ?? null;\n            $defaultValue  = $argumentDefinition->getDefaultValue();\n            $argumentValue = null !== $argumentNode ? $argumentNode->getValue() : null;\n\n            if (null !== $argumentNode && $argumentValue instanceof VariableNode) {\n                $variableName = $argumentValue->getNameValue();\n                $hasValue     = !empty($variableValues) && \\array_key_exists($variableName, $variableValues);\n                $isNull       = $hasValue && null === $variableValues[$variableName];\n            } else {\n                $hasValue = null !== $argumentNode;\n                $isNull   = $hasValue && $argumentValue instanceof NullValueNode;\n            }\n\n            if (!$hasValue && null !== $defaultValue) {\n                // If no argument was provided where the definition has a default value,\n                // use the default value.\n                $coercedValues[$argumentName] = $defaultValue;\n            } elseif ((!$hasValue || $isNull) && $argumentType instanceof NonNullType) {\n                // If no argument or a null value was provided to an argument with a\n                // non-null type (required), produce a field error.\n                if ($isNull) {\n                    throw new ExecutionException(\n                        \\sprintf(\n                            'Argument \"%s\" of non-null type \"%s\" must not be null.',\n                            $argumentName,\n                            $argumentType\n                        ),\n                        [$argumentValue]\n                    );\n                } elseif (null !== $argumentNode && $argumentValue instanceof VariableNode) {\n                    $variableName = $argumentValue->getNameValue();\n                    throw new ExecutionException(\n                        \\sprintf(\n                            'Argument \"%s\" of required type \"%s\" was provided the variable \"$%s\" '\n                            . 'which was not provided a runtime value.',\n                            $argumentName,\n                            $argumentType,\n                            $variableName\n                        ),\n                        [$argumentValue]\n                    );\n                } else {\n                    throw new ExecutionException(\n                        \\sprintf(\n                            'Argument \"%s\" of required type \"%s\" was not provided.',\n                            $argumentName,\n                            $argumentType\n                        ),\n                        [$node]\n                    );\n                }\n            } elseif ($hasValue) {\n                if ($argumentValue instanceof NullValueNode) {\n                    // If the explicit value `null` was provided, an entry in the coerced\n                    // values must exist as the value `null`.\n                    $coercedValues[$argumentName] = null;\n                } elseif ($argumentValue instanceof VariableNode) {\n                    $variableName = $argumentValue->getNameValue();\n                    invariant(!empty($variableValues), 'Must exist for hasValue to be true.');\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                    $coercedValues[$argumentName] = $variableValues[$variableName];\n                } else {\n                    $valueNode = $argumentNode->getValue();\n                    try {\n                        // Value nodes that cannot be resolved should be treated as invalid values\n                        // because there is no undefined value in PHP so that we throw an exception\n                        $coercedValue = ValueASTConverter::convert($valueNode, $argumentType, $variableValues);\n                    } catch (\\Exception $ex) {\n                        // Note: ValuesOfCorrectType 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 ExecutionException(\n                            \\sprintf(\n                                'Argument \"%s\" has invalid value %s.',\n                                $argumentName,\n                                (string)$argumentValue\n                            ),\n                            [$argumentValue],\n                            null,\n                            null,\n                            null,\n                            null,\n                            $ex\n                        );\n                    }\n                    $coercedValues[$argumentName] = $coercedValue;\n                }\n            }\n        }\n\n        return $coercedValues;\n    }\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 null.\n     *\n     * @param Directive $directive\n     * @param mixed     $node\n     * @param array     $variableValues\n     * @return array|null\n     * @throws ExecutionException\n     * @throws InvariantException\n     */\n    public static function coerceDirectiveValues(\n        Directive $directive,\n        $node,\n        array $variableValues = []\n    ): ?array {\n        $directiveNode = $node->hasDirectives()\n            ? find($node->getDirectives(), function (NameAwareInterface $value) use ($directive) {\n                return $value->getNameValue() === $directive->getName();\n            }) : null;\n\n        if (null !== $directiveNode) {\n            return static::coerceArgumentValues($directive, $directiveNode, $variableValues);\n        }\n\n        return null;\n    }\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     * @param Schema                         $schema\n     * @param array|VariableDefinitionNode[] $variableDefinitionNodes\n     * @param array                          $inputs\n     * @return CoercedValue\n     * @throws GraphQLException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    public static function coerceVariableValues(\n        Schema $schema,\n        array $variableDefinitionNodes,\n        array $inputs\n    ): CoercedValue {\n        $coercedValues = [];\n        $errors        = [];\n\n        foreach ($variableDefinitionNodes as $variableDefinitionNode) {\n            $variableName     = $variableDefinitionNode->getVariable()->getNameValue();\n            $variableType     = TypeASTConverter::convert($schema, $variableDefinitionNode->getType());\n            $variableTypeName = (string)$variableType;\n\n            if ($variableTypeName === '') {\n                $variableTypeName = (string)$variableDefinitionNode;\n            }\n\n            if (!static::isInputType($variableType)) {\n                // Must use input types for variables. This should be caught during\n                // validation, however is checked again here for safety.\n                $errors[] = static::buildCoerceException(\n                    \\sprintf(\n                        'Variable \"$%s\" expected value of type \"%s\" which cannot be used as an input type',\n                        $variableName,\n                        $variableTypeName\n                    ),\n                    $variableDefinitionNode,\n                    null\n                );\n            } else {\n                $hasValue = \\array_key_exists($variableName, $inputs);\n                $value    = $hasValue ? $inputs[$variableName] : null;\n                if (!$hasValue && $variableDefinitionNode->hasDefaultValue()) {\n                    // If no value was provided to a variable with a default value,\n                    // use the default value.\n                    $coercedValues[$variableName] = ValueASTConverter::convert(\n                        $variableDefinitionNode->getDefaultValue(),\n                        $variableType\n                    );\n                } elseif ((!$hasValue || null === $value) && $variableType instanceof NonNullType) {\n                    // If no value or a nullish value was provided to a variable with a\n                    // non-null type (required), produce an error.\n                    $errors[] = static::buildCoerceException(\n                        \\sprintf(\n                            $value\n                                ? 'Variable \"$%s\" of non-null type \"%s\" must not be null'\n                                : 'Variable \"$%s\" of required type \"%s\" was not provided',\n                            $variableName,\n                            $variableTypeName\n                        ),\n                        $variableDefinitionNode,\n                        null\n                    );\n                } elseif ($hasValue) {\n                    if (null === $value) {\n                        // If the explicit value `null` was provided, an entry in the coerced\n                        // values must exist as the value `null`.\n                        $coercedValues[$variableName] = null;\n                    } else {\n                        // Otherwise, a non-null value was provided, coerce it to the expected\n                        // type or report an error if coercion fails.\n                        $coercedValue = static::coerceValue($value, $variableType, $variableDefinitionNode);\n                        if ($coercedValue->hasErrors()) {\n                            $message = \\sprintf(\n                                'Variable \"$%s\" got invalid value %s',\n                                $variableName,\n                                jsonEncode($value)\n                            );\n                            foreach ($coercedValue->getErrors() as $error) {\n                                $errors[] = static::buildCoerceException(\n                                    $message,\n                                    $variableDefinitionNode,\n                                    null,\n                                    $error->getMessage(),\n                                    $error\n                                );\n                            }\n                        } else {\n                            $coercedValues[$variableName] = $coercedValue->getValue();\n                        }\n                    }\n                }\n            }\n        }\n\n        return new CoercedValue($coercedValues, $errors);\n    }\n\n    /**\n     * @param TypeInterface|null $type\n     * @return bool\n     */\n    protected static function isInputType(?TypeInterface $type)\n    {\n        return ($type instanceof ScalarType) ||\n            ($type instanceof EnumType) ||\n            ($type instanceof InputObjectType) ||\n            (($type instanceof WrappingTypeInterface) && static::isInputType($type->getOfType()));\n    }\n\n    /**\n     * Returns either a value which is valid for the provided type or a list of\n     * encountered coercion errors.\n     *\n     * @param mixed|array   $value\n     * @param mixed         $type\n     * @param NodeInterface $blameNode\n     * @param Path|null     $path\n     * @return CoercedValue\n     * @throws GraphQLException\n     * @throws InvariantException\n     */\n    protected static function coerceValue($value, $type, $blameNode, ?Path $path = null): CoercedValue\n    {\n        if ($type instanceof NonNullType) {\n            return static::coerceValueForNonNullType($value, $type, $blameNode, $path);\n        }\n\n        if (null === $value) {\n            return new CoercedValue(null);\n        }\n\n        if ($type instanceof ScalarType) {\n            return static::coerceValueForScalarType($value, $type, $blameNode, $path);\n        }\n\n        if ($type instanceof EnumType) {\n            return static::coerceValueForEnumType($value, $type, $blameNode, $path);\n        }\n\n        if ($type instanceof ListType) {\n            return static::coerceValueForListType($value, $type, $blameNode, $path);\n        }\n\n        if ($type instanceof InputObjectType) {\n            return static::coerceValueForInputObjectType($value, $type, $blameNode, $path);\n        }\n\n        throw new GraphQLException('Unexpected type.');\n    }\n\n    /**\n     * @param mixed         $value\n     * @param NonNullType   $type\n     * @param NodeInterface $blameNode\n     * @param Path|null     $path\n     * @return CoercedValue\n     * @throws GraphQLException\n     * @throws InvariantException\n     */\n    protected static function coerceValueForNonNullType(\n        $value,\n        NonNullType $type,\n        NodeInterface $blameNode,\n        ?Path $path\n    ): CoercedValue {\n        if (null === $value) {\n            return new CoercedValue(null, [\n                static::buildCoerceException(\n                    \\sprintf('Expected non-nullable type %s not to be null', (string)$type),\n                    $blameNode,\n                    $path\n                )\n            ]);\n        }\n        return static::coerceValue($value, $type->getOfType(), $blameNode, $path);\n    }\n\n    /**\n     * Scalars determine if a value is valid via parseValue(), which can\n     * throw to indicate failure. If it throws, maintain a reference to\n     * the original error.\n     *\n     * @param mixed         $value\n     * @param ScalarType    $type\n     * @param NodeInterface $blameNode\n     * @param Path|null     $path\n     * @return CoercedValue\n     */\n    protected static function coerceValueForScalarType(\n        $value,\n        ScalarType $type,\n        NodeInterface $blameNode,\n        ?Path $path\n    ): CoercedValue {\n        try {\n            $parseResult = $type->parseValue($value);\n            if (null === $parseResult) {\n                return new CoercedValue(null, [\n                    new GraphQLException(\\sprintf('Expected type %s', (string)$type))\n                ]);\n            }\n            return new CoercedValue($parseResult);\n        } /** @noinspection PhpRedundantCatchClauseInspection */ catch (InvalidTypeException|CoercingException $ex) {\n            return new CoercedValue(null, [\n                static::buildCoerceException(\n                    \\sprintf('Expected type %s', (string)$type),\n                    $blameNode,\n                    $path,\n                    $ex->getMessage(),\n                    $ex\n                )\n            ]);\n        }\n    }\n\n    /**\n     * @param mixed         $value\n     * @param EnumType      $type\n     * @param NodeInterface $blameNode\n     * @param Path|null     $path\n     * @return CoercedValue\n     * @throws InvariantException\n     */\n    protected static function coerceValueForEnumType(\n        $value,\n        EnumType $type,\n        NodeInterface $blameNode,\n        ?Path $path\n    ): CoercedValue {\n        if (\\is_string($value) && null !== ($enumValue = $type->getValue($value))) {\n            return new CoercedValue($enumValue);\n        }\n\n        $suggestions = suggestionList((string)$value, \\array_map(function (EnumValue $enumValue) {\n            return $enumValue->getName();\n        }, $type->getValues()));\n\n        $didYouMean = (!empty($suggestions))\n            ? 'did you mean' . \\implode(',', $suggestions)\n            : null;\n\n        return new CoercedValue(null, [\n            static::buildCoerceException(\\sprintf('Expected type %s', $type->getName()), $blameNode, $path, $didYouMean)\n        ]);\n    }\n\n    /**\n     * @param mixed           $value\n     * @param InputObjectType $type\n     * @param NodeInterface   $blameNode\n     * @param Path|null       $path\n     * @return CoercedValue\n     * @throws InvariantException\n     * @throws GraphQLException\n     */\n    protected static function coerceValueForInputObjectType(\n        $value,\n        InputObjectType $type,\n        NodeInterface $blameNode,\n        ?Path $path\n    ): CoercedValue {\n        $errors        = [];\n        $coercedValues = [];\n        $fields        = $type->getFields();\n\n        // Ensure every defined field is valid.\n        foreach ($fields as $field) {\n            $fieldType = $field->getType();\n\n            if (!isset($value[$field->getName()])) {\n                if (!empty($field->getDefaultValue())) {\n                    $coercedValue[$field->getName()] = $field->getDefaultValue();\n                } elseif ($fieldType instanceof NonNullType) {\n                    $errors[] = new GraphQLException(\n                        \\sprintf(\n                            \"Field %s of required type %s! was not provided.\",\n                            static::printPath(new Path($path, $field->getName())),\n                            (string)$fieldType->getOfType()\n                        )\n                    );\n                }\n            } else {\n                $fieldValue   = $value[$field->getName()];\n                $coercedValue = static::coerceValue(\n                    $fieldValue,\n                    $fieldType,\n                    $blameNode,\n                    new Path($path, $field->getName())\n                );\n\n                if ($coercedValue->hasErrors()) {\n                    $errors = \\array_merge($errors, $coercedValue->getErrors());\n                } elseif (empty($errors)) {\n                    $coercedValues[$field->getName()] = $coercedValue->getValue();\n                }\n            }\n        }\n\n        // Ensure every provided field is defined.\n        foreach ($value as $fieldName => $fieldValue) {\n            if (!isset($fields[$fieldName])) {\n                $suggestions = suggestionList($fieldName, \\array_keys($fields));\n                $didYouMean  = (!empty($suggestions))\n                    ? 'did you mean' . \\implode(',', $suggestions)\n                    : null;\n\n                $errors[] = static::buildCoerceException(\n                    \\sprintf('Field \"%s\" is not defined by type %s', $fieldName, $type->getName()),\n                    $blameNode,\n                    $path,\n                    $didYouMean\n                );\n            }\n        }\n\n        return new CoercedValue($coercedValues, $errors);\n    }\n\n    /**\n     * @param mixed         $value\n     * @param ListType      $type\n     * @param NodeInterface $blameNode\n     * @param Path|null     $path\n     * @return CoercedValue\n     * @throws GraphQLException\n     * @throws InvariantException\n     */\n    protected static function coerceValueForListType(\n        $value,\n        ListType $type,\n        NodeInterface $blameNode,\n        ?Path $path\n    ): CoercedValue {\n        $itemType = $type->getOfType();\n\n        if (\\is_array($value) || $value instanceof \\Traversable) {\n            $errors        = [];\n            $coercedValues = [];\n\n            foreach ($value as $index => $itemValue) {\n                $coercedValue = static::coerceValue($itemValue, $itemType, $blameNode, new Path($path, $index));\n\n                if ($coercedValue->hasErrors()) {\n                    $errors = \\array_merge($errors, $coercedValue->getErrors());\n                } else {\n                    $coercedValues[] = $coercedValue->getValue();\n                }\n            }\n\n            return new CoercedValue($coercedValues, $errors);\n        }\n\n        // Lists accept a non-list value as a list of one.\n        $coercedValue = static::coerceValue($value, $itemType, $blameNode);\n\n        return new CoercedValue([$coercedValue->getValue()], $coercedValue->getErrors());\n    }\n\n    /**\n     * @param string                $message\n     * @param NodeInterface         $blameNode\n     * @param Path|null             $path\n     * @param null|string           $subMessage\n     * @param GraphQLException|null $originalException\n     * @return GraphQLException\n     */\n    protected static function buildCoerceException(\n        string $message,\n        NodeInterface $blameNode,\n        ?Path $path,\n        ?string $subMessage = null,\n        ?GraphQLException $originalException = null\n    ) {\n        $stringPath = static::printPath($path);\n\n        return new CoercingException(\n            $message .\n            (($stringPath !== '') ? ' at ' . $stringPath : $stringPath) .\n            (($subMessage !== null) ? '; ' . $subMessage : '.'),\n            [$blameNode],\n            null,\n            null,\n            null,\n            null,\n            $originalException\n        );\n    }\n\n    /**\n     * @param Path|null $path\n     * @return string\n     */\n    protected static function printPath(?Path $path)\n    {\n        $stringPath  = '';\n        $currentPath = $path;\n\n        while ($currentPath !== null) {\n            $stringPath = \\is_string($currentPath->getKey())\n                ? '.' . $currentPath->getKey() . $stringPath\n                : '[' . (string)$currentPath->getKey() . ']' . $stringPath;\n\n            $currentPath = $currentPath->getPrevious();\n        }\n\n        return !empty($stringPath) ? 'value' . $stringPath : '';\n    }\n}\n"
  },
  {
    "path": "src/GraphQL.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL;\n\nuse Digia\\GraphQL\\Error\\Handler\\ErrorHandlerInterface;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Execution\\ExecutionInterface;\nuse Digia\\GraphQL\\Execution\\ExecutionProvider;\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Language\\LanguageProvider;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ValueNodeInterface;\nuse Digia\\GraphQL\\Language\\NodePrinterInterface;\nuse Digia\\GraphQL\\Language\\ParserInterface;\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Language\\SyntaxErrorException;\nuse Digia\\GraphQL\\Schema\\Building\\SchemaBuilderInterface;\nuse Digia\\GraphQL\\Schema\\Building\\SchemaBuildingProvider;\nuse Digia\\GraphQL\\Schema\\Extension\\SchemaExtenderInterface;\nuse Digia\\GraphQL\\Schema\\Extension\\SchemaExtensionProvider;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistry;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidationProvider;\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidatorInterface;\nuse Digia\\GraphQL\\Type\\CoercerProvider;\nuse Digia\\GraphQL\\Type\\DirectivesProvider;\nuse Digia\\GraphQL\\Type\\IntrospectionProvider;\nuse Digia\\GraphQL\\Type\\ScalarTypesProvider;\nuse Digia\\GraphQL\\Validation\\RulesProvider;\nuse Digia\\GraphQL\\Validation\\ValidationProvider;\nuse Digia\\GraphQL\\Validation\\ValidatorInterface;\nuse League\\Container\\Container;\nuse React\\Promise\\PromiseInterface;\nuse function React\\Promise\\resolve;\n\nclass GraphQL\n{\n    public const BOOLEAN = 'GraphQLBoolean';\n    public const FLOAT   = 'GraphQLFloat';\n    public const INT     = 'GraphQLInt';\n    public const ID      = 'GraphQLID';\n    public const STRING  = 'GraphQLString';\n\n    public const DEPRECATED_DIRECTIVE = 'GraphQLDeprecatedDirective';\n    public const INCLUDE_DIRECTIVE    = 'GraphQLIncludeDirective';\n    public const SKIP_DIRECTIVE       = 'GraphQLSkipDirective';\n\n    public const SCHEMA_INTROSPECTION             = '__Schema';\n    public const DIRECTIVE_INTROSPECTION          = '__Directive';\n    public const DIRECTIVE_LOCATION_INTROSPECTION = '__DirectiveLocation';\n    public const TYPE_INTROSPECTION               = '__Type';\n    public const FIELD_INTROSPECTION              = '__Field';\n    public const INPUT_VALUE_INTROSPECTION        = '__InputValue';\n    public const ENUM_VALUE_INTROSPECTION         = '__EnumValue';\n    public const TYPE_KIND_INTROSPECTION          = '__TypeKind';\n\n    public const SCHEMA_META_FIELD_DEFINITION    = 'SchemaMetaFieldDefinition';\n    public const TYPE_META_FIELD_DEFINITION      = 'TypeMetaFieldDefinition';\n    public const TYPE_NAME_META_FIELD_DEFINITION = 'TypeNameMetaFieldDefinition';\n\n    /**\n     * @var array\n     */\n    private static $providers = [\n        LanguageProvider::class,\n        SchemaBuildingProvider::class,\n        SchemaExtensionProvider::class,\n        SchemaValidationProvider::class,\n        CoercerProvider::class,\n        IntrospectionProvider::class,\n        ScalarTypesProvider::class,\n        DirectivesProvider::class,\n        RulesProvider::class,\n        ValidationProvider::class,\n        ExecutionProvider::class,\n    ];\n\n    /**\n     * @var GraphQL\n     */\n    private static $instance;\n\n    /**\n     * @var Container\n     */\n    protected $container;\n\n    /**\n     * GraphQL constructor.\n     */\n    private function __construct()\n    {\n        $container = new Container();\n\n        $this->registerProviders($container);\n\n        $this->container = $container;\n    }\n\n    /**\n     * @return GraphQL\n     */\n    public static function getInstance(): self\n    {\n        if (null === self::$instance) {\n            self::$instance = new self();\n        }\n\n        return self::$instance;\n    }\n\n    /**\n     * @param string $id\n     * @return mixed\n     */\n    public static function make(string $id)\n    {\n        return static::getInstance()\n            ->getContainer()\n            ->get($id);\n    }\n\n    /**\n     * @param Source                          $source\n     * @param array|ResolverRegistryInterface $resolverRegistry\n     * @param array                           $options\n     * @return Schema\n     */\n    public static function buildSchema(Source $source, $resolverRegistry, array $options = []): Schema\n    {\n        /** @var SchemaBuilderInterface $schemaBuilder */\n        $schemaBuilder = static::make(SchemaBuilderInterface::class);\n\n        return $schemaBuilder->build(\n            static::parse($source, $options),\n            $resolverRegistry instanceof ResolverRegistryInterface\n                ? $resolverRegistry\n                : new ResolverRegistry($resolverRegistry),\n            $options\n        );\n    }\n\n    /**\n     * @param Schema                          $schema\n     * @param Source                          $source\n     * @param array|ResolverRegistryInterface $resolverRegistry\n     * @param array                           $options\n     * @return Schema\n     */\n    public static function extendSchema(\n        Schema $schema,\n        Source $source,\n        $resolverRegistry,\n        array $options = []\n    ): Schema {\n        /** @var SchemaExtenderInterface $schemaExtender */\n        $schemaExtender = static::make(SchemaExtenderInterface::class);\n\n        return $schemaExtender->extend(\n            $schema,\n            static::parse($source, $options),\n            $resolverRegistry instanceof ResolverRegistryInterface\n                ? $resolverRegistry\n                : new ResolverRegistry($resolverRegistry),\n            $options\n        );\n    }\n\n    /**\n     * @param Schema $schema\n     * @return array\n     */\n    public static function validateSchema(Schema $schema): array\n    {\n        /** @var SchemaValidatorInterface $schemaValidator */\n        $schemaValidator = static::make(SchemaValidatorInterface::class);\n\n        return $schemaValidator->validate($schema);\n    }\n\n    /**\n     * @param Source $source\n     * @param array  $options\n     * @return DocumentNode\n     */\n    public static function parse(Source $source, array $options = []): DocumentNode\n    {\n        /** @var ParserInterface $parser */\n        $parser = static::make(ParserInterface::class);\n\n        return $parser->parse($source, $options);\n    }\n\n    /**\n     * @param Source $source\n     * @param array  $options\n     * @return ValueNodeInterface\n     */\n    public static function parseValue(Source $source, array $options = []): ValueNodeInterface\n    {\n        /** @var ParserInterface $parser */\n        $parser = static::make(ParserInterface::class);\n\n        return $parser->parseValue($source, $options);\n    }\n\n    /**\n     * @param Source $source\n     * @param array  $options\n     * @return TypeNodeInterface\n     */\n    public static function parseType(Source $source, array $options = []): TypeNodeInterface\n    {\n        /** @var ParserInterface $parser */\n        $parser = static::make(ParserInterface::class);\n\n        return $parser->parseType($source, $options);\n    }\n\n    /**\n     * @param Schema       $schema\n     * @param DocumentNode $document\n     * @return array\n     */\n    public static function validate(Schema $schema, DocumentNode $document): array\n    {\n        /** @var ValidatorInterface $validator */\n        $validator = static::make(ValidatorInterface::class);\n\n        return $validator->validate($schema, $document);\n    }\n\n    /**\n     * @param Schema                     $schema\n     * @param DocumentNode               $document\n     * @param mixed                      $rootValue\n     * @param mixed                      $contextValue\n     * @param array                      $variableValues\n     * @param string|null                $operationName\n     * @param callable|null              $fieldResolver\n     * @param ErrorHandlerInterface|null $errorHandler\n     * @return PromiseInterface\n     */\n    public static function execute(\n        Schema $schema,\n        DocumentNode $document,\n        $rootValue = null,\n        $contextValue = null,\n        array $variableValues = [],\n        $operationName = null,\n        callable $fieldResolver = null,\n        ?ErrorHandlerInterface $errorHandler = null\n    ): PromiseInterface {\n        /** @var ExecutionInterface $execution */\n        $execution = static::make(ExecutionInterface::class);\n\n        return $execution->execute(\n            $schema,\n            $document,\n            $rootValue,\n            $contextValue,\n            $variableValues,\n            $operationName,\n            $fieldResolver,\n            $errorHandler\n        );\n    }\n\n    /**\n     * @param Schema                     $schema\n     * @param string                     $source\n     * @param mixed                      $rootValue\n     * @param mixed                      $contextValue\n     * @param array                      $variableValues\n     * @param null|string                $operationName\n     * @param callable|null              $fieldResolver\n     * @param ErrorHandlerInterface|null $errorHandler\n     * @return PromiseInterface\n     * @throws InvariantException\n     */\n    public static function process(\n        Schema $schema,\n        string $source,\n        $rootValue = null,\n        $contextValue = null,\n        array $variableValues = [],\n        ?string $operationName = null,\n        ?callable $fieldResolver = null,\n        ?ErrorHandlerInterface $errorHandler = null\n    ): PromiseInterface {\n        $schemaValidationErrors = validateSchema($schema);\n\n        if (!empty($schemaValidationErrors)) {\n            if (null !== $errorHandler) {\n                foreach ($schemaValidationErrors as $schemaValidationError) {\n                    $errorHandler->handleError($schemaValidationError);\n                }\n            }\n\n            return resolve(new ExecutionResult(null, $schemaValidationErrors));\n        }\n\n        try {\n            $document = parse($source);\n        } catch (SyntaxErrorException $error) {\n            if (null !== $errorHandler) {\n                $errorHandler->handleError($error);\n            }\n\n            return resolve(new ExecutionResult(null, [$error]));\n        }\n\n        $validationErrors = validate($schema, $document);\n\n        if (!empty($validationErrors)) {\n            if (null !== $errorHandler) {\n                foreach ($validationErrors as $validationError) {\n                    $errorHandler->handleError($validationError);\n                }\n            }\n\n            return resolve(new ExecutionResult(null, $validationErrors));\n        }\n\n        return executeAsync(\n            $schema,\n            $document,\n            $rootValue,\n            $contextValue,\n            $variableValues,\n            $operationName,\n            $fieldResolver,\n            $errorHandler\n        );\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return string\n     */\n    public static function print(NodeInterface $node): string\n    {\n        /** @var NodePrinterInterface $nodePrinter */\n        $nodePrinter = static::make(NodePrinterInterface::class);\n\n        return $nodePrinter->print($node);\n    }\n\n    /**\n     * @return Container\n     */\n    public function getContainer(): Container\n    {\n        return $this->container;\n    }\n\n    /**\n     * Registers the service provides with the container.\n     *\n     * @param Container $container\n     */\n    protected function registerProviders(Container $container): void\n    {\n        foreach (self::$providers as $className) {\n            $container->addServiceProvider($className);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Language/DirectiveLocationEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nclass DirectiveLocationEnum\n{\n\n    // Request Definitions\n    public const QUERY               = 'QUERY';\n    public const MUTATION            = 'MUTATION';\n    public const SUBSCRIPTION        = 'SUBSCRIPTION';\n    public const FIELD               = 'FIELD';\n    public const FRAGMENT_DEFINITION = 'FRAGMENT_DEFINITION';\n    public const FRAGMENT_SPREAD     = 'FRAGMENT_SPREAD';\n    public const INLINE_FRAGMENT     = 'INLINE_FRAGMENT';\n    public const VARIABLE_DEFINITION = 'VARIABLE_DEFINITION';\n    // Type System Definitions\n    public const SCHEMA                 = 'SCHEMA';\n    public const SCALAR                 = 'SCALAR';\n    public const OBJECT                 = 'OBJECT';\n    public const FIELD_DEFINITION       = 'FIELD_DEFINITION';\n    public const ARGUMENT_DEFINITION    = 'ARGUMENT_DEFINITION';\n    public const INTERFACE              = 'INTERFACE';\n    public const UNION                  = 'UNION';\n    public const ENUM                   = 'ENUM';\n    public const ENUM_VALUE             = 'ENUM_VALUE';\n    public const INPUT_OBJECT           = 'INPUT_OBJECT';\n    public const INPUT_FIELD_DEFINITION = 'INPUT_FIELD_DEFINITION';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Language/FileSourceBuilder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\FileNotFoundException;\nuse Digia\\GraphQL\\Error\\InvariantException;\n\n/**\n * Class FileSourceBuilder\n * @package Digia\\GraphQL\\Language\n */\nclass FileSourceBuilder implements SourceBuilderInterface\n{\n    /**\n     * @var string\n     */\n    private $filePath;\n\n    /**\n     * FileSourceBuilder constructor.\n     * @param string $filePath\n     */\n    public function __construct(string $filePath)\n    {\n        $this->filePath = $filePath;\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * @throws FileNotFoundException\n     * @throws InvariantException\n     */\n    public function build(): Source\n    {\n        if (!\\file_exists($this->filePath) || !\\is_readable($this->filePath)) {\n            throw new FileNotFoundException(sprintf('The file %s cannot be found or is not readable', $this->filePath));\n        }\n\n        return new Source(\\file_get_contents($this->filePath));\n    }\n}\n"
  },
  {
    "path": "src/Language/KeywordEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nclass KeywordEnum\n{\n\n    public const SCHEMA       = 'schema';\n    public const SCALAR       = 'scalar';\n    public const TYPE         = 'type';\n    public const INTERFACE    = 'interface';\n    public const UNION        = 'union';\n    public const ENUM         = 'enum';\n    public const INPUT        = 'input';\n    public const EXTEND       = 'extend';\n    public const DIRECTIVE    = 'directive';\n    public const ON           = 'on';\n    public const FRAGMENT     = 'fragment';\n    public const QUERY        = 'query';\n    public const MUTATION     = 'mutation';\n    public const SUBSCRIPTION = 'subscription';\n    public const TRUE         = 'true';\n    public const FALSE        = 'false';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Language/LanguageException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\AbstractException;\n\nclass LanguageException extends AbstractException\n{\n}\n"
  },
  {
    "path": "src/Language/LanguageProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass LanguageProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        NodeBuilderInterface::class,\n        ParserInterface::class,\n        NodePrinterInterface::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->share(NodeBuilderInterface::class, NodeBuilder::class);\n        $this->container->share(NodePrinterInterface::class, NodePrinter::class);\n        $this->container->add(ParserInterface::class, Parser::class);\n    }\n}\n"
  },
  {
    "path": "src/Language/Lexer.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\n/**\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 */\nclass Lexer implements LexerInterface\n{\n    protected const ENCODING = 'UTF-8';\n\n    /**\n     * A map between punctuation character code and the corresponding token kind.\n     *\n     * @var array\n     */\n    protected static $codeTokenKindMap = [\n        33  => TokenKindEnum::BANG,\n        36  => TokenKindEnum::DOLLAR,\n        38  => TokenKindEnum::AMP,\n        40  => TokenKindEnum::PAREN_L,\n        41  => TokenKindEnum::PAREN_R,\n        58  => TokenKindEnum::COLON,\n        61  => TokenKindEnum::EQUALS,\n        64  => TokenKindEnum::AT,\n        91  => TokenKindEnum::BRACKET_L,\n        93  => TokenKindEnum::BRACKET_R,\n        123 => TokenKindEnum::BRACE_L,\n        124 => TokenKindEnum::PIPE,\n        125 => TokenKindEnum::BRACE_R,\n    ];\n\n    /**\n     * The source file for this lexer.\n     *\n     * @var Source\n     */\n    protected $source;\n\n    /**\n     * The contents of the source file.\n     *\n     * @var string\n     */\n    protected $body;\n\n    /**\n     * The total number of characters in the source file.\n     *\n     * @var int\n     */\n    protected $bodyLength;\n\n    /**\n     * The options for this lexer.\n     *\n     * @var array\n     */\n    protected $options = [];\n\n    /**\n     * The previously focused non-ignored token.\n     *\n     * @var Token\n     */\n    protected $lastToken;\n\n    /**\n     * The currently focused non-ignored token.\n     *\n     * @var Token\n     */\n    protected $token;\n\n    /**\n     * The current position.\n     *\n     * @var int\n     */\n    protected $position;\n\n    /**\n     * The (1-indexed) line containing the current token.\n     *\n     * @var int\n     */\n    protected $line;\n\n    /**\n     * The character offset at which the current line begins.\n     *\n     * @var int\n     */\n    protected $lineStart;\n\n    /**\n     * A key-value map over characters and their corresponding character codes.\n     *\n     * @var array\n     */\n    protected static $charCodeCache = [];\n\n    /**\n     * Lexer constructor.\n     * @param Source $source\n     * @param array  $options\n     */\n    public function __construct(Source $source, array $options)\n    {\n        $startOfFileToken = $this->createStartOfFileToken();\n\n        $this->lastToken  = $startOfFileToken;\n        $this->token      = $startOfFileToken;\n        $this->line       = 1;\n        $this->lineStart  = 0;\n        $this->body       = $source->getBody();\n        $this->bodyLength = \\mb_strlen($this->body);\n        $this->source     = $source;\n        $this->options    = $options;\n    }\n\n    /**\n     * @inheritdoc\n     * @throws SyntaxErrorException\n     */\n    public function advance(): Token\n    {\n        $this->lastToken = $this->token;\n        return $this->token = $this->lookahead();\n    }\n\n    /**\n     * @inheritdoc\n     * @throws SyntaxErrorException\n     */\n    public function lookahead(): Token\n    {\n        $token = $this->token;\n\n        if (TokenKindEnum::EOF !== $token->getKind()) {\n            do {\n                $next = $this->readToken($token);\n                $token->setNext($next);\n                $token = $next;\n            } while (TokenKindEnum::COMMENT === $token->getKind());\n        }\n\n        return $token;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getOption(string $name, $default = null)\n    {\n        return $this->options[$name] ?? $default;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getSource(): Source\n    {\n        return $this->source;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getToken(): Token\n    {\n        return $this->token;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getLastToken(): Token\n    {\n        return $this->lastToken;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function createSyntaxErrorException(?string $description = null): SyntaxErrorException\n    {\n        return new SyntaxErrorException(\n            $this->source,\n            $this->position,\n            $description ?? $this->unexpectedCharacterMessage($this->readCharCode($this->position))\n        );\n    }\n\n    /**\n     * Reads the token after the given token.\n     *\n     * @param Token $prev\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function readToken(Token $prev): Token\n    {\n        $this->position = $prev->getEnd();\n\n        $this->skipWhitespace();\n\n        $line   = $this->line;\n        $column = (1 + $this->position) - $this->lineStart;\n\n        if ($this->position >= $this->bodyLength) {\n            return $this->createEndOfFileToken($line, $column, $prev);\n        }\n\n        $code = $this->readCharCode($this->position);\n\n        // Punctuation: [!$&:=@|()\\[\\]{}]{1}\n        if (33 === $code || 36 === $code || 38 === $code || 58 === $code || 61 === $code || 64 === $code || 124 === $code ||\n            40 === $code || 41 === $code || 91 === $code || 93 === $code || 123 === $code || 125 === $code) {\n            return $this->lexPunctuation($code, $line, $column, $prev);\n        }\n\n        // Comment: #[\\u0009\\u0020-\\uFFFF]*\n        if (35 === $code) {\n            return $this->lexComment($line, $column, $prev);\n        }\n\n        // Int:   -?(0|[1-9][0-9]*)\n        // Float: -?(0|[1-9][0-9]*)(\\.[0-9]+)?((E|e)(+|-)?[0-9]+)?\n        if (45 === $code || isNumber($code)) {\n            return $this->lexNumber($code, $line, $column, $prev);\n        }\n\n        // Name: [_A-Za-z][_0-9A-Za-z]*\n        if (isAlphaNumeric($code)) {\n            return $this->lexName($line, $column, $prev);\n        }\n\n        // Spread: ...\n        if ($this->bodyLength >= 3 && $this->isSpread($code)) {\n            return $this->lexSpread($line, $column, $prev);\n        }\n\n        // String: \"([^\"\\\\\\u000A\\u000D]|(\\\\(u[0-9a-fA-F]{4}|[\"\\\\/bfnrt])))*\"\n        if ($this->isString($code)) {\n            return $this->lexString($line, $column, $prev);\n        }\n\n        // Block String: \"\"\"(\"?\"?(\\\\\"\"\"|\\\\(?!=\"\"\")|[^\"\\\\]))*\"\"\"\n        if ($this->bodyLength >= 3 && $this->isTripleQuote($code)) {\n            return $this->lexBlockString($line, $column, $prev);\n        }\n\n        throw $this->createSyntaxErrorException();\n    }\n\n    /**\n     * @return Token\n     */\n    protected function createStartOfFileToken(): Token\n    {\n        return new Token(TokenKindEnum::SOF);\n    }\n\n    /**\n     * Creates an End Of File (EOF) token.\n     *\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     */\n    protected function createEndOfFileToken(int $line, int $column, Token $prev): Token\n    {\n        return new Token(TokenKindEnum::EOF, $this->bodyLength, $this->bodyLength, $line, $column, $prev);\n    }\n\n    /**\n     * Reads a punctuation token from the source file.\n     *\n     * @param int   $code\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function lexPunctuation(int $code, int $line, int $column, Token $prev): ?Token\n    {\n        if (!isset(self::$codeTokenKindMap[$code])) {\n            throw $this->createSyntaxErrorException();\n        }\n\n        return new Token(self::$codeTokenKindMap[$code], $this->position, $this->position + 1, $line, $column, $prev);\n    }\n\n    /**\n     * Reads a name token from the source file.\n     *\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     */\n    protected function lexName(int $line, int $column, Token $prev): Token\n    {\n        $start = $this->position;\n\n        ++$this->position;\n\n        while ($this->position !== $this->bodyLength &&\n            ($code = $this->readCharCode($this->position)) !== 0 &&\n            isAlphaNumeric($code)) {\n            ++$this->position;\n        }\n\n        $value = sliceString($this->body, $start, $this->position);\n\n        return new Token(TokenKindEnum::NAME, $start, $this->position, $line, $column, $prev, $value);\n    }\n\n    /**\n     * Reads a number (int or float) token from the source file.\n     *\n     * @param int   $code\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function lexNumber(int $code, int $line, int $column, Token $prev): Token\n    {\n        $start   = $this->position;\n        $isFloat = false;\n\n        if (45 === $code) {\n            // -\n            $code = $this->readCharCode(++$this->position);\n        }\n\n        if (48 === $code) {\n            // 0\n            $code = $this->readCharCode(++$this->position);\n\n            if (isNumber($code)) {\n                throw $this->createSyntaxErrorException(\n                    \\sprintf('Invalid number, unexpected digit after 0: %s.', printCharCode($code))\n                );\n            }\n        } else {\n            $this->skipDigits($code);\n            $code = $this->readCharCode($this->position);\n        }\n\n        if (46 === $code) {\n            // .\n            $isFloat = true;\n\n            $code = $this->readCharCode(++$this->position);\n            $this->skipDigits($code);\n            $code = $this->readCharCode($this->position);\n        }\n\n        if (69 === $code || 101 === $code) {\n            // e or E\n            $isFloat = true;\n\n            $code = $this->readCharCode(++$this->position);\n\n            if (43 === $code || 45 === $code) {\n                // + or -\n                $code = $this->readCharCode(++$this->position);\n            }\n\n            $this->skipDigits($code);\n        }\n\n        return new Token(\n            $isFloat ? TokenKindEnum::FLOAT : TokenKindEnum::INT,\n            $start,\n            $this->position,\n            $line,\n            $column,\n            $prev,\n            sliceString($this->body, $start, $this->position)\n        );\n    }\n\n    /**\n     * Skips digits at the current position.\n     *\n     * @param int $code\n     * @throws SyntaxErrorException\n     */\n    protected function skipDigits(int $code): void\n    {\n        if (isNumber($code)) {\n            do {\n                $code = $this->readCharCode(++$this->position);\n            } while (isNumber($code));\n\n            return;\n        }\n\n        throw $this->createSyntaxErrorException(\n            \\sprintf('Invalid number, expected digit but got: %s.', printCharCode($code))\n        );\n    }\n\n    /**\n     * Reads a comment token from the source file.\n     *\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     */\n    protected function lexComment(int $line, int $column, Token $prev): Token\n    {\n        $start = $this->position;\n\n        do {\n            $code = $this->readCharCode(++$this->position);\n        } while ($code !== 0 && ($code > 0x001f || 0x0009 === $code)); // SourceCharacter but not LineTerminator\n\n        return new Token(\n            TokenKindEnum::COMMENT,\n            $start,\n            $this->position,\n            $line,\n            $column,\n            $prev,\n            sliceString($this->body, $start + 1, $this->position)\n        );\n    }\n\n    /**\n     * Reads a spread token from the source.\n     *\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     */\n    protected function lexSpread(int $line, int $column, Token $prev): Token\n    {\n        return new Token(TokenKindEnum::SPREAD, $this->position, $this->position + 3, $line, $column, $prev);\n    }\n\n    /**\n     * Reads a string token from the source.\n     *\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function lexString(int $line, int $column, Token $prev): Token\n    {\n        $start      = $this->position;\n        $chunkStart = ++$this->position; // skip the quote\n        $value      = '';\n\n        while ($this->position < $this->bodyLength) {\n            $code = $this->readCharCode($this->position);\n\n            if (isLineTerminator($code)) {\n                break;\n            }\n\n            // Closing Quote (\")\n            if (34 === $code) {\n                $value .= sliceString($this->body, $chunkStart, $this->position);\n                return new Token(TokenKindEnum::STRING, $start, $this->position + 1, $line, $column, $prev, $value);\n            }\n\n            if (isSourceCharacter($code)) {\n                throw $this->createSyntaxErrorException(\n                    \\sprintf('Invalid character within String: %s.', printCharCode($code))\n                );\n            }\n\n            ++$this->position;\n\n            if (92 === $code) {\n                // \\\n                $value .= sliceString($this->body, $chunkStart, $this->position - 1);\n\n                $code = $this->readCharCode($this->position);\n\n                switch ($code) {\n                    case 34: // \"\n                        $value .= '\"';\n                        break;\n                    case 47: // /\n                        $value .= '/';\n                        break;\n                    case 92: // \\\n                        $value .= '\\\\';\n                        break;\n                    case 98: // b\n                        $value .= '\\b';\n                        break;\n                    case 102: // f\n                        $value .= '\\f';\n                        break;\n                    case 110: // n\n                        $value .= '\\n';\n                        break;\n                    case 114: // r\n                        $value .= '\\r';\n                        break;\n                    case 116: // t\n                        $value .= '\\t';\n                        break;\n                    case 117: // u\n                        $unicodeString = sliceString($this->body, $this->position + 1, $this->position + 5);\n\n                        if (!\\preg_match('/[0-9A-Fa-f]{4}/', $unicodeString)) {\n                            throw $this->createSyntaxErrorException(\n                                \\sprintf('Invalid character escape sequence: \\\\u%s.', $unicodeString)\n                            );\n                        }\n\n                        $value .= '\\\\u' . $unicodeString;\n\n                        $this->position += 4;\n\n                        break;\n                    default:\n                        throw $this->createSyntaxErrorException(\n                            \\sprintf('Invalid character escape sequence: \\\\%s.', \\chr($code))\n                        );\n                }\n\n                ++$this->position;\n\n                $chunkStart = $this->position;\n            }\n        }\n\n        throw $this->createSyntaxErrorException('Unterminated string.');\n    }\n\n    /**\n     * Reads a block string token from the source file.\n     *\n     * @param int   $line\n     * @param int   $column\n     * @param Token $prev\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function lexBlockString(int $line, int $column, Token $prev): Token\n    {\n        $start          = $this->position;\n        $this->position = $start + 3; // skip the triple-quote\n        $chunkStart     = $this->position;\n        $rawValue       = '';\n\n        while ($this->position < $this->bodyLength) {\n            $code = $this->readCharCode($this->position);\n\n            // Closing Triple-Quote (\"\"\")\n            if ($this->isTripleQuote($code)) {\n                $rawValue .= sliceString($this->body, $chunkStart, $this->position);\n                return new Token(\n                    TokenKindEnum::BLOCK_STRING,\n                    $start,\n                    $this->position + 3,\n                    $line,\n                    $column,\n                    $prev,\n                    blockStringValue($rawValue)\n                );\n            }\n\n            if (isSourceCharacter($code) && !isLineTerminator($code)) {\n                throw $this->createSyntaxErrorException(\n                    \\sprintf('Invalid character within String: %s.', printCharCode($code))\n                );\n            }\n\n            if ($this->isEscapedTripleQuote($code)) {\n                $rawValue       .= sliceString($this->body, $chunkStart, $this->position) . '\"\"\"';\n                $this->position += 4;\n                $chunkStart     = $this->position;\n            } else {\n                ++$this->position;\n            }\n        }\n\n        throw $this->createSyntaxErrorException('Unterminated string.');\n    }\n\n    /**\n     * Skips whitespace at the current position.\n     */\n    protected function skipWhitespace(): void\n    {\n        while ($this->position < $this->bodyLength) {\n            $code = $this->readCharCode($this->position);\n\n            if (9 === $code || 32 === $code || 44 === $code || 0xfeff === $code) {\n                // tab | space | comma | BOM\n                ++$this->position;\n            } elseif (10 === $code) {\n                // new line (\\n)\n                ++$this->position;\n                ++$this->line;\n                $this->lineStart = $this->position;\n            } elseif (13 === $code) {\n                // carriage return (\\r)\n                if (10 === $this->readCharCode($this->position + 1)) {\n                    // carriage return and new line (\\r\\n)\n                    $this->position += 2;\n                } else {\n                    ++$this->position;\n                }\n                ++$this->line;\n                $this->lineStart = $this->position;\n            } else {\n                break;\n            }\n        }\n    }\n\n    /**\n     * @param int $position\n     * @return int\n     */\n    protected function readCharCode(int $position): int\n    {\n        $char = \\mb_substr($this->body, $position, 1, self::ENCODING);\n\n        if ('' === $char) {\n            return 0;\n        }\n\n        if (!isset(self::$charCodeCache[$char])) {\n            $code = \\ord($char);\n\n            if ($code >= 128) {\n                $code = \\mb_ord($char, self::ENCODING);\n            }\n\n            self::$charCodeCache[$char] = $code;\n        }\n\n        return self::$charCodeCache[$char];\n    }\n\n    /**\n     * Report a message that an unexpected character was encountered.\n     *\n     * @param int $code\n     * @return string\n     */\n    protected function unexpectedCharacterMessage(int $code): string\n    {\n        if (isSourceCharacter($code) && !isLineTerminator($code)) {\n            return \\sprintf('Cannot contain the invalid character %s.', 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 \\sprintf('Cannot parse the unexpected character %s.', printCharCode($code));\n    }\n\n    /**\n     * @param int $code\n     * @return bool\n     */\n    protected function isSpread(int $code): bool\n    {\n        return 46 === $code &&\n            $this->readCharCode($this->position + 1) === 46 &&\n            $this->readCharCode($this->position + 2) === 46; // ...\n    }\n\n    /**\n     * @param int $code\n     * @return bool\n     */\n    protected function isString(int $code): bool\n    {\n        return 34 === $code && $this->readCharCode($this->position + 1) !== 34;\n    }\n\n    /**\n     * @param int $code\n     * @return bool\n     */\n    protected function isTripleQuote(int $code): bool\n    {\n        return 34 === $code &&\n            34 === $this->readCharCode($this->position + 1) &&\n            34 === $this->readCharCode($this->position + 2); // \"\"\"\n    }\n\n    /**\n     * @param int $code\n     * @return bool\n     */\n    protected function isEscapedTripleQuote(int $code): bool\n    {\n        return $code === 92 &&\n            34 === $this->readCharCode($this->position + 1) &&\n            34 === $this->readCharCode($this->position + 2) &&\n            34 === $this->readCharCode($this->position + 3); // \\\"\"\"\n    }\n}\n"
  },
  {
    "path": "src/Language/LexerInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\ninterface LexerInterface\n{\n    /**\n     * Advances the token stream to the next non-ignored token.\n     *\n     * @return Token\n     */\n    public function advance(): Token;\n\n    /**\n     * Looks ahead and returns the next non-ignored token, but does not change\n     * the Lexer's state.\n     *\n     * @return Token\n     */\n    public function lookahead(): Token;\n\n    /**\n     * Returns an option given to this Lexer by its name.\n     *\n     * @param string     $name\n     * @param mixed|null $default\n     * @return mixed\n     */\n    public function getOption(string $name, $default = null);\n\n    /**\n     * Returns the source lexed by this Lexer.\n     *\n     * @return Source\n     */\n    public function getSource(): Source;\n\n    /**\n     * Returns the token at the Lexer's current position.\n     *\n     * @return Token\n     */\n    public function getToken(): Token;\n\n    /**\n     * Returns the previous focused token for this Lexer.\n     *\n     * @return Token\n     */\n    public function getLastToken(): Token;\n\n    /**\n     * Creates a `SyntaxErrorException` for the current position in the source file.\n     *\n     * @param null|string $description\n     * @return SyntaxErrorException\n     */\n    public function createSyntaxErrorException(?string $description = null): SyntaxErrorException;\n}\n"
  },
  {
    "path": "src/Language/Location.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Util\\ArrayToJsonTrait;\nuse Digia\\GraphQL\\Util\\SerializationInterface;\n\nclass Location implements SerializationInterface\n{\n    use ArrayToJsonTrait;\n\n    /**\n     * @var int\n     */\n    protected $start;\n\n    /**\n     * @var int\n     */\n    protected $end;\n\n    /**\n     * @var Source|null\n     */\n    protected $source;\n\n    /**\n     * Location constructor.\n     *\n     * @param int         $start\n     * @param int         $end\n     * @param Source|null $source\n     */\n    public function __construct(int $start, int $end, ?Source $source = null)\n    {\n        $this->start  = $start;\n        $this->end    = $end;\n        $this->source = $source;\n    }\n\n    /**\n     * @return int\n     */\n    public function getStart(): int\n    {\n        return $this->start;\n    }\n\n    /**\n     * @return int\n     */\n    public function getEnd(): int\n    {\n        return $this->end;\n    }\n\n    /**\n     * @return Source|null\n     */\n    public function getSource(): ?Source\n    {\n        return $this->source;\n    }\n\n    /**\n     * @return array\n     */\n    public function toArray(): array\n    {\n        return [\n            'start' => $this->start,\n            'end'   => $this->end,\n        ];\n    }\n\n    /**\n     * @return string\n     */\n    public function __toString(): string\n    {\n        return $this->toJSON();\n    }\n}\n"
  },
  {
    "path": "src/Language/MultiFileSourceBuilder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\FileNotFoundException;\nuse Digia\\GraphQL\\Error\\InvariantException;\n\n/**\n * Class MultiFileSourceBuilder\n * @package Digia\\GraphQL\\Language\n */\nclass MultiFileSourceBuilder implements SourceBuilderInterface\n{\n\n    /**\n     * @var string[]\n     */\n    private $filePaths;\n\n    /**\n     * MultiFileSourceBuilder constructor.\n     * @param string[] $filePaths\n     */\n    public function __construct(array $filePaths)\n    {\n        $this->filePaths = $filePaths;\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * @throws FileNotFoundException\n     * @throws InvariantException\n     */\n    public function build(): Source\n    {\n        $combinedSource = '';\n\n        foreach ($this->filePaths as $filePath) {\n            if (!\\file_exists($filePath) || !\\is_readable($filePath)) {\n                throw new FileNotFoundException(sprintf('The file %s cannot be found or is not readable', $filePath));\n            }\n\n            $combinedSource .= \\file_get_contents($filePath);\n        }\n\n        return new Source($combinedSource);\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ASTNodeAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface ASTNodeAwareInterface\n{\n    /**\n     * @return bool\n     */\n    public function hasAstNode(): bool;\n\n    /**\n     * @return NodeInterface|null\n     */\n    public function getAstNode(): ?NodeInterface;\n}\n"
  },
  {
    "path": "src/Language/Node/ASTNodeTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait ASTNodeTrait\n{\n    /**\n     * @var ?NodeInterface\n     */\n    protected $astNode;\n\n    /**\n     * @return bool\n     */\n    public function hasAstNode(): bool\n    {\n        return null !== $this->astNode;\n    }\n\n    /**\n     * @return NodeInterface|null\n     */\n    public function getAstNode(): ?NodeInterface\n    {\n        return $this->astNode;\n    }\n\n    /**\n     * @param NodeInterface|null $astNode\n     * @return $this\n     */\n    protected function setAstNode(?NodeInterface $astNode)\n    {\n        $this->astNode = $astNode;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/AbstractNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\Location;\nuse Digia\\GraphQL\\Language\\NodeBuilderInterface;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorBreak;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorInfo;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Util\\ArrayToJsonTrait;\nuse Digia\\GraphQL\\Util\\NodeComparator;\nuse Digia\\GraphQL\\Util\\SerializationInterface;\n\nabstract class AbstractNode implements NodeInterface, SerializationInterface\n{\n    use ArrayToJsonTrait;\n\n    /**\n     * @var string\n     */\n    protected $kind;\n\n    /**\n     * @var Location|null\n     */\n    protected $location;\n\n    /**\n     * @var VisitorInfo|null\n     */\n    protected $visitorInfo;\n\n    /**\n     * @var bool\n     */\n    protected $isEdited = false;\n\n    /**\n     * @var NodeBuilderInterface\n     */\n    private static $nodeBuilder;\n\n    /**\n     * @return array\n     */\n    abstract public function toAST(): array;\n\n    /**\n     * AbstractNode constructor.\n     *\n     * @param string        $kind\n     * @param Location|null $location\n     */\n    public function __construct(string $kind, ?Location $location)\n    {\n        $this->kind     = $kind;\n        $this->location = $location;\n    }\n\n    /**\n     * @return string\n     */\n    public function getKind(): string\n    {\n        return $this->kind;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasLocation(): bool\n    {\n        return null !== $this->location;\n    }\n\n    /**\n     * @return Location|null\n     */\n    public function getLocation(): ?Location\n    {\n        return $this->location;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getLocationAST(): ?array\n    {\n        return null !== $this->location\n            ? $this->location->toArray()\n            : null;\n    }\n\n    /**\n     * @return array\n     */\n    public function toArray(): array\n    {\n        return $this->toAST();\n    }\n\n    /**\n     * @return string\n     */\n    public function __toString(): string\n    {\n        return $this->toJSON();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function acceptVisitor(VisitorInfo $visitorInfo): ?NodeInterface\n    {\n        $this->visitorInfo = $visitorInfo;\n\n        $visitor       = $this->visitorInfo->getVisitor();\n        $VisitorResult = $visitor->enterNode(clone $this);\n        $newNode       = $VisitorResult->getValue();\n\n        // Handle early exit while entering\n        if ($VisitorResult->getAction() === VisitorResult::ACTION_BREAK) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            throw new VisitorBreak();\n        }\n\n        // If the result was null, it means that we should not traverse this branch.\n        if (null === $newNode) {\n            return null;\n        }\n\n        // If the node was edited, we want to return early to avoid visiting its sub-tree completely.\n        if ($newNode->determineIsEdited($this)) {\n            return $newNode;\n        }\n\n        foreach (self::$kindToNodesToVisitMap[$this->kind] as $property) {\n            $nodeOrNodes = $this->{$property};\n\n            if (empty($nodeOrNodes)) {\n                continue;\n            }\n\n            $newNodeOrNodes = $this->visitNodeOrNodes($nodeOrNodes, $property, $newNode);\n\n            if (empty($newNodeOrNodes)) {\n                continue;\n            }\n\n            $setter = 'set' . \\ucfirst($property);\n\n            if (\\method_exists($newNode, $setter)) {\n                $newNode->{$setter}($newNodeOrNodes);\n            }\n        }\n\n        $VisitorResult = $visitor->leaveNode($newNode);\n\n        // Handle early exit while leaving\n        if ($VisitorResult->getAction() === VisitorResult::ACTION_BREAK) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            throw new VisitorBreak();\n        }\n\n        return $VisitorResult->getValue();\n    }\n\n    /**\n     * @return VisitorInfo|null\n     */\n    public function getVisitorInfo(): ?VisitorInfo\n    {\n        return $this->visitorInfo;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function determineIsEdited(NodeInterface $node): bool\n    {\n        return $this->isEdited = $this->isEdited() || !NodeComparator::compare($this, $node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getAncestor(int $depth = 1): ?NodeInterface\n    {\n        return null !== $this->visitorInfo ? $this->visitorInfo->getAncestor($depth) : null;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isEdited(): bool\n    {\n        return $this->isEdited;\n    }\n\n    /**\n     * @param NodeInterface|NodeInterface[] $nodeOrNodes\n     * @param mixed                         $key\n     * @param NodeInterface                 $parent\n     * @return NodeInterface|NodeInterface[]|null\n     */\n    protected function visitNodeOrNodes($nodeOrNodes, $key, NodeInterface $parent)\n    {\n        $this->visitorInfo->addAncestor($parent);\n\n        $newNodeOrNodes = \\is_array($nodeOrNodes)\n            ? $this->visitNodes($nodeOrNodes, $key)\n            : $this->visitNode($nodeOrNodes, $key, $parent);\n\n        $this->visitorInfo->removeAncestor();\n\n        return $newNodeOrNodes;\n    }\n\n    /**\n     * @param NodeInterface[] $nodes\n     * @param string|int      $key\n     * @return NodeInterface[]\n     */\n    protected function visitNodes(array $nodes, $key): array\n    {\n        $this->visitorInfo->addOneToPath($key);\n\n        $index    = 0;\n        $newNodes = [];\n\n        foreach ($nodes as $node) {\n            $newNode = $this->visitNode($node, $index, null);\n\n            if (null !== $newNode) {\n                $newNodes[$index] = $newNode;\n                $index++;\n            }\n        }\n\n        $this->visitorInfo->removeOneFromPath();\n\n        return $newNodes;\n    }\n\n    /**\n     * @param NodeInterface      $node\n     * @param string|int         $key\n     * @param NodeInterface|null $parent\n     * @return NodeInterface|null\n     */\n    protected function visitNode(NodeInterface $node, $key, ?NodeInterface $parent): ?NodeInterface\n    {\n        $this->visitorInfo->addOneToPath($key);\n\n        $info = new VisitorInfo(\n            $this->visitorInfo->getVisitor(),\n            $key,\n            $parent,\n            $this->visitorInfo->getPath(),\n            $this->visitorInfo->getAncestors()\n        );\n\n        $newNode = $node->acceptVisitor($info);\n\n        // If the node was edited, we need to revisit it to produce the expected result.\n        if (null !== $newNode && $newNode->isEdited()) {\n            $newNode = $newNode->acceptVisitor($info);\n        }\n\n        $this->visitorInfo->removeOneFromPath();\n\n        return $newNode;\n    }\n\n    /**\n     * @param NodeInterface $other\n     * @return bool\n     */\n    protected function compareNode(NodeInterface $other)\n    {\n        return $this->toJSON() === $other->toJSON();\n    }\n\n    /**\n     * @return NodeBuilderInterface\n     */\n    protected function getNodeBuilder(): NodeBuilderInterface\n    {\n        if (null === self::$nodeBuilder) {\n            self::$nodeBuilder = GraphQL::make(NodeBuilderInterface::class);\n        }\n\n        return self::$nodeBuilder;\n    }\n\n    /**\n     * @var array\n     */\n    protected static $kindToNodesToVisitMap = [\n        'Name' => [],\n\n        'Document'            => ['definitions'],\n        'OperationDefinition' => [\n            'name',\n            'variableDefinitions',\n            'directives',\n            'selectionSet',\n        ],\n        'VariableDefinition'  => ['variable', 'type', 'defaultValue'],\n        'Variable'            => ['name'],\n        'SelectionSet'        => ['selections'],\n        'Field'               => ['alias', 'name', 'arguments', 'directives', 'selectionSet'],\n        'Argument'            => ['name', 'value'],\n\n        'FragmentSpread'     => ['name', 'directives'],\n        'InlineFragment'     => ['typeCondition', 'directives', 'selectionSet'],\n        'FragmentDefinition' => [\n            'name',\n            'variableDefinitions',\n            'typeCondition',\n            'directives',\n            'selectionSet',\n        ],\n\n        'IntValue'     => [],\n        'FloatValue'   => [],\n        'StringValue'  => [],\n        'BooleanValue' => [],\n        'NullValue'    => [],\n        'EnumValue'    => [],\n        'ListValue'    => ['values'],\n        'ObjectValue'  => ['fields'],\n        'ObjectField'  => ['name', 'value'],\n\n        'Directive' => ['name', 'arguments'],\n\n        'NamedType'   => ['name'],\n        'ListType'    => ['type'],\n        'NonNullType' => ['type'],\n\n        'SchemaDefinition'        => ['directives', 'operationTypes'],\n        'OperationTypeDefinition' => ['type'],\n\n        'ScalarTypeDefinition'      => ['description', 'name', 'directives'],\n        'ObjectTypeDefinition'      => [\n            'description',\n            'name',\n            'interfaces',\n            'directives',\n            'fields',\n        ],\n        'FieldDefinition'           => ['description', 'name', 'arguments', 'type', 'directives'],\n        'InputValueDefinition'      => [\n            'description',\n            'name',\n            'type',\n            'defaultValue',\n            'directives',\n        ],\n        'InterfaceTypeDefinition'   => ['description', 'name', '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\n        'DirectiveDefinition' => ['description', 'name', 'arguments', 'locations'],\n\n        'SchemaExtension' => ['directives', 'operationTypes'],\n\n        'ScalarTypeExtension'      => ['name', 'directives'],\n        'ObjectTypeExtension'      => ['name', 'interfaces', 'directives', 'fields'],\n        'InterfaceTypeExtension'   => ['name', 'directives', 'fields'],\n        'UnionTypeExtension'       => ['name', 'directives', 'types'],\n        'EnumTypeExtension'        => ['name', 'directives', 'values'],\n        'InputObjectTypeExtension' => ['name', 'directives', 'fields'],\n    ];\n}\n"
  },
  {
    "path": "src/Language/Node/AliasTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait AliasTrait\n{\n\n    /**\n     * @var NameNode|null\n     */\n    protected $alias;\n\n    /**\n     * @return null|string\n     */\n    abstract public function getNameValue(): ?string;\n\n    /**\n     * @return NameNode|null\n     */\n    public function getAlias(): ?NameNode\n    {\n        return $this->alias;\n    }\n\n    /**\n     * @return null|string\n     */\n    public function getAliasValue(): ?string\n    {\n        return null !== $this->alias ? $this->alias->getValue() : null;\n    }\n\n    /**\n     * @return null|string\n     */\n    public function getAliasOrNameValue(): ?string\n    {\n        return $this->getAliasValue() ?? $this->getNameValue();\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getAliasAST(): ?array\n    {\n        return null !== $this->alias ? $this->alias->toAST() : null;\n    }\n\n    /**\n     * @param NameNode|null $alias\n     * @return $this\n     */\n    public function setAlias(?NameNode $alias)\n    {\n        $this->alias = $alias;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ArgumentNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ArgumentNode extends AbstractNode implements NameAwareInterface\n{\n    use NameTrait;\n    use ValueLiteralTrait;\n\n    /**\n     * ArgumentNode constructor.\n     *\n     * @param NameNode           $name\n     * @param ValueNodeInterface $value\n     * @param Location|null      $location\n     */\n    public function __construct(NameNode $name, ValueNodeInterface $value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::ARGUMENT, $location);\n\n        $this->name  = $name;\n        $this->value = $value;\n    }\n\n    /**\n     * @return array\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'name'  => $this->getNameAST(),\n            'value' => $this->getValueAST(),\n            'loc'   => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ArgumentsAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface ArgumentsAwareInterface\n{\n    /**\n     * @return bool\n     */\n    public function hasArguments(): bool;\n\n    /**\n     * @return ArgumentNode[]\n     */\n    public function getArguments(): array;\n\n    /**\n     * @return array\n     */\n    public function getArgumentsAST(): array;\n\n    /**\n     * @param ArgumentNode[] $arguments\n     * @return $this\n     */\n    public function setArguments(array $arguments);\n}\n"
  },
  {
    "path": "src/Language/Node/ArgumentsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait ArgumentsTrait\n{\n    /**\n     * @var ArgumentNode[]\n     */\n    protected $arguments = [];\n\n    /**\n     * @return bool\n     */\n    public function hasArguments(): bool\n    {\n        return !empty($this->arguments);\n    }\n\n    /**\n     * @return ArgumentNode[]\n     */\n    public function getArguments(): array\n    {\n        return $this->arguments ?? [];\n    }\n\n    /**\n     * @return array\n     */\n    public function getArgumentsAST(): array\n    {\n        return \\array_map(function (ArgumentNode $node) {\n            return $node->toAST();\n        }, $this->getArguments());\n    }\n\n    /**\n     * @param ArgumentNode[] $arguments\n     * @return $this\n     */\n    public function setArguments(array $arguments)\n    {\n        $this->arguments = $arguments;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/BooleanValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass BooleanValueNode extends AbstractNode implements ValueNodeInterface, ValueAwareInterface\n{\n    use ValueTrait;\n\n    /**\n     * BooleanValueNode constructor.\n     *\n     * @param mixed         $value\n     * @param Location|null $location\n     */\n    public function __construct($value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::BOOLEAN, $location);\n\n        $this->value = $value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'value' => $this->value,\n            'loc'   => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/DefaultValueTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait DefaultValueTrait\n{\n    /**\n     * @var ValueNodeInterface|null\n     */\n    protected $defaultValue;\n\n    /**\n     * @return bool\n     */\n    public function hasDefaultValue(): bool\n    {\n        return null !== $this->defaultValue;\n    }\n\n    /**\n     * @return ValueNodeInterface|null\n     */\n    public function getDefaultValue(): ?ValueNodeInterface\n    {\n        return $this->defaultValue;\n    }\n\n    /**\n     * @return array\n     */\n    public function getDefaultValueAST(): ?array\n    {\n        return null !== $this->defaultValue ? $this->defaultValue->toAST() : null;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/DefinitionNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface DefinitionNodeInterface extends NodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/DescriptionTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait DescriptionTrait\n{\n    /**\n     * @var StringValueNode|null\n     */\n    protected $description;\n\n    /**\n     * @return StringValueNode|null\n     */\n    public function getDescription(): ?StringValueNode\n    {\n        return $this->description;\n    }\n\n    /**\n     * @return null|string\n     */\n    public function getDescriptionValue(): ?string\n    {\n        return null !== $this->description ? $this->description->getValue() : null;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getDescriptionAST(): ?array\n    {\n        return null !== $this->description ? $this->description->toAST() : null;\n    }\n\n    /**\n     * @param StringValueNode|null $description\n     * @return $this\n     */\n    public function setDescription(?StringValueNode $description)\n    {\n        $this->description = $description;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/DirectiveDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass DirectiveDefinitionNode extends AbstractNode implements TypeSystemDefinitionNodeInterface, NameAwareInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use InputArgumentsTrait;\n\n    /**\n     * @var NameNode[]\n     */\n    protected $locations;\n\n    /**\n     * DirectiveDefinitionNode constructor.\n     *\n     * @param StringValueNode|null       $description\n     * @param NameNode                   $name\n     * @param InputValueDefinitionNode[] $arguments\n     * @param NameNode[]                 $locations\n     * @param Location|null              $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $arguments,\n        array $locations,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::DIRECTIVE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->arguments   = $arguments;\n        $this->locations   = $locations;\n    }\n\n    /**\n     * @return NameNode[]\n     */\n    public function getLocations(): array\n    {\n        return $this->locations;\n    }\n\n    /**\n     * @return array\n     */\n    public function getLocationsAST(): array\n    {\n        return \\array_map(function (NameNode $node) {\n            return $node->toAST();\n        }, $this->locations);\n    }\n\n    /**\n     * @param NameNode[] $locations\n     * @return $this\n     */\n    public function setLocations(array $locations)\n    {\n        $this->locations = $locations;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'arguments'   => $this->getArgumentsAST(),\n            'locations'   => $this->getLocationsAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/DirectiveNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass DirectiveNode extends AbstractNode implements ArgumentsAwareInterface, NameAwareInterface\n{\n    use NameTrait;\n    use ArgumentsTrait;\n\n    /**\n     * DirectiveNode constructor.\n     *\n     * @param NameNode       $name\n     * @param ArgumentNode[] $arguments\n     * @param Location|null  $location\n     */\n    public function __construct(NameNode $name, array $arguments, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::DIRECTIVE, $location);\n\n        $this->name      = $name;\n        $this->arguments = $arguments;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'      => $this->kind,\n            'name'      => $this->getNameAST(),\n            'arguments' => $this->getArgumentsAST(),\n            'loc'       => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/DirectivesAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface DirectivesAwareInterface\n{\n    /**\n     * @return bool\n     */\n    public function hasDirectives(): bool;\n\n    /**\n     * @return DirectiveNode[]\n     */\n    public function getDirectives(): array;\n\n    /**\n     * @return array\n     */\n    public function getDirectivesAST(): array;\n\n    /**\n     * @param DirectiveNode[] $directives\n     * @return $this\n     */\n    public function setDirectives(array $directives);\n}\n"
  },
  {
    "path": "src/Language/Node/DirectivesTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait DirectivesTrait\n{\n    /**\n     * @var DirectiveNode[]\n     */\n    protected $directives = [];\n\n    /**\n     * @return bool\n     */\n    public function hasDirectives(): bool\n    {\n        return !empty($this->directives);\n    }\n\n    /**\n     * @return DirectiveNode[]\n     */\n    public function getDirectives(): array\n    {\n        return $this->directives;\n    }\n\n    /**\n     * @return array\n     */\n    public function getDirectivesAST(): array\n    {\n        return \\array_map(function (DirectiveNode $directive) {\n            return $directive->toAST();\n        }, $this->directives);\n    }\n\n    /**\n     * @param array|DirectiveNode[] $directives\n     * @return $this\n     */\n    public function setDirectives(array $directives)\n    {\n        $this->directives = $directives;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/DocumentNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass DocumentNode extends AbstractNode\n{\n    /**\n     * @var DefinitionNodeInterface[]|TypeSystemExtensionNodeInterface[]\n     */\n    protected $definitions;\n\n    /**\n     * DocumentNode constructor.\n     *\n     * @param DefinitionNodeInterface[] $definitions\n     * @param Location|null             $location\n     */\n    public function __construct(array $definitions, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::DOCUMENT, $location);\n\n        $this->definitions = $definitions;\n    }\n\n    /**\n     * @return DefinitionNodeInterface[]|TypeSystemExtensionNodeInterface[]\n     */\n    public function getDefinitions(): array\n    {\n        return $this->definitions;\n    }\n\n    /**\n     * @return array\n     */\n    public function getDefinitionsAST(): array\n    {\n        return \\array_map(function (NodeInterface $node) {\n            return $node->toAST();\n        }, $this->definitions);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'definitions' => $this->getDefinitionsAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n\n    /**\n     * @param DefinitionNodeInterface[] $definitions\n     * @return DocumentNode\n     */\n    protected function setDefinitions(array $definitions): DocumentNode\n    {\n        $this->definitions = $definitions;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/EnumTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass EnumTypeDefinitionNode extends AbstractNode implements\n    TypeSystemDefinitionNodeInterface,\n    DirectivesAwareInterface,\n    NameAwareInterface,\n    NamedTypeNodeInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use DirectivesTrait;\n    use EnumValuesTrait;\n\n    /**\n     * EnumTypeDefinitionNode constructor.\n     *\n     * @param StringValueNode|null      $description\n     * @param NameNode                  $name\n     * @param DirectiveNode[]           $directives\n     * @param EnumValueDefinitionNode[] $values\n     * @param Location|null             $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $directives,\n        array $values,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::ENUM_TYPE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->directives  = $directives;\n        $this->values      = $values;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'values'      => $this->getValuesAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/EnumTypeExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass EnumTypeExtensionNode extends AbstractNode implements\n    TypeSystemExtensionNodeInterface,\n    DirectivesAwareInterface,\n    NameAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n    use EnumValuesTrait;\n\n    /**\n     * EnumTypeExtensionNode constructor.\n     *\n     * @param NameNode                  $name\n     * @param DirectiveNode[]           $directives\n     * @param EnumValueDefinitionNode[] $values\n     * @param Location|null             $location\n     */\n    public function __construct(NameNode $name, array $directives, array $values, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::ENUM_TYPE_EXTENSION, $location);\n\n        $this->name       = $name;\n        $this->directives = $directives;\n        $this->values     = $values;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'name'       => $this->getNameAST(),\n            'directives' => $this->getDirectivesAST(),\n            'values'     => $this->getValuesAST(),\n            'loc'        => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/EnumValueDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass EnumValueDefinitionNode extends AbstractNode implements\n    DefinitionNodeInterface,\n    DirectivesAwareInterface,\n    NameAwareInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use DirectivesTrait;\n\n    /**\n     * EnumValueDefinitionNode constructor.\n     *\n     * @param StringValueNode|null $description\n     * @param NameNode             $name\n     * @param DirectiveNode[]      $directives\n     * @param Location|null        $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $directives,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::ENUM_VALUE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->directives  = $directives;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/EnumValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass EnumValueNode extends AbstractNode implements ValueNodeInterface\n{\n    use ValueTrait;\n\n    /**\n     * EnumValueNode constructor.\n     *\n     * @param mixed         $value\n     * @param Location|null $location\n     */\n    public function __construct($value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::ENUM, $location);\n\n        $this->value = $value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return (string)$this->value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'value' => $this->value,\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/EnumValuesTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait EnumValuesTrait\n{\n    /**\n     * @var EnumValueDefinitionNode[]\n     */\n    protected $values;\n\n    /**\n     * @return bool\n     */\n    public function hasValues(): bool\n    {\n        return !empty($this->values);\n    }\n\n    /**\n     * @return EnumValueDefinitionNode[]\n     */\n    public function getValues(): array\n    {\n        return $this->values;\n    }\n\n    /**\n     * @return array\n     */\n    public function getValuesAST(): array\n    {\n        return \\array_map(function (EnumValueDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->values);\n    }\n\n    /**\n     * @param array|EnumValueDefinitionNode[] $values\n     * @return $this\n     */\n    public function setValues(array $values)\n    {\n        $this->values = $values;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ExecutableDefinitionNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface ExecutableDefinitionNodeInterface extends DefinitionNodeInterface\n{\n    // TODO: Figure out of the `getNameValue` method can be moved to `DefinitionNodeInterface`.\n\n    /**\n     * @return null|string\n     */\n    public function getNameValue(): ?string;\n}\n"
  },
  {
    "path": "src/Language/Node/FieldDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass FieldDefinitionNode extends AbstractNode implements\n    DefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use TypeTrait;\n    use NameTrait;\n    use DescriptionTrait;\n    use InputArgumentsTrait;\n    use DirectivesTrait;\n\n    /**\n     * FieldDefinitionNode constructor.\n     *\n     * @param StringValueNode|null       $description\n     * @param NameNode                   $name\n     * @param InputValueDefinitionNode[] $arguments\n     * @param TypeNodeInterface          $type\n     * @param DirectiveNode[]            $directives\n     * @param Location|null              $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $arguments,\n        TypeNodeInterface $type,\n        array $directives,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::FIELD_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->arguments   = $arguments;\n        $this->type        = $type;\n        $this->directives  = $directives;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->description,\n            'name'        => $this->getNameAST(),\n            'arguments'   => $this->getArgumentsAST(),\n            'type'        => $this->getTypeAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/FieldNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass FieldNode extends AbstractNode implements\n    SelectionNodeInterface,\n    NameAwareInterface,\n    ArgumentsAwareInterface,\n    DirectivesAwareInterface,\n    SelectionSetAwareInterface\n{\n    use NameTrait;\n    use AliasTrait;\n    use ArgumentsTrait;\n    use DirectivesTrait;\n    use SelectionSetTrait;\n\n    /**\n     * FieldNode constructor.\n     *\n     * @param NameNode|null         $alias\n     * @param NameNode              $name\n     * @param ArgumentNode[]        $arguments\n     * @param DirectiveNode[]       $directives\n     * @param SelectionSetNode|null $selectionSet\n     * @param Location|null         $location\n     */\n    public function __construct(\n        ?NameNode $alias,\n        NameNode $name,\n        array $arguments,\n        array $directives,\n        ?SelectionSetNode $selectionSet,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::FIELD, $location);\n\n        $this->alias        = $alias;\n        $this->name         = $name;\n        $this->arguments    = $arguments;\n        $this->directives   = $directives;\n        $this->selectionSet = $selectionSet;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'         => $this->kind,\n            'loc'          => $this->getLocationAST(),\n            'alias'        => $this->getAliasAST(),\n            'name'         => $this->getNameAST(),\n            'arguments'    => $this->getArgumentsAST(),\n            'directives'   => $this->getDirectivesAST(),\n            'selectionSet' => $this->getSelectionSetAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/FieldsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait FieldsTrait\n{\n    /**\n     * @var FieldDefinitionNode[]\n     */\n    protected $fields;\n\n    /**\n     * @return bool\n     */\n    public function hasFields(): bool\n    {\n        return !empty($this->fields);\n    }\n\n    /**\n     * @return FieldDefinitionNode[]\n     */\n    public function getFields(): array\n    {\n        return $this->fields;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFieldsAST(): array\n    {\n        return \\array_map(function (FieldDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->fields);\n    }\n\n    /**\n     * @param array|FieldDefinitionNode[] $fields\n     * @return $this\n     */\n    public function setFields(array $fields)\n    {\n        $this->fields = $fields;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/FloatValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass FloatValueNode extends AbstractNode implements ValueNodeInterface, ValueAwareInterface\n{\n    use ValueTrait;\n\n    /**\n     * FloatValueNode constructor.\n     *\n     * @param mixed         $value\n     * @param Location|null $location\n     */\n    public function __construct($value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::FLOAT, $location);\n\n        $this->value = $value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'loc'   => $this->getLocationAST(),\n            'value' => $this->value,\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/FragmentDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass FragmentDefinitionNode extends AbstractNode implements\n    ExecutableDefinitionNodeInterface,\n    NameAwareInterface,\n    VariableDefinitionsAwareInterface,\n    DirectivesAwareInterface,\n    SelectionSetAwareInterface\n{\n    use NameTrait;\n    use VariableDefinitionsTrait;\n    use TypeConditionTrait;\n    use DirectivesTrait;\n    use SelectionSetTrait;\n\n    /**\n     * FragmentDefinitionNode constructor.\n     *\n     * @param NameNode                 $name\n     * @param VariableDefinitionNode[] $variableDefinitions\n     * @param NamedTypeNode|null       $typeCondition\n     * @param DirectiveNode[]          $directives\n     * @param SelectionSetNode|null    $selectionSet\n     * @param Location|null            $location\n     */\n    public function __construct(\n        NameNode $name,\n        array $variableDefinitions,\n        ?NamedTypeNode $typeCondition,\n        array $directives,\n        ?SelectionSetNode $selectionSet,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::FRAGMENT_DEFINITION, $location);\n\n        $this->name                = $name;\n        $this->variableDefinitions = $variableDefinitions;\n        $this->typeCondition       = $typeCondition;\n        $this->directives          = $directives;\n        $this->selectionSet        = $selectionSet;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'                => $this->kind,\n            'name'                => $this->getNameAST(),\n            'variableDefinitions' => $this->getVariableDefinitionsAST(),\n            'typeCondition'       => $this->getTypeConditionAST(),\n            'directives'          => $this->getDirectivesAST(),\n            'selectionSet'        => $this->getSelectionSetAST(),\n            'loc'                 => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/FragmentNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface FragmentNodeInterface extends NodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/FragmentSpreadNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass FragmentSpreadNode extends AbstractNode implements\n    FragmentNodeInterface,\n    SelectionNodeInterface,\n    NameAwareInterface,\n    SelectionSetAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n    use SelectionSetTrait;\n\n    /**\n     * FragmentSpreadNode constructor.\n     *\n     * @param NameNode              $name\n     * @param DirectiveNode[]       $directives\n     * @param SelectionSetNode|null $selectionSet\n     * @param Location|null         $location\n     */\n    public function __construct(\n        NameNode $name,\n        array $directives,\n        ?SelectionSetNode $selectionSet,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::FRAGMENT_SPREAD, $location);\n\n        $this->name         = $name;\n        $this->directives   = $directives;\n        $this->selectionSet = $selectionSet;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'         => $this->kind,\n            'name'         => $this->getNameAST(),\n            'directives'   => $this->getDirectivesAST(),\n            'selectionSet' => $this->getSelectionSetAST(),\n            'loc'          => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InlineFragmentNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass InlineFragmentNode extends AbstractNode implements\n    FragmentNodeInterface,\n    SelectionNodeInterface,\n    SelectionSetAwareInterface\n{\n    use DirectivesTrait;\n    use TypeConditionTrait;\n    use SelectionSetTrait;\n\n    /**\n     * InlineFragmentNode constructor.\n     *\n     * @param NamedTypeNode|null    $typeCondition\n     * @param DirectiveNode[]       $directives\n     * @param SelectionSetNode|null $selectionSet\n     * @param Location|null         $location\n     */\n    public function __construct(\n        ?NamedTypeNode $typeCondition,\n        array $directives,\n        ?SelectionSetNode $selectionSet,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::INLINE_FRAGMENT, $location);\n\n        $this->typeCondition = $typeCondition;\n        $this->directives    = $directives;\n        $this->selectionSet  = $selectionSet;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'          => $this->kind,\n            'typeCondition' => $this->getTypeConditionAST(),\n            'directives'    => $this->getDirectivesAST(),\n            'selectionSet'  => $this->getSelectionSetAST(),\n            'loc'           => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InputArgumentsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait InputArgumentsTrait\n{\n    /**\n     * @var InputValueDefinitionNode[]\n     */\n    protected $arguments;\n\n    /**\n     * @return bool\n     */\n    public function hasArguments(): bool\n    {\n        return !empty($this->arguments);\n    }\n\n    /**\n     * @return InputValueDefinitionNode[]\n     */\n    public function getArguments(): array\n    {\n        return $this->arguments ?? [];\n    }\n\n    /**\n     * @return array\n     */\n    public function getArgumentsAST(): array\n    {\n        return \\array_map(function (InputValueDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->arguments);\n    }\n\n    /**\n     * @param array|InputValueDefinitionNode[] $arguments\n     * @return $this\n     */\n    public function setArguments(array $arguments)\n    {\n        $this->arguments = $arguments;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InputFieldsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait InputFieldsTrait\n{\n    /**\n     * @var InputValueDefinitionNode[]\n     */\n    protected $fields;\n\n    /**\n     * @return bool\n     */\n    public function hasFields(): bool\n    {\n        return !empty($this->fields);\n    }\n\n    /**\n     * @return InputValueDefinitionNode[]\n     */\n    public function getFields(): array\n    {\n        return $this->fields;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFieldsAST(): array\n    {\n        return \\array_map(function (InputValueDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->fields);\n    }\n\n    /**\n     * @param array|InputValueDefinitionNode[] $fields\n     * @return $this\n     */\n    public function setFields(array $fields)\n    {\n        $this->fields = $fields;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InputObjectTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass InputObjectTypeDefinitionNode extends AbstractNode implements\n    TypeSystemDefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface,\n    NamedTypeNodeInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use DirectivesTrait;\n    use InputFieldsTrait;\n\n    /**\n     * InputObjectTypeDefinitionNode constructor.\n     *\n     * @param StringValueNode|null       $description\n     * @param NameNode                   $name\n     * @param DirectiveNode[]            $directives\n     * @param InputValueDefinitionNode[] $fields\n     * @param Location|null              $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $directives,\n        array $fields,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::INPUT_OBJECT_TYPE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->directives  = $directives;\n        $this->fields      = $fields;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'fields'      => $this->getFieldsAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InputObjectTypeExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass InputObjectTypeExtensionNode extends AbstractNode implements\n    TypeSystemExtensionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n    use InputFieldsTrait;\n\n    /**\n     * InputObjectTypeExtensionNode constructor.\n     *\n     * @param NameNode                   $name\n     * @param DirectiveNode[]            $directives\n     * @param InputValueDefinitionNode[] $fields\n     * @param Location|null              $location\n     */\n    public function __construct(\n        NameNode $name,\n        array $directives,\n        array $fields,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::INPUT_OBJECT_TYPE_EXTENSION, $location);\n\n        $this->name        = $name;\n        $this->directives  = $directives;\n        $this->fields      = $fields;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'name'       => $this->getNameAST(),\n            'directives' => $this->getDirectivesAST(),\n            'fields'     => $this->getFieldsAST(),\n            'loc'        => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InputValueDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass InputValueDefinitionNode extends AbstractNode implements\n    DefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use TypeTrait;\n    use DefaultValueTrait;\n    use DirectivesTrait;\n\n    /**\n     * InputValueDefinitionNode constructor.\n     *\n     * @param StringValueNode|null    $description\n     * @param NameNode                $name\n     * @param TypeNodeInterface       $type\n     * @param ValueNodeInterface|null $defaultValue\n     * @param DirectiveNode[]         $directives\n     * @param Location|null           $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        TypeNodeInterface $type,\n        ?ValueNodeInterface $defaultValue,\n        array $directives,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::INPUT_VALUE_DEFINITION, $location);\n\n        $this->description  = $description;\n        $this->name         = $name;\n        $this->type         = $type;\n        $this->defaultValue = $defaultValue;\n        $this->directives   = $directives;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'         => $this->kind,\n            'description'  => $this->getDescriptionAST(),\n            'name'         => $this->getNameAST(),\n            'type'         => $this->getTypeAST(),\n            'defaultValue' => $this->getDefaultValueAST(),\n            'directives'   => $this->getDirectivesAST(),\n            'loc'          => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/IntValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass IntValueNode extends AbstractNode implements ValueNodeInterface, ValueAwareInterface\n{\n    use ValueTrait;\n\n    /**\n     * FloatValueNode constructor.\n     *\n     * @param mixed         $value\n     * @param Location|null $location\n     */\n    public function __construct($value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::INT, $location);\n\n        $this->value = $value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'loc'   => $this->getLocationAST(),\n            'value' => $this->value,\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InterfaceTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass InterfaceTypeDefinitionNode extends AbstractNode implements\n    TypeSystemDefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface,\n    NamedTypeNodeInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use DirectivesTrait;\n    use FieldsTrait;\n\n    /**\n     * InterfaceTypeDefinitionNode constructor.\n     *\n     * @param StringValueNode|null  $description\n     * @param NameNode              $name\n     * @param DirectiveNode[]       $directives\n     * @param FieldDefinitionNode[] $fields\n     * @param Location|null         $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $directives,\n        array $fields,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::INTERFACE_TYPE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->directives  = $directives;\n        $this->fields      = $fields;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'fields'      => $this->getFieldsAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InterfaceTypeExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass InterfaceTypeExtensionNode extends AbstractNode implements\n    TypeSystemExtensionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n    use FieldsTrait;\n\n    /**\n     * InterfaceTypeExtensionNode constructor.\n     *\n     * @param NameNode              $name\n     * @param DirectiveNode[]       $directives\n     * @param FieldDefinitionNode[] $fields\n     * @param Location|null         $location\n     */\n    public function __construct(NameNode $name, array $directives, array $fields, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::INTERFACE_TYPE_EXTENSION, $location);\n\n        $this->name       = $name;\n        $this->directives = $directives;\n        $this->fields     = $fields;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'name'       => $this->getNameAST(),\n            'directives' => $this->getDirectivesAST(),\n            'fields'     => $this->getFieldsAST(),\n            'loc'        => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/InterfacesTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait InterfacesTrait\n{\n    /**\n     * @var NamedTypeNode[]\n     */\n    protected $interfaces;\n\n    /**\n     * @return bool\n     */\n    public function hasInterfaces(): bool\n    {\n        return !empty($this->interfaces);\n    }\n\n    /**\n     * @return NamedTypeNode[]\n     */\n    public function getInterfaces(): array\n    {\n        return $this->interfaces;\n    }\n\n    /**\n     * @return array\n     */\n    public function getInterfacesAST(): array\n    {\n        return \\array_map(function (NamedTypeNode $node) {\n            return $node->toAST();\n        }, $this->interfaces);\n    }\n\n    /**\n     * @param array|NamedTypeNode[] $interfaces\n     * @return $this\n     */\n    public function setInterfaces(array $interfaces)\n    {\n        $this->interfaces = $interfaces;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ListTypeNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ListTypeNode extends AbstractNode implements TypeNodeInterface\n{\n    use TypeTrait;\n\n    /**\n     * FloatValueNode constructor.\n     *\n     * @param TypeNodeInterface $type\n     * @param Location|null     $location\n     */\n    public function __construct(TypeNodeInterface $type, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::LIST_TYPE, $location);\n\n        $this->type = $type;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind' => $this->kind,\n            'type' => $this->getTypeAST(),\n            'loc'  => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ListValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ListValueNode extends AbstractNode implements ValueNodeInterface\n{\n    /**\n     * @var ValueNodeInterface[]\n     */\n    protected $values;\n\n    /**\n     * ListValueNode constructor.\n     *\n     * @param ValueNodeInterface[] $values\n     * @param Location|null        $location\n     */\n    public function __construct(array $values, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::LIST, $location);\n\n        $this->values = $values;\n    }\n\n    /**\n     * @return array|ValueNodeInterface[]\n     */\n    public function getValues(): array\n    {\n        return $this->values;\n    }\n\n    /**\n     * @return array\n     */\n    public function getValuesAST(): array\n    {\n        return \\array_map(function (ValueNodeInterface $node) {\n            return $node->toAST();\n        }, $this->values);\n    }\n\n    /**\n     * @param array|ValueNodeInterface[] $values\n     * @return $this\n     */\n    public function setValues(array $values)\n    {\n        $this->values = $values;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'   => $this->kind,\n            'loc'    => $this->getLocationAST(),\n            'values' => $this->getValuesAST(),\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return \\json_encode(\\array_map(function (ValueAwareInterface $node) {\n            return $node->getValue();\n        }, $this->getValues()));\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/NameAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface NameAwareInterface\n{\n    /**\n     * @return NameNode|null\n     */\n    public function getName(): ?NameNode;\n\n    /**\n     * @return string|null\n     */\n    public function getNameValue(): ?string;\n\n    /**\n     * @return array|null\n     */\n    public function getNameAST(): ?array;\n\n    /**\n     * @param NameNode|null $name\n     * @return $this\n     */\n    public function setName(?NameNode $name);\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string;\n}\n"
  },
  {
    "path": "src/Language/Node/NameNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass NameNode extends AbstractNode\n{\n    use ValueTrait;\n\n    /**\n     * @var string\n     */\n    protected $kind = NodeKindEnum::NAME;\n\n    /**\n     * NameNode constructor.\n     *\n     * @param mixed         $value\n     * @param Location|null $location\n     */\n    public function __construct($value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::NAME, $location);\n\n        $this->value = $value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'value' => $this->value,\n            'loc'   => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/NameTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait NameTrait\n{\n    /**\n     * @var NameNode|null\n     */\n    protected $name;\n\n    /**\n     * @return NameNode|null\n     */\n    public function getName(): ?NameNode\n    {\n        return $this->name;\n    }\n\n    /**\n     * @return string|null\n     */\n    public function getNameValue(): ?string\n    {\n        return null !== $this->name ? $this->name->getValue() : null;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getNameAST(): ?array\n    {\n        return null !== $this->name ? $this->name->toAST() : null;\n    }\n\n    /**\n     * @param NameNode|null $name\n     * @return $this\n     */\n    public function setName(?NameNode $name)\n    {\n        $this->name = $name;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return $this->getNameValue() ?? '';\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/NamedTypeNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass NamedTypeNode extends AbstractNode implements NamedTypeNodeInterface, NameAwareInterface\n{\n    use NameTrait;\n\n    /**\n     * NamedTypeNode constructor.\n     *\n     * @param NameNode      $name\n     * @param Location|null $location\n     */\n    public function __construct(NameNode $name, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::NAMED_TYPE, $location);\n\n        $this->name = $name;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind' => $this->kind,\n            'name' => $this->getNameAST(),\n            'loc'  => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/NamedTypeNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\n/**\n * Interface for named type nodes.\n */\ninterface NamedTypeNodeInterface extends TypeNodeInterface\n{\n    /**\n     * @return NameNode|null\n     */\n    public function getName(): ?NameNode;\n\n    /**\n     * @return null|string\n     */\n    public function getNameValue(): ?string;\n}\n"
  },
  {
    "path": "src/Language/Node/NodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorBreak;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorInfo;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorInterface;\n\ninterface NodeInterface\n{\n\n    /**\n     * @return string\n     */\n    public function getKind(): string;\n\n    /**\n     * @return bool\n     */\n    public function hasLocation(): bool;\n\n    /**\n     * @return Location|null\n     */\n    public function getLocation(): ?Location;\n\n    /**\n     * @return array\n     */\n    public function toAST(): array;\n\n    /**\n     * @return string\n     */\n    public function toJSON(): string;\n\n    /**\n     * @param VisitorInfo $visitorInfo\n     * @return NodeInterface|null\n     */\n    public function acceptVisitor(VisitorInfo $visitorInfo): ?NodeInterface;\n\n    /**\n     * @return VisitorInfo|null\n     */\n    public function getVisitorInfo(): ?VisitorInfo;\n\n    /**\n     * @param NodeInterface $node\n     * @return bool\n     */\n    public function determineIsEdited(NodeInterface $node): bool;\n\n    /**\n     * @param int $depth\n     * @return NodeInterface|null\n     */\n    public function getAncestor(int $depth = 1): ?NodeInterface;\n\n    /**\n     * @return bool\n     */\n    public function isEdited(): bool;\n}\n"
  },
  {
    "path": "src/Language/Node/NodeKindEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nclass NodeKindEnum\n{\n\n    // Name\n    public const NAME = 'Name';\n\n    // Document\n    public const DOCUMENT             = 'Document';\n    public const OPERATION_DEFINITION = 'OperationDefinition';\n    public const VARIABLE_DEFINITION  = 'VariableDefinition';\n    public const VARIABLE             = 'Variable';\n    public const SELECTION_SET        = 'SelectionSet';\n    public const FIELD                = 'Field';\n    public const ARGUMENT             = 'Argument';\n\n    // Fragments\n    public const FRAGMENT_SPREAD     = 'FragmentSpread';\n    public const INLINE_FRAGMENT     = 'InlineFragment';\n    public const FRAGMENT_DEFINITION = 'FragmentDefinition';\n\n    // Values\n    public const INT          = 'IntValue';\n    public const FLOAT        = 'FloatValue';\n    public const STRING       = 'StringValue';\n    public const BOOLEAN      = 'BooleanValue';\n    public const NULL         = 'NullValue';\n    public const ENUM         = 'EnumValue';\n    public const LIST         = 'ListValue';\n    public const OBJECT       = 'ObjectValue';\n    public const OBJECT_FIELD = 'ObjectField';\n\n    // Directives\n    public const DIRECTIVE = 'Directive';\n\n    // Types\n    public const NAMED_TYPE    = 'NamedType';\n    public const LIST_TYPE     = 'ListType';\n    public const NON_NULL_TYPE = 'NonNullType';\n\n    // Type System Definitions\n    public const SCHEMA_DEFINITION         = 'SchemaDefinition';\n    public const OPERATION_TYPE_DEFINITION = 'OperationTypeDefinition';\n\n    // Type Definitions\n    public const SCALAR_TYPE_DEFINITION       = 'ScalarTypeDefinition';\n    public const OBJECT_TYPE_DEFINITION       = 'ObjectTypeDefinition';\n    public const FIELD_DEFINITION             = 'FieldDefinition';\n    public const INPUT_VALUE_DEFINITION       = 'InputValueDefinition';\n    public const INTERFACE_TYPE_DEFINITION    = 'InterfaceTypeDefinition';\n    public const UNION_TYPE_DEFINITION        = 'UnionTypeDefinition';\n    public const ENUM_TYPE_DEFINITION         = 'EnumTypeDefinition';\n    public const ENUM_VALUE_DEFINITION        = 'EnumValueDefinition';\n    public const INPUT_OBJECT_TYPE_DEFINITION = 'InputObjectTypeDefinition';\n\n    // Directive Definitions\n    public const DIRECTIVE_DEFINITION = 'DirectiveDefinition';\n\n    // Type System Extensions\n    public const SCHEMA_EXTENSION = 'SchemaExtension';\n\n    // Type Extensions\n    public const SCALAR_TYPE_EXTENSION       = 'ScalarTypeExtension';\n    public const OBJECT_TYPE_EXTENSION       = 'ObjectTypeExtension';\n    public const INTERFACE_TYPE_EXTENSION    = 'InterfaceTypeExtension';\n    public const UNION_TYPE_EXTENSION        = 'UnionTypeExtension';\n    public const ENUM_TYPE_EXTENSION         = 'EnumTypeExtension';\n    public const INPUT_OBJECT_TYPE_EXTENSION = 'InputObjectTypeExtension';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/NonNullTypeNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass NonNullTypeNode extends AbstractNode implements TypeNodeInterface\n{\n    use TypeTrait;\n\n    /**\n     * NonNullTypeNode constructor.\n     *\n     * @param TypeNodeInterface $type\n     * @param Location|null     $location\n     */\n    public function __construct(TypeNodeInterface $type, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::NON_NULL_TYPE, $location);\n\n        $this->type = $type;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind' => $this->kind,\n            'type' => $this->getTypeAST(),\n            'loc'  => $this->getLocationAST(),\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return (string)$this->type . '!';\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/NullValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass NullValueNode extends AbstractNode implements ValueNodeInterface\n{\n    /**\n     * NullValueNode constructor.\n     *\n     * @param Location|null $location\n     */\n    public function __construct(?Location $location)\n    {\n        parent::__construct(NodeKindEnum::NULL, $location);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind' => $this->kind,\n            'loc'  => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ObjectFieldNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ObjectFieldNode extends AbstractNode implements NameAwareInterface\n{\n    use NameTrait;\n    use ValueLiteralTrait;\n\n    /**\n     * ObjectFieldNode constructor.\n     *\n     * @param NameNode                $name\n     * @param ValueNodeInterface|null $value\n     * @param Location|null           $location\n     */\n    public function __construct(NameNode $name, ?ValueNodeInterface $value, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::OBJECT_FIELD, $location);\n\n        $this->name  = $name;\n        $this->value = $value;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'name'  => $this->getNameAST(),\n            'value' => $this->getValueAST(),\n            'loc'   => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ObjectTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ObjectTypeDefinitionNode extends AbstractNode implements\n    TypeSystemDefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface,\n    NamedTypeNodeInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use InterfacesTrait;\n    use DirectivesTrait;\n    use FieldsTrait;\n\n    /**\n     * ObjectTypeDefinitionNode constructor.\n     *\n     * @param StringValueNode|null  $description\n     * @param NameNode              $name\n     * @param NamedTypeNode[]       $interfaces\n     * @param DirectiveNode[]       $directives\n     * @param FieldDefinitionNode[] $fields\n     * @param Location|null         $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $interfaces,\n        array $directives,\n        array $fields,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::OBJECT_TYPE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->interfaces  = $interfaces;\n        $this->directives  = $directives;\n        $this->fields      = $fields;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'interfaces'  => $this->getInterfacesAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'fields'      => $this->getFieldsAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ObjectTypeExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ObjectTypeExtensionNode extends AbstractNode implements\n    TypeSystemExtensionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use NameTrait;\n    use InterfacesTrait;\n    use DirectivesTrait;\n    use FieldsTrait;\n\n    /**\n     * ObjectTypeExtensionNode constructor.\n     *\n     * @param NameNode              $name\n     * @param NamedTypeNode[]       $interfaces\n     * @param DirectiveNode[]       $directives\n     * @param FieldDefinitionNode[] $fields\n     * @param Location|null         $location\n     */\n    public function __construct(\n        NameNode $name,\n        array $interfaces,\n        array $directives,\n        array $fields,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::OBJECT_TYPE_EXTENSION, $location);\n\n        $this->name        = $name;\n        $this->interfaces  = $interfaces;\n        $this->directives  = $directives;\n        $this->fields      = $fields;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'name'       => $this->getNameAST(),\n            'interfaces' => $this->getInterfacesAST(),\n            'directives' => $this->getDirectivesAST(),\n            'fields'     => $this->getFieldsAST(),\n            'loc'        => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ObjectValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ObjectValueNode extends AbstractNode implements ValueNodeInterface\n{\n    /**\n     * @var ObjectFieldNode[]\n     */\n    protected $fields;\n\n    /**\n     * ObjectValueNode constructor.\n     *\n     * @param ObjectFieldNode[] $fields\n     * @param Location|null     $location\n     */\n    public function __construct(array $fields, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::OBJECT, $location);\n\n        $this->fields = $fields;\n    }\n\n    /**\n     * @return ObjectFieldNode[]\n     */\n    public function getFields(): array\n    {\n        return $this->fields;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFieldsAST(): array\n    {\n        return \\array_map(function (ObjectFieldNode $node) {\n            return $node->toAST();\n        }, $this->fields);\n    }\n\n    /**\n     * @param array $fields\n     * @return $this\n     */\n    public function setFields(array $fields)\n    {\n        $this->fields = $fields;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'   => $this->kind,\n            'fields' => $this->getFieldsAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/OperationDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass OperationDefinitionNode extends AbstractNode implements\n    ExecutableDefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface,\n    VariableDefinitionsAwareInterface,\n    SelectionSetAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n    use VariableDefinitionsTrait;\n    use SelectionSetTrait;\n\n    /**\n     * @var string\n     */\n    protected $operation;\n\n    /**\n     * OperationDefinitionNode constructor.\n     *\n     * @param string                   $operation\n     * @param NameNode|null            $name\n     * @param VariableDefinitionNode[] $variableDefinitions\n     * @param DirectiveNode[]          $directives\n     * @param SelectionSetNode|null    $selectionSet\n     * @param Location|null            $location\n     */\n    public function __construct(\n        string $operation,\n        ?NameNode $name,\n        array $variableDefinitions,\n        array $directives,\n        ?SelectionSetNode $selectionSet,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::OPERATION_DEFINITION, $location);\n\n        $this->operation           = $operation;\n        $this->name                = $name;\n        $this->variableDefinitions = $variableDefinitions;\n        $this->directives          = $directives;\n        $this->selectionSet        = $selectionSet;\n    }\n\n    /**\n     * @return string\n     */\n    public function getOperation(): string\n    {\n        return $this->operation;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'                => $this->kind,\n            'loc'                 => $this->getLocationAST(),\n            'operation'           => $this->operation,\n            'name'                => $this->getNameAST(),\n            'variableDefinitions' => $this->getVariableDefinitionsAST(),\n            'directives'          => $this->getDirectivesAST(),\n            'selectionSet'        => $this->getSelectionSetAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/OperationTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass OperationTypeDefinitionNode extends AbstractNode implements DefinitionNodeInterface\n{\n    use TypeTrait;\n\n    /**\n     * @var string\n     */\n    protected $operation;\n\n    /**\n     * OperationTypeDefinitionNode constructor.\n     *\n     * @param string            $operation\n     * @param TypeNodeInterface $type\n     * @param Location|null     $location\n     */\n    public function __construct(string $operation, TypeNodeInterface $type, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::OPERATION_TYPE_DEFINITION, $location);\n\n        $this->operation = $operation;\n        $this->type      = $type;\n    }\n\n    /**\n     * @return string\n     */\n    public function getOperation(): string\n    {\n        return $this->operation;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'      => $this->kind,\n            'operation' => $this->operation,\n            'type'      => $this->getTypeAST(),\n            'loc'       => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ScalarTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ScalarTypeDefinitionNode extends AbstractNode implements\n    TypeSystemDefinitionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface,\n    NamedTypeNodeInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use DirectivesTrait;\n\n    /**\n     * ScalarTypeDefinitionNode constructor.\n     *\n     * @param StringValueNode|null $description\n     * @param NameNode             $name\n     * @param DirectiveNode[]      $directives\n     * @param Location|null        $location\n     */\n    public function __construct(?StringValueNode $description, NameNode $name, array $directives, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::SCALAR_TYPE_DEFINITION, $location);\n\n        $this->directives  = $directives;\n        $this->description = $description;\n        $this->name        = $name;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ScalarTypeExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass ScalarTypeExtensionNode extends AbstractNode implements\n    TypeSystemExtensionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n\n    /**\n     * ScalarTypeDefinitionNode constructor.\n     *\n     * @param NameNode        $name\n     * @param DirectiveNode[] $directives\n     * @param Location|null   $location\n     */\n    public function __construct(NameNode $name, array $directives, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::SCALAR_TYPE_EXTENSION, $location);\n\n        $this->name       = $name;\n        $this->directives = $directives;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'name'       => $this->getNameAST(),\n            'directives' => $this->getDirectivesAST(),\n            'loc'        => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/SchemaDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass SchemaDefinitionNode extends AbstractNode implements TypeSystemDefinitionNodeInterface, DirectivesAwareInterface\n{\n    use DirectivesTrait;\n\n    /**\n     * @var OperationTypeDefinitionNode[]\n     */\n    protected $operationTypes;\n\n    /**\n     * SchemaDefinitionNode constructor.\n     *\n     * @param DirectiveNode[]               $directives\n     * @param OperationTypeDefinitionNode[] $operationTypes\n     * @param Location|null                 $location\n     */\n    public function __construct(array $directives, array $operationTypes, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::SCHEMA_DEFINITION, $location);\n\n        $this->directives     = $directives;\n        $this->operationTypes = $operationTypes;\n    }\n\n    /**\n     * @return OperationTypeDefinitionNode[]\n     */\n    public function getOperationTypes(): array\n    {\n        return $this->operationTypes;\n    }\n\n    /**\n     * @return array\n     */\n    public function getOperationTypesAST(): array\n    {\n        return \\array_map(function (OperationTypeDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->operationTypes);\n    }\n\n    /**\n     * @param OperationTypeDefinitionNode[] $operationTypes\n     * @return $this\n     */\n    public function setOperationTypes(array $operationTypes)\n    {\n        $this->operationTypes = $operationTypes;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'           => $this->kind,\n            'directives'     => $this->getDirectivesAST(),\n            'operationTypes' => $this->getOperationTypesAST(),\n            'loc'            => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/SchemaExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass SchemaExtensionNode extends AbstractNode implements TypeSystemExtensionNodeInterface, DirectivesAwareInterface\n{\n    use DirectivesTrait;\n\n    /**\n     * @var OperationTypeDefinitionNode[]\n     */\n    protected $operationTypes;\n\n    /**\n     * SchemaExtensionNode constructor.\n     * @param DirectiveNode[]               $directives\n     * @param OperationTypeDefinitionNode[] $operationTypes\n     * @param Location|null                 $location\n     */\n    public function __construct(array $directives, array $operationTypes, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::SCHEMA_EXTENSION, $location);\n\n        $this->directives     = $directives;\n        $this->operationTypes = $operationTypes;\n    }\n\n    /**\n     * @return OperationTypeDefinitionNode[]\n     */\n    public function getOperationTypes(): array\n    {\n        return $this->operationTypes;\n    }\n\n    /**\n     * @return array\n     */\n    public function getOperationTypesAST(): array\n    {\n        return \\array_map(function (OperationTypeDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->operationTypes);\n    }\n\n    /**\n     * @param OperationTypeDefinitionNode[] $operationTypes\n     * @return $this\n     */\n    public function setOperationTypes(array $operationTypes)\n    {\n        $this->operationTypes = $operationTypes;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'           => $this->kind,\n            'directives'     => $this->getDirectivesAST(),\n            'operationTypes' => $this->getOperationTypesAST(),\n            'loc'            => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/SelectionNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface SelectionNodeInterface extends NodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/SelectionSetAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface SelectionSetAwareInterface\n{\n    /**\n     * @return bool\n     */\n    public function hasSelectionSet(): bool;\n\n    /**\n     * @return SelectionSetNode|null\n     */\n    public function getSelectionSet(): ?SelectionSetNode;\n}\n"
  },
  {
    "path": "src/Language/Node/SelectionSetNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass SelectionSetNode extends AbstractNode\n{\n    /**\n     * @var SelectionNodeInterface[]\n     */\n    protected $selections = [];\n\n    /**\n     * SelectionSetNode constructor.\n     *\n     * @param SelectionNodeInterface[] $selections\n     * @param Location|null            $location\n     */\n    public function __construct(array $selections, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::SELECTION_SET, $location);\n\n        $this->selections = $selections;\n    }\n\n    /**\n     * @return SelectionNodeInterface[]\n     */\n    public function getSelections(): array\n    {\n        return $this->selections;\n    }\n\n    /**\n     * @return array\n     */\n    public function getSelectionsAST(): array\n    {\n        return \\array_map(function (SelectionNodeInterface $node) {\n            return $node->toAST();\n        }, $this->selections);\n    }\n\n    /**\n     * @param SelectionNodeInterface[] $selections\n     * @return SelectionSetNode\n     */\n    public function setSelections(array $selections): SelectionSetNode\n    {\n        $this->selections = $selections;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'loc'        => $this->getLocationAST(),\n            'selections' => $this->getSelectionsAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/SelectionSetTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait SelectionSetTrait\n{\n\n    /**\n     * @var SelectionSetNode|null\n     */\n    protected $selectionSet;\n\n    /**\n     * @return bool\n     */\n    public function hasSelectionSet(): bool\n    {\n        return null !== $this->selectionSet;\n    }\n\n    /**\n     * @return SelectionSetNode|null\n     */\n    public function getSelectionSet(): ?SelectionSetNode\n    {\n        return $this->selectionSet;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getSelectionSetAST(): ?array\n    {\n        return null !== $this->selectionSet ? $this->selectionSet->toArray() : null;\n    }\n\n    /**\n     * @param SelectionSetNode|null $selectionSet\n     * @return $this\n     */\n    public function setSelectionSet(?SelectionSetNode $selectionSet)\n    {\n        $this->selectionSet = $selectionSet;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/StringValueNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass StringValueNode extends AbstractNode implements ValueNodeInterface, ValueAwareInterface\n{\n    use ValueTrait;\n\n    /**\n     * @var bool\n     */\n    protected $block;\n\n    /**\n     * StringValueNode constructor.\n     *\n     * @param mixed         $value\n     * @param bool          $block\n     * @param Location|null $location\n     */\n    public function __construct($value, bool $block, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::STRING, $location);\n\n        $this->value = $value;\n        $this->block = $block;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isBlock(): bool\n    {\n        return $this->block;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'  => $this->kind,\n            'loc'   => $this->getLocationAST(),\n            'block' => $this->block,\n            'value' => $this->value,\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/TypeConditionTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait TypeConditionTrait\n{\n    /**\n     * @var NamedTypeNode|null\n     */\n    protected $typeCondition;\n\n    /**\n     * @return NamedTypeNode|null\n     */\n    public function getTypeCondition(): ?NamedTypeNode\n    {\n        return $this->typeCondition;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getTypeConditionAST(): ?array\n    {\n        return null !== $this->typeCondition ? $this->typeCondition->toAST() : null;\n    }\n\n    /**\n     * @param NamedTypeNode|null $typeCondition\n     * @return $this\n     */\n    public function setTypeCondition(?NamedTypeNode $typeCondition)\n    {\n        $this->typeCondition = $typeCondition;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/TypeNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\n/**\n * Tagging interface for Type nodes.\n */\ninterface TypeNodeInterface extends NodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/TypeSystemDefinitionNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\n/**\n * Tagging interface for Type System Definition nodes.\n */\ninterface TypeSystemDefinitionNodeInterface extends DefinitionNodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/TypeSystemExtensionNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface TypeSystemExtensionNodeInterface extends NodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/TypeTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait TypeTrait\n{\n    /**\n     * @var TypeNodeInterface\n     */\n    protected $type;\n\n    /**\n     * @return TypeNodeInterface\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * @return array\n     */\n    public function getTypeAST(): array\n    {\n        return $this->type->toAST();\n    }\n\n    /**\n     * @param TypeNodeInterface $type\n     * @return $this\n     */\n    public function setType($type)\n    {\n        $this->type = $type;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/TypesTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait TypesTrait\n{\n    /**\n     * @var NamedTypeNode[]\n     */\n    protected $types;\n\n    /**\n     * @return bool\n     */\n    public function hasTypes(): bool\n    {\n        return !empty($this->types);\n    }\n\n    /**\n     * @return NamedTypeNode[]\n     */\n    public function getTypes(): array\n    {\n        return $this->types;\n    }\n\n    /**\n     * @return array\n     */\n    public function getTypesAST(): array\n    {\n        return \\array_map(function (NamedTypeNode $node) {\n            return $node->toAST();\n        }, $this->types);\n    }\n\n    /**\n     * @param array|NamedTypeNode[] $types\n     * @return $this\n     */\n    public function setTypes(array $types)\n    {\n        $this->types = $types;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/UnionTypeDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass UnionTypeDefinitionNode extends AbstractNode implements\n    TypeSystemDefinitionNodeInterface,\n    NameAwareInterface,\n    NamedTypeNodeInterface\n{\n    use DescriptionTrait;\n    use NameTrait;\n    use DirectivesTrait;\n    use TypesTrait;\n\n    /**\n     * UnionTypeDefinitionNode constructor.\n     *\n     * @param StringValueNode|null $description\n     * @param NameNode             $name\n     * @param DirectiveNode[]      $directives\n     * @param NamedTypeNode[]      $types\n     * @param Location|null        $location\n     */\n    public function __construct(\n        ?StringValueNode $description,\n        NameNode $name,\n        array $directives,\n        array $types,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::UNION_TYPE_DEFINITION, $location);\n\n        $this->description = $description;\n        $this->name        = $name;\n        $this->directives  = $directives;\n        $this->types       = $types;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'        => $this->kind,\n            'description' => $this->getDescriptionAST(),\n            'name'        => $this->getNameAST(),\n            'directives'  => $this->getDirectivesAST(),\n            'types'       => $this->getTypesAST(),\n            'loc'         => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/UnionTypeExtensionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass UnionTypeExtensionNode extends AbstractNode implements\n    TypeSystemExtensionNodeInterface,\n    NameAwareInterface,\n    DirectivesAwareInterface\n{\n    use NameTrait;\n    use DirectivesTrait;\n    use TypesTrait;\n\n    /**\n     * UnionTypeExtensionNode constructor.\n     *\n     * @param NameNode        $name\n     * @param DirectiveNode[] $directives\n     * @param NamedTypeNode[] $types\n     * @param Location|null   $location\n     */\n    public function __construct(NameNode $name, array $directives, array $types, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::UNION_TYPE_EXTENSION, $location);\n\n        $this->name       = $name;\n        $this->directives = $directives;\n        $this->types      = $types;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'       => $this->kind,\n            'name'       => $this->getNameAST(),\n            'directives' => $this->getDirectivesAST(),\n            'types'      => $this->getTypesAST(),\n            'loc'        => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ValueAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface ValueAwareInterface\n{\n    /**\n     * @return mixed|null\n     */\n    public function getValue();\n}\n"
  },
  {
    "path": "src/Language/Node/ValueLiteralTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait ValueLiteralTrait\n{\n    /**\n     * @var ValueNodeInterface|null\n     */\n    protected $value;\n\n    /**\n     * @return ValueNodeInterface|null\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getValueAST(): ?array\n    {\n        return null !== $this->value ? $this->value->toAST() : null;\n    }\n\n    /**\n     * @param ValueNodeInterface|null $value\n     * @return $this\n     */\n    public function setValue($value)\n    {\n        $this->value = $value;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/ValueNodeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface ValueNodeInterface extends NodeInterface\n{\n}\n"
  },
  {
    "path": "src/Language/Node/ValueTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait ValueTrait\n{\n    /**\n     * @var mixed|null\n     */\n    protected $value;\n\n    /**\n     * @return mixed|null\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * @param mixed|null $value\n     * @return $this\n     */\n    public function setValue($value)\n    {\n        $this->value = $value;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/VariableDefinitionNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass VariableDefinitionNode extends AbstractNode implements DefinitionNodeInterface\n{\n    use DefaultValueTrait;\n    use TypeTrait;\n\n    /**\n     * @var VariableNode\n     */\n    protected $variable;\n\n    /**\n     * VariableDefinitionNode constructor.\n     *\n     * @param VariableNode            $variable\n     * @param TypeNodeInterface       $type\n     * @param ValueNodeInterface|null $defaultValue\n     * @param Location|null           $location\n     */\n    public function __construct(\n        VariableNode $variable,\n        TypeNodeInterface $type,\n        ?ValueNodeInterface $defaultValue,\n        ?Location $location\n    ) {\n        parent::__construct(NodeKindEnum::VARIABLE_DEFINITION, $location);\n\n        $this->variable     = $variable;\n        $this->type         = $type;\n        $this->defaultValue = $defaultValue;\n    }\n\n    /**\n     * @return VariableNode\n     */\n    public function getVariable(): VariableNode\n    {\n        return $this->variable;\n    }\n\n    /**\n     * @return array\n     */\n    public function getVariableAST(): array\n    {\n        return $this->variable->toAST();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return (string)$this->type;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind'     => $this->kind,\n            'variable' => $this->getVariableAST(),\n            'type'     => $this->getTypeAST(),\n            'loc'      => $this->getLocationAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/VariableDefinitionsAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ninterface VariableDefinitionsAwareInterface\n{\n    /**\n     * @return VariableDefinitionNode[]\n     */\n    public function getVariableDefinitions(): array;\n}\n"
  },
  {
    "path": "src/Language/Node/VariableDefinitionsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\ntrait VariableDefinitionsTrait\n{\n    /**\n     * @var VariableDefinitionNode[]\n     */\n    protected $variableDefinitions = [];\n\n    /**\n     * @return VariableDefinitionNode[]\n     */\n    public function getVariableDefinitions(): array\n    {\n        return $this->variableDefinitions;\n    }\n\n    /**\n     * @return array\n     */\n    public function getVariableDefinitionsAST(): array\n    {\n        return \\array_map(function (VariableDefinitionNode $node) {\n            return $node->toAST();\n        }, $this->variableDefinitions);\n    }\n\n    /**\n     * @param VariableDefinitionNode[] $variableDefinitions\n     * @return $this\n     */\n    protected function setVariableDefinitions(array $variableDefinitions)\n    {\n        $this->variableDefinitions = $variableDefinitions;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/Node/VariableNode.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Node;\n\nuse Digia\\GraphQL\\Language\\Location;\n\nclass VariableNode extends AbstractNode implements ValueNodeInterface, NameAwareInterface\n{\n    use NameTrait;\n\n    /**\n     * VariableNode constructor.\n     *\n     * @param NameNode      $name\n     * @param Location|null $location\n     */\n    public function __construct(NameNode $name, ?Location $location)\n    {\n        parent::__construct(NodeKindEnum::VARIABLE, $location);\n\n        $this->name = $name;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toAST(): array\n    {\n        return [\n            'kind' => $this->kind,\n            'name' => $this->getNameAST(),\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/NodeBuilder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Language\\Node\\NonNullTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\n\nclass NodeBuilder implements NodeBuilderInterface\n{\n    /**\n     * @param array $ast\n     * @return NodeInterface\n     * @throws LanguageException\n     */\n    public function build(array $ast): NodeInterface\n    {\n        if (!isset($ast['kind'])) {\n            /** @noinspection ExceptionsAnnotatingAndHandlingInspection */\n            throw new LanguageException(\\sprintf('Nodes must specify a kind, got %s', \\json_encode($ast)));\n        }\n\n        ['kind' => $kind] = $ast;\n\n        switch ($kind) {\n            case NodeKindEnum::ARGUMENT:\n                return $this->buildArgument($ast);\n            case NodeKindEnum::BOOLEAN:\n                return $this->buildBoolean($ast);\n            case NodeKindEnum::DIRECTIVE_DEFINITION:\n                return $this->buildDirectiveDefinition($ast);\n            case NodeKindEnum::DIRECTIVE:\n                return $this->buildDirective($ast);\n            case NodeKindEnum::DOCUMENT:\n                return $this->buildDocument($ast);\n            case NodeKindEnum::ENUM:\n                return $this->buildEnum($ast);\n            case NodeKindEnum::ENUM_TYPE_DEFINITION:\n                return $this->buildEnumTypeDefinition($ast);\n            case NodeKindEnum::ENUM_TYPE_EXTENSION:\n                return $this->buildEnumTypeExtension($ast);\n            case NodeKindEnum::ENUM_VALUE_DEFINITION:\n                return $this->buildEnumValueDefinition($ast);\n            case NodeKindEnum::FIELD:\n                return $this->buildField($ast);\n            case NodeKindEnum::FIELD_DEFINITION:\n                return $this->buildFieldDefinition($ast);\n            case NodeKindEnum::FLOAT:\n                return $this->buildFloat($ast);\n            case NodeKindEnum::FRAGMENT_DEFINITION:\n                return $this->buildFragmentDefinition($ast);\n            case NodeKindEnum::FRAGMENT_SPREAD:\n                return $this->buildFragmentSpread($ast);\n            case NodeKindEnum::INLINE_FRAGMENT:\n                return $this->buildInlineFragment($ast);\n            case NodeKindEnum::INPUT_OBJECT_TYPE_DEFINITION:\n                return $this->buildInputObjectTypeDefinition($ast);\n            case NodeKindEnum::INPUT_OBJECT_TYPE_EXTENSION:\n                return $this->buildInputObjectTypeExtension($ast);\n            case NodeKindEnum::INPUT_VALUE_DEFINITION:\n                return $this->buildInputValueDefinition($ast);\n            case NodeKindEnum::INTERFACE_TYPE_DEFINITION:\n                return $this->buildInterfaceTypeDefinition($ast);\n            case NodeKindEnum::INTERFACE_TYPE_EXTENSION:\n                return $this->buildInterfaceTypeExtension($ast);\n            case NodeKindEnum::INT:\n                return $this->buildInt($ast);\n            case NodeKindEnum::LIST_TYPE:\n                return $this->buildListType($ast);\n            case NodeKindEnum::LIST:\n                return $this->buildList($ast);\n            case NodeKindEnum::NAMED_TYPE:\n                return $this->buildNamedType($ast);\n            case NodeKindEnum::NAME:\n                return $this->buildName($ast);\n            case NodeKindEnum::NON_NULL_TYPE:\n                return $this->buildNonNullType($ast);\n            case NodeKindEnum::NULL:\n                return $this->buildNull($ast);\n            case NodeKindEnum::OBJECT_FIELD:\n                return $this->buildObjectField($ast);\n            case NodeKindEnum::OBJECT_TYPE_DEFINITION:\n                return $this->buildObjectTypeDefinition($ast);\n            case NodeKindEnum::OBJECT_TYPE_EXTENSION:\n                return $this->buildObjectTypeExtension($ast);\n            case NodeKindEnum::OBJECT:\n                return $this->buildObject($ast);\n            case NodeKindEnum::OPERATION_DEFINITION:\n                return $this->buildOperationDefinition($ast);\n            case NodeKindEnum::OPERATION_TYPE_DEFINITION:\n                return $this->buildOperationTypeDefinition($ast);\n            case NodeKindEnum::SCALAR_TYPE_DEFINITION:\n                return $this->buildScalarTypeDefinition($ast);\n            case NodeKindEnum::SCALAR_TYPE_EXTENSION:\n                return $this->buildScalarTypeExtension($ast);\n            case NodeKindEnum::SCHEMA_DEFINITION:\n                return $this->buildSchemaDefinition($ast);\n            case NodeKindEnum::SCHEMA_EXTENSION:\n                return $this->buildSchemaExtension($ast);\n            case NodeKindEnum::SELECTION_SET:\n                return $this->buildSelectionSet($ast);\n            case NodeKindEnum::STRING:\n                return $this->buildString($ast);\n            case NodeKindEnum::UNION_TYPE_DEFINITION:\n                return $this->buildUnionTypeDefinition($ast);\n            case NodeKindEnum::UNION_TYPE_EXTENSION:\n                return $this->buildUnionTypeExtension($ast);\n            case NodeKindEnum::VARIABLE_DEFINITION:\n                return $this->buildVariableDefinition($ast);\n            case NodeKindEnum::VARIABLE:\n                return $this->buildVariable($ast);\n        }\n\n        /** @noinspection ExceptionsAnnotatingAndHandlingInspection */\n        throw new LanguageException(\\sprintf('Node of kind \"%s\" not supported.', $kind));\n    }\n\n    /**\n     * @param array $ast\n     * @return ArgumentNode\n     * @throws LanguageException\n     */\n    protected function buildArgument(array $ast): ArgumentNode\n    {\n        return new ArgumentNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNode($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return BooleanValueNode\n     */\n    protected function buildBoolean(array $ast): BooleanValueNode\n    {\n        return new BooleanValueNode(\n            $this->getValue($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return DirectiveDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildDirectiveDefinition(array $ast): DirectiveDefinitionNode\n    {\n        return new DirectiveDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'arguments'),\n            $this->buildNodes($ast, 'locations'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return DirectiveNode\n     * @throws LanguageException\n     */\n    protected function buildDirective(array $ast): DirectiveNode\n    {\n        return new DirectiveNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'arguments'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return DocumentNode\n     * @throws LanguageException\n     */\n    protected function buildDocument(array $ast): DocumentNode\n    {\n        return new DocumentNode(\n            $this->buildNodes($ast, 'definitions'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return EnumValueNode\n     */\n    protected function buildEnum(array $ast): EnumValueNode\n    {\n        return new EnumValueNode(\n            $this->getValue($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return EnumTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildEnumTypeDefinition(array $ast): EnumTypeDefinitionNode\n    {\n        return new EnumTypeDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'values'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return EnumTypeExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildEnumTypeExtension(array $ast): EnumTypeExtensionNode\n    {\n        return new EnumTypeExtensionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'values'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return EnumValueDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildEnumValueDefinition(array $ast): EnumValueDefinitionNode\n    {\n        return new EnumValueDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return FieldDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildFieldDefinition(array $ast): FieldDefinitionNode\n    {\n        return new FieldDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'arguments'),\n            $this->buildNode($ast, 'type'),\n            $this->buildNodes($ast, 'directives'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return FieldNode\n     * @throws LanguageException\n     */\n    protected function buildField(array $ast): FieldNode\n    {\n        return new FieldNode(\n            $this->buildNode($ast, 'alias'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'arguments'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNode($ast, 'selectionSet'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return FloatValueNode\n     */\n    protected function buildFloat(array $ast): FloatValueNode\n    {\n        return new FloatValueNode(\n            $this->getValue($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return FragmentDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildFragmentDefinition(array $ast): FragmentDefinitionNode\n    {\n        return new FragmentDefinitionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'variableDefinitions'),\n            $this->buildNode($ast, 'typeCondition'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNode($ast, 'selectionSet'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return FragmentSpreadNode\n     * @throws LanguageException\n     */\n    protected function buildFragmentSpread(array $ast): FragmentSpreadNode\n    {\n        return new FragmentSpreadNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNode($ast, 'selectionSet'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return InlineFragmentNode\n     * @throws LanguageException\n     */\n    protected function buildInlineFragment(array $ast): InlineFragmentNode\n    {\n        return new InlineFragmentNode(\n            $this->buildNode($ast, 'typeCondition'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNode($ast, 'selectionSet'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return InputObjectTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildInputObjectTypeDefinition(array $ast): InputObjectTypeDefinitionNode\n    {\n        return new InputObjectTypeDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return InputObjectTypeExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildInputObjectTypeExtension(array $ast): InputObjectTypeExtensionNode\n    {\n        return new InputObjectTypeExtensionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return InputValueDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildInputValueDefinition(array $ast): InputValueDefinitionNode\n    {\n        return new InputValueDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNode($ast, 'type'),\n            $this->buildNode($ast, 'defaultValue'),\n            $this->buildNodes($ast, 'directives'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return InterfaceTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildInterfaceTypeDefinition(array $ast): InterfaceTypeDefinitionNode\n    {\n        return new InterfaceTypeDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return InterfaceTypeExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildInterfaceTypeExtension(array $ast): InterfaceTypeExtensionNode\n    {\n        return new InterfaceTypeExtensionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return IntValueNode\n     */\n    protected function buildInt(array $ast): IntValueNode\n    {\n        return new IntValueNode(\n            $this->getValue($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ListTypeNode\n     * @throws LanguageException\n     */\n    protected function buildListType(array $ast): ListTypeNode\n    {\n        return new ListTypeNode(\n            $this->buildNode($ast, 'type'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ListValueNode\n     * @throws LanguageException\n     */\n    protected function buildList(array $ast): ListValueNode\n    {\n        return new ListValueNode(\n            $this->buildNodes($ast, 'values'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return NamedTypeNode\n     * @throws LanguageException\n     */\n    protected function buildNamedType(array $ast): NamedTypeNode\n    {\n        return new NamedTypeNode(\n            $this->buildNode($ast, 'name'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return NameNode\n     */\n    protected function buildName(array $ast): NameNode\n    {\n        return new NameNode(\n            $this->getValue($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return NonNullTypeNode\n     * @throws LanguageException\n     */\n    protected function buildNonNullType(array $ast): NonNullTypeNode\n    {\n        return new NonNullTypeNode(\n            $this->buildNode($ast, 'type'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return NullValueNode\n     */\n    protected function buildNull(array $ast): NullValueNode\n    {\n        return new NullValueNode($this->createLocation($ast));\n    }\n\n    /**\n     * @param array $ast\n     * @return ObjectFieldNode\n     * @throws LanguageException\n     */\n    protected function buildObjectField(array $ast): ObjectFieldNode\n    {\n        return new ObjectFieldNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNode($ast, 'value'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ObjectTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildObjectTypeDefinition(array $ast): ObjectTypeDefinitionNode\n    {\n        return new ObjectTypeDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'interfaces'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ObjectTypeExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildObjectTypeExtension(array $ast): ObjectTypeExtensionNode\n    {\n        return new ObjectTypeExtensionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'interfaces'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ObjectValueNode\n     * @throws LanguageException\n     */\n    protected function buildObject(array $ast): ObjectValueNode\n    {\n        return new ObjectValueNode(\n            $this->buildNodes($ast, 'fields'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return OperationDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildOperationDefinition(array $ast): OperationDefinitionNode\n    {\n        return new OperationDefinitionNode(\n            $this->getValue($ast, 'operation'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'variableDefinitions'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNode($ast, 'selectionSet'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return OperationTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildOperationTypeDefinition(array $ast): OperationTypeDefinitionNode\n    {\n        return new OperationTypeDefinitionNode(\n            $this->getValue($ast, 'operation'),\n            $this->buildNode($ast, 'type'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ScalarTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildScalarTypeDefinition(array $ast): ScalarTypeDefinitionNode\n    {\n        return new ScalarTypeDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return ScalarTypeExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildScalarTypeExtension(array $ast): ScalarTypeExtensionNode\n    {\n        return new ScalarTypeExtensionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return SchemaDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildSchemaDefinition(array $ast): SchemaDefinitionNode\n    {\n        return new SchemaDefinitionNode(\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'operationTypes'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return SchemaExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildSchemaExtension(array $ast): SchemaExtensionNode\n    {\n        return new SchemaExtensionNode(\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'operationTypes'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return SelectionSetNode\n     * @throws LanguageException\n     */\n    protected function buildSelectionSet(array $ast): SelectionSetNode\n    {\n        return new SelectionSetNode(\n            $this->buildNodes($ast, 'selections'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return StringValueNode\n     */\n    protected function buildString(array $ast): StringValueNode\n    {\n        return new StringValueNode(\n            $this->getValue($ast, 'value'),\n            $this->getValue($ast, 'block', false),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return UnionTypeDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildUnionTypeDefinition(array $ast): UnionTypeDefinitionNode\n    {\n        return new UnionTypeDefinitionNode(\n            $this->buildNode($ast, 'description'),\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'types'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return UnionTypeExtensionNode\n     * @throws LanguageException\n     */\n    protected function buildUnionTypeExtension(array $ast): UnionTypeExtensionNode\n    {\n        return new UnionTypeExtensionNode(\n            $this->buildNode($ast, 'name'),\n            $this->buildNodes($ast, 'directives'),\n            $this->buildNodes($ast, 'types'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return VariableDefinitionNode\n     * @throws LanguageException\n     */\n    protected function buildVariableDefinition(array $ast): VariableDefinitionNode\n    {\n        return new VariableDefinitionNode(\n            $this->buildNode($ast, 'variable'),\n            $this->buildNode($ast, 'type'),\n            $this->buildNode($ast, 'defaultValue'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * @param array $ast\n     * @return VariableNode\n     * @throws LanguageException\n     */\n    protected function buildVariable(array $ast): VariableNode\n    {\n        return new VariableNode(\n            $this->buildNode($ast, 'name'),\n            $this->createLocation($ast)\n        );\n    }\n\n    /**\n     * Creates a location object.\n     *\n     * @param array $ast\n     * @return Location|null\n     */\n    protected function createLocation(array $ast): ?Location\n    {\n        return isset($ast['loc']['start'], $ast['loc']['end'])\n            ? new Location($ast['loc']['start'], $ast['loc']['end'], $ast['loc']['source'] ?? null)\n            : null;\n    }\n\n    /**\n     * Returns the value of a single property in the given AST.\n     *\n     * @param array  $ast\n     * @param string $propertyName\n     * @param mixed  $defaultValue\n     * @return mixed|null\n     */\n    protected function getValue(array $ast, string $propertyName, $defaultValue = null)\n    {\n        return $ast[$propertyName] ?? $defaultValue;\n    }\n\n    /**\n     * Builds a single item from the given AST.\n     *\n     * @param array  $ast\n     * @param string $propertyName\n     * @return NodeInterface|null\n     * @throws LanguageException\n     */\n    protected function buildNode(array $ast, string $propertyName): ?NodeInterface\n    {\n        return isset($ast[$propertyName]) ? $this->build($ast[$propertyName]) : null;\n    }\n\n    /**\n     * Builds many items from the given AST.\n     *\n     * @param array  $ast\n     * @param string $propertyName\n     * @return NodeInterface[]\n     * @throws LanguageException\n     */\n    protected function buildNodes(array $ast, string $propertyName): array\n    {\n        $array = [];\n\n        if (isset($ast[$propertyName]) && \\is_array($ast[$propertyName])) {\n            foreach ($ast[$propertyName] as $subAst) {\n                $array[] = $this->build($subAst);\n            }\n        }\n\n        return $array;\n    }\n}\n"
  },
  {
    "path": "src/Language/NodeBuilderInterface.php",
    "content": "<?php\n\n// TODO: Move this file under the Node namespace\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\ninterface NodeBuilderInterface\n{\n    /**\n     * @param array $ast\n     * @return NodeInterface\n     */\n    public function build(array $ast): NodeInterface;\n}\n"
  },
  {
    "path": "src/Language/NodePrinter.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NonNullTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass NodePrinter implements NodePrinterInterface\n{\n    /**\n     * @inheritdoc\n     * @throws PrintException\n     */\n    public function print(NodeInterface $node): string\n    {\n        $printMethod = 'print' . $node->getKind();\n\n        if (\\method_exists($this, $printMethod)) {\n            return $this->{$printMethod}($node);\n        }\n\n        throw new PrintException(\\sprintf('Invalid AST Node: %s.', toString($node)));\n    }\n\n    /**\n     * @param NameNode $node\n     * @return null|string\n     */\n    protected function printName(NameNode $node): ?string\n    {\n        return $node->getValue();\n    }\n\n    /**\n     * @param VariableNode $node\n     * @return string\n     */\n    protected function printVariable(VariableNode $node): string\n    {\n        return '$' . $node->getName();\n    }\n\n    // Document\n\n    /**\n     * @param DocumentNode $node\n     * @return string\n     */\n    protected function printDocument(DocumentNode $node): string\n    {\n        return \\implode(\"\\n\\n\", $node->getDefinitions()) . \"\\n\";\n    }\n\n    /**\n     * @param OperationDefinitionNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printOperationDefinition(OperationDefinitionNode $node): string\n    {\n        $operation            = $node->getOperation();\n        $name                 = $this->printOne($node->getName());\n        $variablesDefinitions = $this->printMany($node->getVariableDefinitions());\n        $directives           = $this->printMany($node->getDirectives());\n        $selectionSet         = $this->printOne($node->getSelectionSet());\n\n        // Anonymous queries with no directives or variable definitions can use\n        // the query short form.\n        return empty($name) && empty($directives) && empty($variablesDefinitions) && $operation === 'query'\n            ? $selectionSet\n            : \\implode(' ', [\n                $operation,\n                $name . wrap('(', \\implode(', ', $variablesDefinitions), ')'),\n                \\implode(' ', $directives),\n                $selectionSet,\n            ]);\n    }\n\n    /**\n     * @param VariableDefinitionNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printVariableDefinition(VariableDefinitionNode $node): string\n    {\n        $variable     = $this->printOne($node->getVariable());\n        $type         = $this->printOne($node->getType());\n        $defaultValue = $this->printOne($node->getDefaultValue());\n\n        return $variable . ': ' . $type . wrap(' = ', $defaultValue);\n    }\n\n    /**\n     * @param SelectionSetNode $node\n     * @return string\n     */\n    protected function printSelectionSet(SelectionSetNode $node): string\n    {\n        return block($this->printMany($node->getSelections()));\n    }\n\n    /**\n     * @param FieldNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printField(FieldNode $node): string\n    {\n        $alias        = $this->printOne($node->getAlias());\n        $name         = $this->printOne($node->getName());\n        $arguments    = $this->printMany($node->getArguments());\n        $directives   = $this->printMany($node->getDirectives());\n        $selectionSet = $this->printOne($node->getSelectionSet());\n\n        return \\implode(' ', [\n            wrap('', $alias, ': ') . $name . wrap('(', \\implode(', ', $arguments), ')'),\n            \\implode(' ', $directives),\n            $selectionSet,\n        ]);\n    }\n\n    /**\n     * @param ArgumentNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printArgument(ArgumentNode $node): string\n    {\n        $name  = $this->printOne($node->getName());\n        $value = $this->printOne($node->getValue());\n\n        return $name . ': ' . $value;\n    }\n\n    // Fragments\n\n    /**\n     * @param FragmentSpreadNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printFragmentSpread(FragmentSpreadNode $node): string\n    {\n        $name       = $this->printOne($node->getName());\n        $directives = $this->printMany($node->getDirectives());\n\n        return '...' . $name . wrap(' ', \\implode(' ', $directives));\n    }\n\n    /**\n     * @param InlineFragmentNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printInlineFragment(InlineFragmentNode $node): string\n    {\n        $typeCondition = $this->printOne($node->getTypeCondition());\n        $directives    = $this->printMany($node->getDirectives());\n        $selectionSet  = $this->printOne($node->getSelectionSet());\n\n        return \\implode(' ', [\n            '...', wrap('on ', $typeCondition),\n            \\implode(' ', $directives),\n            $selectionSet\n        ]);\n    }\n\n    /**\n     * @param FragmentDefinitionNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printFragmentDefinition(FragmentDefinitionNode $node): string\n    {\n        $name                = $this->printOne($node->getName());\n        $typeCondition       = $this->printOne($node->getTypeCondition());\n        $variableDefinitions = $this->printMany($node->getVariableDefinitions());\n        $directives          = $this->printMany($node->getDirectives());\n        $selectionSet        = $this->printOne($node->getSelectionSet());\n\n        // Note: fragment variable definitions are experimental and may be changed\n        // or removed in the future.\n        return \\implode(' ', [\n            'fragment ' . $name . wrap('(', \\implode(', ', $variableDefinitions), ')'),\n            'on ' . $typeCondition . ' ' . \\implode(' ', $directives),\n            $selectionSet\n        ]);\n    }\n\n    // Value\n\n    /**\n     * @param IntValueNode $node\n     * @return string\n     */\n    protected function printIntValue(IntValueNode $node): string\n    {\n        return (string)$node->getValue();\n    }\n\n    /**\n     * @param FloatValueNode $node\n     * @return string\n     */\n    protected function printFloatValue(FloatValueNode $node): string\n    {\n        return (string)$node->getValue();\n    }\n\n    /**\n     * @param StringValueNode $node\n     * @return string\n     */\n    protected function printStringValue(StringValueNode $node): string\n    {\n        $value = $node->getValue();\n\n        return $node->isBlock()\n            ? printBlockString($value, false)\n            : \\json_encode($value, JSON_UNESCAPED_UNICODE);\n    }\n\n    /**\n     * @param BooleanValueNode $node\n     * @return string\n     */\n    protected function printBooleanValue(BooleanValueNode $node): string\n    {\n        return $node->getValue() ? 'true' : 'false';\n    }\n\n    /**\n     * @param NullValueNode $node\n     * @return string\n     */\n    protected function printNullValue(NullValueNode $node): string\n    {\n        return 'null';\n    }\n\n    /**\n     * @param EnumValueNode $node\n     * @return string\n     */\n    protected function printEnumValue(EnumValueNode $node): string\n    {\n        return (string)$node->getValue();\n    }\n\n    /**\n     * @param ListValueNode $node\n     * @return string\n     */\n    protected function printListValue(ListValueNode $node): string\n    {\n        $values = $this->printMany($node->getValues());\n        return wrap('[', \\implode(', ', $values), ']');\n    }\n\n    /**\n     * @param ObjectValueNode $node\n     * @return string\n     */\n    protected function printObjectValue(ObjectValueNode $node): string\n    {\n        $fields = $this->printMany($node->getFields());\n        return wrap('{', \\implode(', ', $fields), '}');\n    }\n\n    /**\n     * @param ObjectFieldNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printObjectField(ObjectFieldNode $node): string\n    {\n        $name  = $this->printOne($node->getName());\n        $value = $this->printOne($node->getValue());\n\n        return $name . ': ' . $value;\n    }\n\n    // Directive\n\n    /**\n     * @param DirectiveNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printDirective(DirectiveNode $node): string\n    {\n        $name      = $this->printOne($node->getName());\n        $arguments = $this->printMany($node->getArguments());\n\n        return '@' . $name . wrap('(', \\implode(', ', $arguments), ')');\n    }\n\n    // Type\n\n    /**\n     * @param NamedTypeNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printNamedType(NamedTypeNode $node): string\n    {\n        return $this->printOne($node->getName());\n    }\n\n    /**\n     * @param ListTypeNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printListType(ListTypeNode $node): string\n    {\n        return wrap('[', $this->printOne($node->getType()), ']');\n    }\n\n    /**\n     * @param NonNullTypeNode $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printNonNullType(NonNullTypeNode $node): string\n    {\n        return $this->printOne($node->getType()) . '!';\n    }\n\n    /**\n     * @param NodeInterface|null $node\n     * @return string\n     * @throws PrintException\n     */\n    protected function printOne(?NodeInterface $node): string\n    {\n        return null !== $node ? $this->print($node) : '';\n    }\n\n    /**\n     * @param array $nodes\n     * @return array\n     */\n    protected function printMany(array $nodes): array\n    {\n        return \\array_map(function ($node) {\n            return $this->print($node);\n        }, $nodes);\n    }\n}\n"
  },
  {
    "path": "src/Language/NodePrinterInterface.php",
    "content": "<?php\n\n// TODO: Move this file under the Node namespace\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\ninterface NodePrinterInterface\n{\n    /**\n     * @param NodeInterface $node\n     * @return string\n     */\n    public function print(NodeInterface $node): string;\n}\n"
  },
  {
    "path": "src/Language/Parser.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ExecutableDefinitionNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NonNullTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\TypeSystemDefinitionNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\TypeSystemExtensionNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ValueNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse function Digia\\GraphQL\\Util\\arraySome;\n\n/** @noinspection PhpHierarchyChecksInspection */\n\n/**\n * Class Parser\n * @package Digia\\GraphQL\\Language\n */\nclass Parser implements ParserInterface\n{\n    /**\n     * @var LexerInterface\n     */\n    protected $lexer;\n\n    /**\n     * @param string $name\n     * @param array  $arguments\n     * @return mixed\n     *\n     * @throws InvariantException\n     * @throws SyntaxErrorException\n     */\n    public function __call(string $name, array $arguments)\n    {\n        $lexCallback = \\str_replace('parse', 'lex', $name);\n\n        if (\\method_exists($this, $lexCallback)) {\n            return $this->parsePartial([$this, $lexCallback], $arguments[0], $arguments[1] ?? []);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Given a GraphQL source, parses it into a Document.\n     * Throws GraphQLError if a syntax error is encountered.\n     *\n     * @inheritdoc\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     * @throws InvariantException\n     */\n    public function parse(Source $source, array $options = []): DocumentNode\n    {\n        $this->lexer = $this->createLexer($source, $options);\n\n        return $this->lexDocument();\n    }\n\n    /**\n     * @param callable $lexCallback\n     * @param Source   $source\n     * @param array    $options\n     * @return NodeInterface\n     * @throws SyntaxErrorException\n     */\n    protected function parsePartial(callable $lexCallback, Source $source, array $options = []): NodeInterface\n    {\n        $this->lexer = $this->createLexer($source, $options);\n\n        $this->expect(TokenKindEnum::SOF);\n        $node = $lexCallback();\n        $this->expect(TokenKindEnum::EOF);\n\n        return $node;\n    }\n\n    /**\n     * Converts a name lex token into a name parse node.\n     *\n     * @return NameNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexName(): NameNode\n    {\n        $token = $this->expect(TokenKindEnum::NAME);\n\n        return new NameNode($token->getValue(), $this->createLocation($token));\n    }\n\n    // Implements the parsing rules in the Document section.\n\n    /**\n     * Document : Definition+\n     *\n     * @return DocumentNode\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     */\n    protected function lexDocument(): DocumentNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expect(TokenKindEnum::SOF);\n\n        $definitions = [];\n\n        do {\n            $definitions[] = $this->lexDefinition();\n        } while (!$this->skip(TokenKindEnum::EOF));\n\n        return new DocumentNode($definitions, $this->createLocation($start));\n    }\n\n    /**\n     * Definition :\n     *   - ExecutableDefinition\n     *   - TypeSystemDefinition\n     *\n     * @return NodeInterface\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     */\n    protected function lexDefinition(): NodeInterface\n    {\n        if ($this->peek(TokenKindEnum::NAME)) {\n            $token = $this->lexer->getToken();\n\n            switch ($token->getValue()) {\n                case KeywordEnum::QUERY:\n                case KeywordEnum::MUTATION:\n                case KeywordEnum::SUBSCRIPTION:\n                case KeywordEnum::FRAGMENT:\n                    return $this->lexExecutableDefinition();\n                case KeywordEnum::SCHEMA:\n                case KeywordEnum::SCALAR:\n                case KeywordEnum::TYPE:\n                case KeywordEnum::INTERFACE:\n                case KeywordEnum::UNION:\n                case KeywordEnum::ENUM:\n                case KeywordEnum::INPUT:\n                case KeywordEnum::DIRECTIVE:\n                    return $this->lexTypeSystemDefinition();\n                case KeywordEnum::EXTEND:\n                    return $this->lexTypeSystemExtension();\n\n            }\n        } elseif ($this->peek(TokenKindEnum::BRACE_L)) {\n            return $this->lexExecutableDefinition();\n        } elseif ($this->peekDescription()) {\n            return $this->lexTypeSystemDefinition();\n        }\n\n        throw $this->unexpected();\n    }\n\n    /**\n     * ExecutableDefinition :\n     *   - OperationDefinition\n     *   - FragmentDefinition\n     *\n     * @return ExecutableDefinitionNodeInterface\n     * @throws SyntaxErrorException\n     */\n    protected function lexExecutableDefinition(): ExecutableDefinitionNodeInterface\n    {\n        if ($this->peek(TokenKindEnum::NAME)) {\n            // Valid names are: query, mutation, subscription and fragment\n            $token = $this->lexer->getToken();\n\n            switch ($token->getValue()) {\n                case KeywordEnum::QUERY:\n                case KeywordEnum::MUTATION:\n                case KeywordEnum::SUBSCRIPTION:\n                    return $this->lexOperationDefinition();\n                case KeywordEnum::FRAGMENT:\n                    return $this->lexFragmentDefinition();\n            }\n        } elseif ($this->peek(TokenKindEnum::BRACE_L)) {\n            // Anonymous query\n            return $this->lexOperationDefinition();\n        }\n\n        throw $this->unexpected();\n    }\n\n    // Implements the parsing rules in the Operations section.\n\n    /**\n     * OperationDefinition :\n     *  - SelectionSet\n     *  - OperationType Name? VariableDefinitions? Directives? SelectionSet\n     *\n     * @return OperationDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexOperationDefinition(): OperationDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        if ($this->peek(TokenKindEnum::BRACE_L)) {\n            // Anonymous query\n            return new OperationDefinitionNode(\n                KeywordEnum::QUERY,\n                null,\n                [],\n                [],\n                $this->lexSelectionSet(),\n                $this->createLocation($start)\n            );\n        }\n\n        $operation = $this->lexOperationType();\n\n        if ($this->peek(TokenKindEnum::NAME)) {\n            $name = $this->lexName();\n        }\n\n        return new OperationDefinitionNode(\n            $operation,\n            $name ?? null,\n            $this->lexVariableDefinitions(),\n            $this->lexDirectives(),\n            $this->lexSelectionSet(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * OperationType : one of query mutation subscription\n     *\n     * @return null|string\n     * @throws SyntaxErrorException\n     */\n    protected function lexOperationType(): ?string\n    {\n        $token = $this->expect(TokenKindEnum::NAME);\n        $value = $token->getValue();\n\n        if (isOperation($value)) {\n            return $value;\n        }\n\n        throw $this->unexpected($token);\n    }\n\n    /**\n     * VariableDefinitions : ( VariableDefinition+ )\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexVariableDefinitions(): array\n    {\n        return $this->peek(TokenKindEnum::PAREN_L)\n            ? $this->many(\n                TokenKindEnum::PAREN_L,\n                [$this, 'lexVariableDefinition'],\n                TokenKindEnum::PAREN_R\n            )\n            : [];\n    }\n\n    /**\n     * VariableDefinition : Variable : Type DefaultValue?\n     *\n     * @return VariableDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexVariableDefinition(): VariableDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        /**\n         * @return TypeNodeInterface\n         */\n        $parseType = function (): TypeNodeInterface {\n            $this->expect(TokenKindEnum::COLON);\n            return $this->lexType();\n        };\n\n        return new VariableDefinitionNode(\n            $this->lexVariable(),\n            $parseType(),\n            $this->skip(TokenKindEnum::EQUALS)\n                ? $this->lexValue(true)\n                : null,\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * Variable : $ Name\n     *\n     * @return VariableNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexVariable(): VariableNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expect(TokenKindEnum::DOLLAR);\n\n        return new VariableNode($this->lexName(), $this->createLocation($start));\n    }\n\n    /**\n     * SelectionSet : { Selection+ }\n     *\n     * @return SelectionSetNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexSelectionSet(): SelectionSetNode\n    {\n        $start = $this->lexer->getToken();\n\n        return new SelectionSetNode(\n            $this->many(\n                TokenKindEnum::BRACE_L,\n                [$this, 'lexSelection'],\n                TokenKindEnum::BRACE_R\n            ),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * Selection :\n     *   - Field\n     *   - FragmentSpread\n     *   - InlineFragment\n     *\n     * @return NodeInterface|FragmentNodeInterface|FieldNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexSelection(): NodeInterface\n    {\n        return $this->peek(TokenKindEnum::SPREAD)\n            ? $this->lexFragment()\n            : $this->lexField();\n    }\n\n    /**\n     * Field : Alias? Name Arguments? Directives? SelectionSet?\n     *\n     * Alias : Name :\n     *\n     * @return FieldNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexField(): FieldNode\n    {\n        $start = $this->lexer->getToken();\n\n        $nameOrAlias = $this->lexName();\n\n        if ($this->skip(TokenKindEnum::COLON)) {\n            $alias = $nameOrAlias;\n            $name  = $this->lexName();\n        } else {\n            $name = $nameOrAlias;\n        }\n\n        return new FieldNode(\n            $alias ?? null,\n            $name,\n            $this->lexArguments(false),\n            $this->lexDirectives(),\n            $this->peek(TokenKindEnum::BRACE_L)\n                ? $this->lexSelectionSet()\n                : null,\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * Arguments[Const] : ( Argument[?Const]+ )\n     *\n     * @param bool $isConst\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexArguments(bool $isConst = false): ?array\n    {\n        /**\n         * @return ArgumentNode\n         */\n        $parseFunction = function () use ($isConst): ArgumentNode {\n            return $this->lexArgument($isConst);\n        };\n\n        return $this->peek(TokenKindEnum::PAREN_L)\n            ? $this->many(\n                TokenKindEnum::PAREN_L,\n                $parseFunction,\n                TokenKindEnum::PAREN_R\n            )\n            : [];\n    }\n\n    /**\n     * Argument[Const] : Name : Value[?Const]\n     *\n     * @param bool $isConst\n     * @return ArgumentNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexArgument(bool $isConst = false): ArgumentNode\n    {\n        $start = $this->lexer->getToken();\n\n        /**\n         * @return NodeInterface|TypeNodeInterface|ValueNodeInterface\n         */\n        $parseValue = function () use ($isConst): NodeInterface {\n            $this->expect(TokenKindEnum::COLON);\n            return $this->lexValue($isConst);\n        };\n\n        return new ArgumentNode(\n            $this->lexName(),\n            $parseValue(),\n            $this->createLocation($start)\n        );\n    }\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     * @return FragmentNodeInterface\n     * @throws SyntaxErrorException\n     */\n    protected function lexFragment(): FragmentNodeInterface\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expect(TokenKindEnum::SPREAD);\n\n        $token = $this->lexer->getToken();\n\n        if (KeywordEnum::ON !== $token->getValue() && $this->peek(TokenKindEnum::NAME)) {\n            return new FragmentSpreadNode(\n                $this->lexFragmentName($token),\n                $this->lexDirectives(),\n                null,\n                $this->createLocation($start)\n            );\n        }\n\n        if (KeywordEnum::ON === $token->getValue()) {\n            $this->lexer->advance();\n            $typeCondition = $this->lexNamedType();\n        }\n\n        return new InlineFragmentNode(\n            $typeCondition ?? null,\n            $this->lexDirectives(),\n            $this->lexSelectionSet(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * FragmentDefinition :\n     *   - fragment FragmentName on TypeCondition Directives? SelectionSet\n     *\n     * TypeCondition : NamedType\n     *\n     * @return FragmentDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexFragmentDefinition(): FragmentDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::FRAGMENT);\n\n        $parseTypeCondition = function () {\n            $this->expectKeyword(KeywordEnum::ON);\n            return $this->lexNamedType();\n        };\n\n        return new FragmentDefinitionNode(\n            $this->lexFragmentName(),\n            $this->lexVariableDefinitions(),\n            $parseTypeCondition(),\n            $this->lexDirectives(),\n            $this->lexSelectionSet(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * FragmentName : Name but not `on`\n     *\n     * @param Token|null $token\n     * @return NameNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexFragmentName(?Token $token = null): NameNode\n    {\n        if (null === $token) {\n            $token = $this->lexer->getToken();\n        }\n\n        if (KeywordEnum::ON === $token->getValue()) {\n            throw $this->unexpected();\n        }\n\n        return $this->lexName();\n    }\n\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     * @param bool $isConst\n     * @return NodeInterface|ValueNodeInterface|TypeNodeInterface\n     * @throws SyntaxErrorException\n     */\n    protected function lexValue(bool $isConst = false): NodeInterface\n    {\n        $token = $this->lexer->getToken();\n        $value = $token->getValue();\n\n        switch ($token->getKind()) {\n            case TokenKindEnum::BRACKET_L:\n                return $this->lexList($isConst);\n            case TokenKindEnum::BRACE_L:\n                return $this->lexObject($isConst);\n            case TokenKindEnum::INT:\n                $this->lexer->advance();\n                return new IntValueNode($value, $this->createLocation($token));\n            case TokenKindEnum::FLOAT:\n                $this->lexer->advance();\n                return new FloatValueNode($value, $this->createLocation($token));\n            case TokenKindEnum::STRING:\n            case TokenKindEnum::BLOCK_STRING:\n                return $this->lexStringLiteral();\n            case TokenKindEnum::NAME:\n                if ($value === 'true' || $value === 'false') {\n                    $this->lexer->advance();\n                    return new BooleanValueNode($value === 'true', $this->createLocation($token));\n                }\n\n                if ($value === 'null') {\n                    $this->lexer->advance();\n                    return new NullValueNode($this->createLocation($token));\n                }\n\n                $this->lexer->advance();\n                return new EnumValueNode($value, $this->createLocation($token));\n            case TokenKindEnum::DOLLAR:\n                if (!$isConst) {\n                    return $this->lexVariable();\n                }\n                break;\n        }\n\n        throw $this->unexpected();\n    }\n\n    /**\n     * @return StringValueNode\n     */\n    protected function lexStringLiteral(): StringValueNode\n    {\n        $token = $this->lexer->getToken();\n\n        $this->lexer->advance();\n\n        return new StringValueNode(\n            $token->getValue(),\n            TokenKindEnum::BLOCK_STRING === $token->getKind(),\n            $this->createLocation($token)\n        );\n    }\n\n    /**\n     * ListValue[Const] :\n     *   - [ ]\n     *   - [ Value[?Const]+ ]\n     *\n     * @param bool $isConst\n     * @return ListValueNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexList(bool $isConst): ListValueNode\n    {\n        $start = $this->lexer->getToken();\n\n        $parseFunction = function () use ($isConst) {\n            return $this->lexValue($isConst);\n        };\n\n        return new ListValueNode(\n            $this->any(\n                TokenKindEnum::BRACKET_L,\n                $parseFunction,\n                TokenKindEnum::BRACKET_R\n            ),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * ObjectValue[Const] :\n     *   - { }\n     *   - { ObjectField[?Const]+ }\n     *\n     * @param bool $isConst\n     * @return ObjectValueNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexObject(bool $isConst): ObjectValueNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expect(TokenKindEnum::BRACE_L);\n\n        $fields = [];\n\n        while (!$this->skip(TokenKindEnum::BRACE_R)) {\n            $fields[] = $this->lexObjectField($isConst);\n        }\n\n        return new ObjectValueNode($fields, $this->createLocation($start));\n    }\n\n    /**\n     * ObjectField[Const] : Name : Value[?Const]\n     *\n     * @param bool $isConst\n     * @return ObjectFieldNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexObjectField(bool $isConst): ObjectFieldNode\n    {\n        $start = $this->lexer->getToken();\n\n        /**\n         * @param bool $isConst\n         * @return NodeInterface|TypeNodeInterface|ValueNodeInterface\n         */\n        $parseValue = function (bool $isConst): NodeInterface {\n            $this->expect(TokenKindEnum::COLON);\n            return $this->lexValue($isConst);\n        };\n\n        return new ObjectFieldNode(\n            $this->lexName(),\n            $parseValue($isConst),\n            $this->createLocation($start)\n        );\n    }\n\n    // Implements the parsing rules in the Directives section.\n\n    /**\n     * Directives[Const] : Directive[?Const]+\n     *\n     * @param bool $isConst\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexDirectives(bool $isConst = false): array\n    {\n        $directives = [];\n\n        while ($this->peek(TokenKindEnum::AT)) {\n            $directives[] = $this->lexDirective($isConst);\n        }\n\n        return $directives;\n    }\n\n    /**\n     * Directive[Const] : @ Name Arguments[?Const]?\n     *\n     * @param bool $isConst\n     * @return DirectiveNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexDirective(bool $isConst = false): DirectiveNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expect(TokenKindEnum::AT);\n\n        return new DirectiveNode(\n            $this->lexName(),\n            $this->lexArguments($isConst),\n            $this->createLocation($start)\n        );\n    }\n\n    // Implements the parsing rules in the Types section.\n\n    /**\n     * Type :\n     *   - NamedType\n     *   - ListType\n     *   - NonNullType\n     *\n     * @return TypeNodeInterface\n     * @throws SyntaxErrorException\n     */\n    protected function lexType(): TypeNodeInterface\n    {\n        $start = $this->lexer->getToken();\n\n        if ($this->skip(TokenKindEnum::BRACKET_L)) {\n            $type = $this->lexType();\n\n            $this->expect(TokenKindEnum::BRACKET_R);\n\n            $type = new ListTypeNode($type, $this->createLocation($start));\n        } else {\n            $type = $this->lexNamedType();\n        }\n\n        if ($this->skip(TokenKindEnum::BANG)) {\n            return new NonNullTypeNode($type, $this->createLocation($start));\n        }\n\n        return $type;\n    }\n\n    /**\n     * NamedType : Name\n     *\n     * @return NamedTypeNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexNamedType(): NamedTypeNode\n    {\n        $start = $this->lexer->getToken();\n\n        return new NamedTypeNode($this->lexName(), $this->createLocation($start));\n    }\n\n    // Implements the parsing rules in the Type Definition section.\n\n    /**\n     * TypeSystemDefinition :\n     *   - SchemaDefinition\n     *   - TypeDefinition\n     *   - TypeExtension\n     *   - DirectiveDefinition\n     *\n     * TypeDefinition :\n     *   - ScalarTypeDefinition\n     *   - ObjectTypeDefinition\n     *   - InterfaceTypeDefinition\n     *   - UnionTypeDefinition\n     *   - EnumTypeDefinition\n     *   - InputObjectTypeDefinition\n     *\n     * @return TypeSystemDefinitionNodeInterface\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     */\n    protected function lexTypeSystemDefinition(): TypeSystemDefinitionNodeInterface\n    {\n        // Many definitions begin with a description and require a lookahead.\n        $token = $this->peekDescription()\n            ? $this->lexer->lookahead()\n            : $this->lexer->getToken();\n\n        if (TokenKindEnum::NAME === $token->getKind()) {\n            switch ($token->getValue()) {\n                case KeywordEnum::SCHEMA:\n                    return $this->lexSchemaDefinition();\n                case KeywordEnum::SCALAR:\n                    return $this->lexScalarTypeDefinition();\n                case KeywordEnum::TYPE:\n                    return $this->lexObjectTypeDefinition();\n                case KeywordEnum::INTERFACE:\n                    return $this->lexInterfaceTypeDefinition();\n                case KeywordEnum::UNION:\n                    return $this->lexUnionTypeDefinition();\n                case KeywordEnum::ENUM:\n                    return $this->lexEnumTypeDefinition();\n                case KeywordEnum::INPUT:\n                    return $this->lexInputObjectTypeDefinition();\n                case KeywordEnum::DIRECTIVE:\n                    return $this->lexDirectiveDefinition();\n            }\n        }\n\n        throw $this->unexpected($token);\n    }\n\n    /**\n     * @return bool\n     */\n    protected function peekDescription(): bool\n    {\n        return $this->peek(TokenKindEnum::STRING) || $this->peek(TokenKindEnum::BLOCK_STRING);\n    }\n\n    /**\n     * Description : StringValue\n     *\n     * @return StringValueNode|null\n     */\n    public function lexDescription(): ?StringValueNode\n    {\n        return $this->peekDescription()\n            ? $this->lexStringLiteral()\n            : null;\n    }\n\n    /**\n     * SchemaDefinition : schema Directives[Const]? { OperationTypeDefinition+ }\n     *\n     * @return SchemaDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexSchemaDefinition(): SchemaDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::SCHEMA);\n\n        return new SchemaDefinitionNode(\n            $this->lexDirectives(),\n            $this->many(\n                TokenKindEnum::BRACE_L,\n                [$this, 'lexOperationTypeDefinition'],\n                TokenKindEnum::BRACE_R\n            ),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * OperationTypeDefinition : OperationType : NamedType\n     *\n     * @return OperationTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexOperationTypeDefinition(): OperationTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $operation = $this->lexOperationType();\n\n        $this->expect(TokenKindEnum::COLON);\n\n        return new OperationTypeDefinitionNode(\n            $operation,\n            $this->lexNamedType(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * ScalarTypeDefinition : Description? scalar Name Directives[Const]?\n     *\n     * @return ScalarTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexScalarTypeDefinition(): ScalarTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::SCALAR);\n\n        return new ScalarTypeDefinitionNode(\n            $description,\n            $this->lexName(),\n            $this->lexDirectives(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * ObjectTypeDefinition :\n     *   Description?\n     *   type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?\n     *\n     * @return ObjectTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexObjectTypeDefinition(): ObjectTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::TYPE);\n\n        return new ObjectTypeDefinitionNode(\n            $description,\n            $this->lexName(),\n            $this->lexImplementsInterfaces(),\n            $this->lexDirectives(),\n            $this->lexFieldsDefinition(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * ImplementsInterfaces :\n     *   - implements `&`? NamedType\n     *   - ImplementsInterfaces & NamedType\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexImplementsInterfaces(): array\n    {\n        $types = [];\n\n        $token = $this->lexer->getToken();\n\n        if ('implements' === $token->getValue()) {\n            $this->lexer->advance();\n\n            // Optional leading ampersand\n            $this->skip(TokenKindEnum::AMP);\n\n            do {\n                $types[] = $this->lexNamedType();\n            } while ($this->skip(TokenKindEnum::AMP));\n        }\n\n        return $types;\n    }\n\n    /**\n     * FieldsDefinition : { FieldDefinition+ }\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexFieldsDefinition(): array\n    {\n        return $this->peek(TokenKindEnum::BRACE_L)\n            ? $this->many(\n                TokenKindEnum::BRACE_L,\n                [$this, 'lexFieldDefinition'],\n                TokenKindEnum::BRACE_R\n            )\n            : [];\n    }\n\n    /**\n     * FieldDefinition :\n     *   - Description? Name ArgumentsDefinition? : Type Directives[Const]?\n     *\n     * @return FieldDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexFieldDefinition(): FieldDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n        $name        = $this->lexName();\n        $arguments   = $this->lexArgumentsDefinition();\n\n        $this->expect(TokenKindEnum::COLON);\n\n        return new FieldDefinitionNode(\n            $description,\n            $name,\n            $arguments,\n            $this->lexType(),\n            $this->lexDirectives(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * ArgumentsDefinition : ( InputValueDefinition+ )\n     *\n     * @return InputValueDefinitionNode[]\n     * @throws SyntaxErrorException\n     */\n    protected function lexArgumentsDefinition(): array\n    {\n        $parseFunction = function (): InputValueDefinitionNode {\n            return $this->lexInputValueDefinition();\n        };\n\n        return $this->peek(TokenKindEnum::PAREN_L)\n            ? $this->many(\n                TokenKindEnum::PAREN_L,\n                $parseFunction,\n                TokenKindEnum::PAREN_R\n            )\n            : [];\n    }\n\n    /**\n     * InputValueDefinition :\n     *   - Description? Name : Type DefaultValue? Directives[Const]?\n     *\n     * @return InputValueDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexInputValueDefinition(): InputValueDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n        $name        = $this->lexName();\n\n        $this->expect(TokenKindEnum::COLON);\n\n        return new InputValueDefinitionNode(\n            $description,\n            $name,\n            $this->lexType(),\n            $this->skip(TokenKindEnum::EQUALS)\n                ? $this->lexValue(true)\n                : null,\n            $this->lexDirectives(true),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * InterfaceTypeDefinition :\n     *   - Description? interface Name Directives[Const]? FieldsDefinition?\n     *\n     * @return InterfaceTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexInterfaceTypeDefinition(): InterfaceTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::INTERFACE);\n\n        return new InterfaceTypeDefinitionNode(\n            $description,\n            $this->lexName(),\n            $this->lexDirectives(),\n            $this->lexFieldsDefinition(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * UnionTypeDefinition :\n     *   - Description? union Name Directives[Const]? UnionMemberTypes?\n     *\n     * @return UnionTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexUnionTypeDefinition(): UnionTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::UNION);\n\n        return new UnionTypeDefinitionNode(\n            $description,\n            $this->lexName(),\n            $this->lexDirectives(),\n            $this->lexUnionMemberTypes(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * UnionMemberTypes :\n     *   - = `|`? NamedType\n     *   - UnionMemberTypes | NamedType\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexUnionMemberTypes(): array\n    {\n        $types = [];\n\n        if ($this->skip(TokenKindEnum::EQUALS)) {\n            // Optional leading pipe\n            $this->skip(TokenKindEnum::PIPE);\n\n            do {\n                $types[] = $this->lexNamedType();\n            } while ($this->skip(TokenKindEnum::PIPE));\n        }\n\n        return $types;\n    }\n\n    /**\n     * EnumTypeDefinition :\n     *   - Description? enum Name Directives[Const]? EnumValuesDefinition?\n     *\n     * @return EnumTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexEnumTypeDefinition(): EnumTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::ENUM);\n\n        return new EnumTypeDefinitionNode(\n            $description,\n            $this->lexName(),\n            $this->lexDirectives(),\n            $this->lexEnumValuesDefinition(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * EnumValuesDefinition : { EnumValueDefinition+ }\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexEnumValuesDefinition(): array\n    {\n        return $this->peek(TokenKindEnum::BRACE_L)\n            ? $this->many(\n                TokenKindEnum::BRACE_L,\n                [$this, 'lexEnumValueDefinition'],\n                TokenKindEnum::BRACE_R\n            )\n            : [];\n    }\n\n    /**\n     * EnumValueDefinition : Description? EnumValue Directives[Const]?\n     *\n     * EnumValue : Name\n     *\n     * @return EnumValueDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexEnumValueDefinition(): EnumValueDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        return new EnumValueDefinitionNode(\n            $this->lexDescription(),\n            $this->lexName(),\n            $this->lexDirectives(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * InputObjectTypeDefinition :\n     *   - Description? input Name Directives[Const]? InputFieldsDefinition?\n     *\n     * @return InputObjectTypeDefinitionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexInputObjectTypeDefinition(): InputObjectTypeDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::INPUT);\n\n        return new InputObjectTypeDefinitionNode(\n            $description,\n            $this->lexName(),\n            $this->lexDirectives(true),\n            $this->lexInputFieldsDefinition(),\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * InputFieldsDefinition : { InputValueDefinition+ }\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function lexInputFieldsDefinition(): array\n    {\n        $parseFunction = function (): InputValueDefinitionNode {\n            return $this->lexInputValueDefinition();\n        };\n\n        return $this->peek(TokenKindEnum::BRACE_L)\n            ? $this->many(\n                TokenKindEnum::BRACE_L,\n                $parseFunction,\n                TokenKindEnum::BRACE_R\n            )\n            : [];\n    }\n\n    /**\n     * TypeExtension :\n     *   - ScalarTypeExtension\n     *   - ObjectTypeExtension\n     *   - InterfaceTypeExtension\n     *   - UnionTypeExtension\n     *   - EnumTypeExtension\n     *   - InputObjectTypeDefinition\n     *\n     * @return TypeSystemExtensionNodeInterface\n     * @throws SyntaxErrorException\n     */\n    protected function lexTypeSystemExtension(): TypeSystemExtensionNodeInterface\n    {\n        $token = $this->lexer->lookahead();\n\n        if (TokenKindEnum::NAME === $token->getKind()) {\n            switch ($token->getValue()) {\n                case KeywordEnum::SCHEMA:\n                    return $this->lexSchemaExtension();\n                case KeywordEnum::SCALAR:\n                    return $this->lexScalarTypeExtension(false);\n                case KeywordEnum::TYPE:\n                    return $this->lexObjectTypeExtension();\n                case KeywordEnum::INTERFACE:\n                    return $this->lexInterfaceTypeExtension();\n                case KeywordEnum::UNION:\n                    return $this->lexUnionTypeExtension();\n                case KeywordEnum::ENUM:\n                    return $this->lexEnumTypeExtension();\n                case KeywordEnum::INPUT:\n                    return $this->lexInputObjectTypeExtension();\n            }\n        }\n\n        throw $this->unexpected($token);\n    }\n\n    /**\n     * SchemaExtension :\n     *  - extend schema Directives[Const]? { OperationTypeDefinition+ }\n     *  - extend schema Directives[Const]\n     *\n     * @return SchemaExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexSchemaExtension(): SchemaExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::SCHEMA);\n\n        $directives = $this->lexDirectives(true);\n\n        $parseFunction = function (): OperationTypeDefinitionNode {\n            return $this->lexOperationTypeDefinition();\n        };\n\n        $operationTypes = $this->peek(TokenKindEnum::BRACE_L)\n            ? $this->many(\n                TokenKindEnum::BRACE_L,\n                $parseFunction,\n                TokenKindEnum::BRACE_R\n            )\n            : [];\n\n        if (empty($directives) && empty($operationTypes)) {\n            $this->unexpected();\n        }\n\n        return new SchemaExtensionNode($directives, $operationTypes, $this->createLocation($start));\n    }\n\n    /**\n     * ScalarTypeExtension :\n     *   - extend scalar Name Directives[Const]\n     *\n     * @param bool $isConst\n     * @return ScalarTypeExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexScalarTypeExtension(bool $isConst = false): ScalarTypeExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::SCALAR);\n\n        $name       = $this->lexName();\n        $directives = $this->lexDirectives($isConst);\n\n        if (empty($directives)) {\n            throw $this->unexpected();\n        }\n\n        return new ScalarTypeExtensionNode($name, $directives, $this->createLocation($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     * @return ObjectTypeExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexObjectTypeExtension(): ObjectTypeExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::TYPE);\n\n        $name       = $this->lexName();\n        $interfaces = $this->lexImplementsInterfaces();\n        $directives = $this->lexDirectives();\n        $fields     = $this->lexFieldsDefinition();\n\n        if (empty($interfaces) && empty($directives) && empty($fields)) {\n            throw $this->unexpected();\n        }\n\n        return new ObjectTypeExtensionNode(\n            $name,\n            $interfaces,\n            $directives,\n            $fields,\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * InterfaceTypeExtension :\n     *   - extend interface Name Directives[Const]? FieldsDefinition\n     *   - extend interface Name Directives[Const]\n     *\n     * @return InterfaceTypeExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexInterfaceTypeExtension(): InterfaceTypeExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::INTERFACE);\n\n        $name       = $this->lexName();\n        $directives = $this->lexDirectives();\n        $fields     = $this->lexFieldsDefinition();\n\n        if (empty($directives) && empty($fields)) {\n            throw $this->unexpected();\n        }\n\n        return new InterfaceTypeExtensionNode($name, $directives, $fields, $this->createLocation($start));\n    }\n\n    /**\n     * UnionTypeExtension :\n     *   - extend union Name Directives[Const]? UnionMemberTypes\n     *   - extend union Name Directives[Const]\n     *\n     * @return UnionTypeExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexUnionTypeExtension(): UnionTypeExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::UNION);\n\n        $name       = $this->lexName();\n        $directives = $this->lexDirectives();\n        $types      = $this->lexUnionMemberTypes();\n\n        if (empty($directives) && empty($types)) {\n            throw $this->unexpected();\n        }\n\n        return new UnionTypeExtensionNode($name, $directives, $types, $this->createLocation($start));\n    }\n\n    /**\n     * EnumTypeExtension :\n     *   - extend enum Name Directives[Const]? EnumValuesDefinition\n     *   - extend enum Name Directives[Const]\n     *\n     * @return EnumTypeExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexEnumTypeExtension(): EnumTypeExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::ENUM);\n\n        $name       = $this->lexName();\n        $directives = $this->lexDirectives();\n        $values     = $this->lexEnumValuesDefinition();\n\n        if (empty($directives) && empty($values)) {\n            throw $this->unexpected();\n        }\n\n        return new EnumTypeExtensionNode($name, $directives, $values, $this->createLocation($start));\n    }\n\n    /**\n     * InputObjectTypeExtension :\n     *   - extend input Name Directives[Const]? InputFieldsDefinition\n     *   - extend input Name Directives[Const]\n     *\n     * @return InputObjectTypeExtensionNode\n     * @throws SyntaxErrorException\n     */\n    protected function lexInputObjectTypeExtension(): InputObjectTypeExtensionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $this->expectKeyword(KeywordEnum::EXTEND);\n        $this->expectKeyword(KeywordEnum::INPUT);\n\n        $name       = $this->lexName();\n        $directives = $this->lexDirectives(true);\n        $fields     = $this->lexInputFieldsDefinition();\n\n        if (empty($directives) && empty($fields)) {\n            throw $this->unexpected();\n        }\n\n        return new InputObjectTypeExtensionNode($name, $directives, $fields, $this->createLocation($start));\n    }\n\n    /**\n     * DirectiveDefinition :\n     *   - Description? directive @ Name ArgumentsDefinition? on DirectiveLocations\n     *\n     * @return DirectiveDefinitionNode\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     */\n    protected function lexDirectiveDefinition(): DirectiveDefinitionNode\n    {\n        $start = $this->lexer->getToken();\n\n        $description = $this->lexDescription();\n\n        $this->expectKeyword(KeywordEnum::DIRECTIVE);\n        $this->expect(TokenKindEnum::AT);\n\n        $name      = $this->lexName();\n        $arguments = $this->lexArgumentsDefinition();\n\n        $this->expectKeyword(KeywordEnum::ON);\n\n        $locations = $this->lexDirectiveLocations();\n\n        return new DirectiveDefinitionNode(\n            $description,\n            $name,\n            $arguments,\n            $locations,\n            $this->createLocation($start)\n        );\n    }\n\n    /**\n     * DirectiveLocations :\n     *   - `|`? DirectiveLocation\n     *   - DirectiveLocations | DirectiveLocation\n     *\n     * @return array\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     */\n    protected function lexDirectiveLocations(): array\n    {\n        $this->skip(TokenKindEnum::PIPE);\n\n        $locations = [];\n\n        do {\n            $locations[] = $this->lexDirectiveLocation();\n        } while ($this->skip(TokenKindEnum::PIPE));\n\n        return $locations;\n    }\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     * @return NameNode\n     * @throws SyntaxErrorException\n     * @throws \\ReflectionException\n     */\n    protected function lexDirectiveLocation(): NameNode\n    {\n        $start = $this->lexer->getToken();\n\n        $name = $this->lexName();\n\n        if (arraySome(DirectiveLocationEnum::values(), function ($value) use ($name) {\n            return $name->getValue() === $value;\n        })) {\n            return $name;\n        }\n\n        throw $this->unexpected($start);\n    }\n\n    /**\n     * Returns a location object, used to identify the place in\n     * the source that created a given parsed object.\n     *\n     * @param Token $start\n     * @return Location|null\n     */\n    protected function createLocation(Token $start): ?Location\n    {\n        return !$this->lexer->getOption('noLocation', false)\n            ? new Location(\n                $start->getStart(),\n                $this->lexer->getLastToken()->getEnd(),\n                $this->lexer->getSource()\n            )\n            : null;\n    }\n\n    /**\n     * @param Source $source\n     * @param array  $options\n     * @return LexerInterface\n     */\n    protected function createLexer($source, array $options): LexerInterface\n    {\n        return new Lexer($source, $options);\n    }\n\n    /**\n     * Determines if the next token is of a given kind.\n     *\n     * @param string $kind\n     * @return bool\n     */\n    protected function peek(string $kind): bool\n    {\n        return $kind === $this->lexer->getToken()->getKind();\n    }\n\n    /**\n     * If the next token is of the given kind, return true after advancing\n     * the lexer. Otherwise, do not change the parser state and return false.\n     *\n     * @param string $kind\n     * @return bool\n     */\n    protected function skip(string $kind): bool\n    {\n        if ($match = $this->peek($kind)) {\n            $this->lexer->advance();\n        }\n\n        return $match;\n    }\n\n    /**\n     * If the next token is of the given kind, return that token after advancing\n     * the lexer. Otherwise, do not change the parser state and throw an error.\n     *\n     * @param string $kind\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function expect(string $kind): Token\n    {\n        $token = $this->lexer->getToken();\n\n        if ($kind === $token->getKind()) {\n            $this->lexer->advance();\n            return $token;\n        }\n\n        throw $this->lexer->createSyntaxErrorException(\\sprintf('Expected %s, found %s.', $kind, $token));\n    }\n\n    /**\n     * @param string $value\n     * @return Token\n     * @throws SyntaxErrorException\n     */\n    protected function expectKeyword(string $value): Token\n    {\n        $token = $this->lexer->getToken();\n\n        if (TokenKindEnum::NAME === $token->getKind() && $value === $token->getValue()) {\n            $this->lexer->advance();\n            return $token;\n        }\n\n        throw $this->lexer->createSyntaxErrorException(\\sprintf('Expected %s, found %s', $value, $token));\n    }\n\n    /**\n     * Helper function for creating an error when an unexpected lexed token\n     * is encountered.\n     *\n     * @param Token|null $atToken\n     * @return SyntaxErrorException\n     */\n    protected function unexpected(?Token $atToken = null): SyntaxErrorException\n    {\n        $token = $atToken ?? $this->lexer->getToken();\n\n        return $this->lexer->createSyntaxErrorException(\\sprintf('Unexpected %s', $token));\n    }\n\n    /**\n     * Returns a possibly empty list of parse nodes, determined by\n     * the parseFn. This list begins with a lex token of openKind\n     * and ends with a lex token of closeKind. Advances the parser\n     * to the next lex token after the closing token.\n     *\n     * @param string   $openKind\n     * @param callable $parseFunction\n     * @param string   $closeKind\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function any(string $openKind, callable $parseFunction, string $closeKind): array\n    {\n        $this->expect($openKind);\n\n        $nodes = [];\n\n        while (!$this->skip($closeKind)) {\n            $nodes[] = $parseFunction();\n        }\n\n        return $nodes;\n    }\n\n    /**\n     * Returns a non-empty list of parse nodes, determined by\n     * the parseFn. This list begins with a lex token of openKind\n     * and ends with a lex token of closeKind. Advances the parser\n     * to the next lex token after the closing token.\n     *\n     * @param string   $openKind\n     * @param callable $parseFunction\n     * @param string   $closeKind\n     * @return array\n     * @throws SyntaxErrorException\n     */\n    protected function many(string $openKind, callable $parseFunction, string $closeKind): array\n    {\n        $this->expect($openKind);\n\n        $nodes = [$parseFunction()];\n\n        while (!$this->skip($closeKind)) {\n            $nodes[] = $parseFunction();\n        }\n\n        return $nodes;\n    }\n}\n"
  },
  {
    "path": "src/Language/ParserInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\n\n/**\n * Interface ParserInterface\n * @package Digia\\GraphQL\\Language\n *\n * @method parseValue($source, array $options = []): ValueNodeInterface\n * @method parseType($source, array $options = []): TypeNodeInterface\n * @method parseName($source, array $options = []): NameNode\n * @method parseOperationDefinition($source, array $options = []): OperationDefinitionNode\n * @method parseVariableDefinition($source, array $options = []): VariableDefinitionNode\n * @method parseVariable($source, array $options = []): VariableNode\n * @method parseSelectionSet($source, array $options = []): SelectionSetNode\n * @method parseField($source, array $options = []): FieldNode\n * @method parseArgument($source, array $options = []): ArgumentNode\n * @method parseFragment($source, array $options = []): FragmentNodeInterface\n * @method parseFragmentDefinition($source, array $options = []): FragmentDefinitionNode\n * @method parseDirective($source, array $options = []): DirectiveNode\n * @method parseNamedType($source, array $options = []): NamedTypeNode\n * @method parseDescription($source, array $options = []): ?StringValueNode\n * @method parseSchemaDefinition($source, array $options = []): SchemaDefinitionNode\n * @method parseOperationTypeDefinition($source, array $options = []): OperationTypeDefinitionNode\n * @method parseScalarTypeDefinition($source, array $options = []): ScalarTypeDefinitionNode\n * @method parseObjectTypeDefinition($source, array $options = []): ObjectTypeDefinitionNode\n * @method parseFieldDefinition($source, array $options = []): FieldDefinitionNode\n * @method parseInputValueDefinition($source, array $options = []): InputValueDefinitionNode\n * @method parseInterfaceTypeDefinition($source, array $options = []): InterfaceTypeDefinitionNode\n * @method parseUnionTypeDefinition($source, array $options = []): UnionTypeDefinitionNode\n * @method parseEnumTypeDefinition($source, array $options = []): EnumTypeDefinitionNode\n * @method parseEnumValueDefinition($source, array $options = []): EnumValueDefinitionNode\n * @method parseInputObjectTypeDefinition($source, array $options = []): InputObjectTypeDefinitionNode\n * @method parseScalarTypeExtension($source, array $options = []): ScalarTypeExtensionNode\n * @method parseObjectTypeExtension($source, array $options = []): ObjectTypeExtensionNode\n * @method parseInterfaceTypeExtension($source, array $options = []): InterfaceTypeExtensionNode\n * @method parseUnionTypeExtension($source, array $options = []): UnionTypeExtensionNode\n * @method parseEnumTypeExtension($source, array $options = []): EnumTypeExtensionNode\n * @method parseInputObjectTypeExtension($source, array $options = []): InputObjectTypeExtensionNode\n * @method parseDirectiveDefinition($source, array $options = []): DirectiveDefinitionNode\n */\ninterface ParserInterface\n{\n    /**\n     * Given a GraphQL source, parses it into a Document.\n     *\n     * @param Source $source\n     * @param array  $options\n     * @return DocumentNode\n     */\n    public function parse(Source $source, array $options = []): DocumentNode;\n}\n"
  },
  {
    "path": "src/Language/PrintException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\AbstractException;\n\nclass PrintException extends AbstractException\n{\n}\n"
  },
  {
    "path": "src/Language/Source.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\n\n/**\n * A representation of source input to GraphQL.\n * `name` and `locationOffset` are optional. They are useful for clients who\n * store GraphQL documents in source files; for example, if the GraphQL input\n * starts at line 40 in a file named Foo.graphql, it might be useful for name to\n * be \"Foo.graphql\", line to be 40 and column to be 0.\n * line and column are 1-indexed\n */\nclass Source\n{\n\n    /**\n     * @var string\n     */\n    protected $body;\n\n    /**\n     * @var string\n     */\n    protected $name;\n\n    /**\n     * @var SourceLocation|null\n     */\n    protected $locationOffset;\n\n    /**\n     * Source constructor.\n     *\n     * @param string              $body\n     * @param null|string         $name\n     * @param SourceLocation|null $locationOffset\n     * @throws InvariantException\n     */\n    public function __construct(string $body, ?string $name = 'GraphQL request', ?SourceLocation $locationOffset = null)\n    {\n        $this->body = $body;\n        $this->name = $name;\n\n        $this->setLocationOffset($locationOffset);\n    }\n\n    /**\n     * @return int\n     */\n    public function getBodyLength(): int\n    {\n        return mb_strlen($this->body);\n    }\n\n    /**\n     * @return string\n     */\n    public function getBody(): string\n    {\n        return $this->body;\n    }\n\n    /**\n     * @return string\n     */\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    /**\n     * @return SourceLocation|null\n     */\n    public function getLocationOffset(): ?SourceLocation\n    {\n        return $this->locationOffset;\n    }\n\n    /**\n     * @param string $body\n     * @return Source\n     */\n    protected function setBody(string $body): Source\n    {\n        $this->body = $body;\n        return $this;\n    }\n\n    /**\n     * @param string $name\n     * @return Source\n     */\n    protected function setName(string $name): Source\n    {\n        $this->name = $name;\n        return $this;\n    }\n\n    /**\n     * @param SourceLocation|null $locationOffset\n     * @return Source\n     * @throws InvariantException\n     */\n    protected function setLocationOffset(?SourceLocation $locationOffset): Source\n    {\n        if (null !== $locationOffset) {\n            if ($locationOffset->getLine() < 1) {\n                throw new InvariantException(\"'line is 1-indexed and must be positive\");\n            }\n\n            if ($locationOffset->getColumn() < 1) {\n                throw new InvariantException(\"'column is 1-indexed and must be positive'\");\n            }\n        }\n\n        $this->locationOffset = $locationOffset ?? new SourceLocation();\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/SourceBuilderInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\n/**\n * Interface SourceBuilderInterface\n * @package Digia\\GraphQL\\Language\n */\ninterface SourceBuilderInterface\n{\n\n    /**\n     * @return Source\n     */\n    public function build(): Source;\n}\n"
  },
  {
    "path": "src/Language/SourceLocation.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Util\\ArrayToJsonTrait;\nuse Digia\\GraphQL\\Util\\SerializationInterface;\n\nclass SourceLocation implements SerializationInterface\n{\n    use ArrayToJsonTrait;\n\n    /**\n     * @var int\n     */\n    protected $line;\n\n    /**\n     * @var int\n     */\n    protected $column;\n\n    /**\n     * SourceLocation constructor.\n     *\n     * @param int $line\n     * @param int $column\n     */\n    public function __construct(int $line = 1, int $column = 1)\n    {\n        $this->line   = $line;\n        $this->column = $column;\n    }\n\n    /**\n     * @return int\n     */\n    public function getLine(): int\n    {\n        return $this->line;\n    }\n\n    /**\n     * @return int\n     */\n    public function getColumn(): int\n    {\n        return $this->column;\n    }\n\n    /**\n     * @param Source $source\n     * @param int    $position\n     * @return SourceLocation\n     */\n    public static function fromSource(Source $source, int $position): self\n    {\n        $line    = 1;\n        $column  = $position + 1;\n        $matches = [];\n\n        \\preg_match_all(\"/\\r\\n|[\\n\\r]/\", \\substr($source->getBody(), 0, $position), $matches, PREG_OFFSET_CAPTURE);\n\n        foreach ($matches[0] as $index => $match) {\n            $line   += 1;\n            $column = $position + 1 - ($match[1] + \\strlen($match[0]));\n        }\n\n        return new static($line, $column);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toArray(): array\n    {\n        return [\n            'line'   => $this->line,\n            'column' => $this->column,\n        ];\n    }\n}\n"
  },
  {
    "path": "src/Language/StringSourceBuilder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nclass StringSourceBuilder implements SourceBuilderInterface\n{\n\n    /**\n     * @var string\n     */\n    private $body;\n\n    /**\n     * StringSourceBuilder constructor.\n     * @param string $body\n     */\n    public function __construct(string $body)\n    {\n        $this->body = $body;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function build(): Source\n    {\n        return new Source($this->body);\n    }\n}\n"
  },
  {
    "path": "src/Language/SyntaxErrorException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass SyntaxErrorException extends GraphQLException\n{\n    /**\n     * SyntaxErrorException constructor.\n     * @param Source $source\n     * @param int    $position\n     * @param string $description\n     */\n    public function __construct(Source $source, int $position, string $description)\n    {\n        parent::__construct(\n            sprintf('Syntax Error: %s', $description),\n            null,\n            $source,\n            [$position]\n        );\n    }\n}\n"
  },
  {
    "path": "src/Language/Token.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse Digia\\GraphQL\\Util\\ArrayToJsonTrait;\nuse Digia\\GraphQL\\Util\\SerializationInterface;\n\nclass Token implements SerializationInterface\n{\n    use ArrayToJsonTrait;\n\n    /**\n     * @var string\n     */\n    protected $kind;\n\n    /**\n     * @var int\n     */\n    protected $start;\n\n    /**\n     * @var int\n     */\n    protected $end;\n\n    /**\n     * @var int\n     */\n    protected $line;\n\n    /**\n     * @var int\n     */\n    protected $column;\n\n    /**\n     * @var Token|null\n     */\n    protected $prev;\n\n    /**\n     * @var Token|null\n     */\n    protected $next;\n\n    /**\n     * @var string|null\n     */\n    protected $value;\n\n    /**\n     * Token constructor.\n     *\n     * @param string      $kind\n     * @param int         $start\n     * @param int         $end\n     * @param int         $line\n     * @param int         $column\n     * @param Token|null  $prev\n     * @param string|null $value\n     */\n    public function __construct(\n        string $kind,\n        int $start = 0,\n        int $end = 0,\n        int $line = 0,\n        int $column = 0,\n        ?Token $prev = null,\n        ?string $value = null\n    ) {\n        $this->kind   = $kind;\n        $this->start  = $start;\n        $this->end    = $end;\n        $this->line   = $line;\n        $this->column = $column;\n        $this->prev   = $prev;\n        $this->value  = $value;\n    }\n\n    /**\n     * @return string\n     */\n    public function getKind(): string\n    {\n        return $this->kind;\n    }\n\n    /**\n     * @return int\n     */\n    public function getStart(): int\n    {\n        return $this->start;\n    }\n\n    /**\n     * @return int\n     */\n    public function getEnd(): int\n    {\n        return $this->end;\n    }\n\n    /**\n     * @return int\n     */\n    public function getLine(): int\n    {\n        return $this->line;\n    }\n\n    /**\n     * @return int\n     */\n    public function getColumn(): int\n    {\n        return $this->column;\n    }\n\n    /**\n     * @return Token|null\n     */\n    public function getPrev(): ?Token\n    {\n        return $this->prev;\n    }\n\n    /**\n     * @return Token|null\n     */\n    public function getNext(): ?Token\n    {\n        return $this->next;\n    }\n\n    /**\n     * @return string|null\n     */\n    public function getValue(): ?string\n    {\n        return $this->value;\n    }\n\n    /**\n     * @param Token|null $next\n     * @return $this\n     */\n    public function setNext(?Token $next)\n    {\n        $this->next = $next;\n        return $this;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function toArray(): array\n    {\n        return [\n            'kind'   => $this->kind,\n            'line'   => $this->line,\n            'column' => $this->column,\n            'value'  => $this->value,\n        ];\n    }\n\n    /**\n     * @return string\n     */\n    public function __toString(): string\n    {\n        return $this->value !== null\n            ? sprintf('%s \"%s\"', $this->kind, $this->value)\n            : $this->kind;\n    }\n}\n"
  },
  {
    "path": "src/Language/TokenKindEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nclass TokenKindEnum\n{\n\n    public const SOF          = '<SOF>';\n    public const EOF          = '<EOF>';\n    public const BANG         = '!';\n    public const DOLLAR       = '$';\n    public const AMP          = '&';\n    public const PAREN_L      = '(';\n    public const PAREN_R      = ')';\n    public const SPREAD       = '...';\n    public const COLON        = ':';\n    public const EQUALS       = '=';\n    public const AT           = '@';\n    public const BRACKET_L    = '[';\n    public const BRACKET_R    = ']';\n    public const BRACE_L      = '{';\n    public const PIPE         = '|';\n    public const BRACE_R      = '}';\n    public const NAME         = 'Name';\n    public const INT          = 'Int';\n    public const FLOAT        = 'Float';\n    public const STRING       = 'String';\n    public const BLOCK_STRING = 'BlockString';\n    public const COMMENT      = 'Comment';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Language/Visitor/ParallelVisitor.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass ParallelVisitor implements VisitorInterface\n{\n    /**\n     * @var VisitorInterface[]\n     */\n    protected $visitors;\n\n    /**\n     * @var array\n     */\n    protected $skipping = [];\n\n    /**\n     * ParallelVisitor constructor.\n     * @param array|VisitorInterface[] $visitors\n     */\n    public function __construct($visitors)\n    {\n        $this->visitors = $visitors;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function enterNode(NodeInterface $node): VisitorResult\n    {\n        foreach ($this->visitors as $i => $visitor) {\n            if (!isset($this->skipping[$i])) {\n                $VisitorResult = $visitor->enterNode($node);\n\n                if ($VisitorResult->getAction() === VisitorResult::ACTION_BREAK) {\n                    $this->skipping[$i] = true;\n                    continue;\n                }\n\n                if (null === $VisitorResult->getValue()) {\n                    $this->skipping[$i] = $node;\n\n                    $VisitorResult = new VisitorResult($node);\n                }\n            }\n        }\n\n        return $VisitorResult ?? new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function leaveNode(NodeInterface $node): VisitorResult\n    {\n        foreach ($this->visitors as $i => $visitor) {\n            if (!isset($this->skipping[$i])) {\n                $VisitorResult = $visitor->leaveNode($node);\n\n                if ($VisitorResult->getAction() === VisitorResult::ACTION_BREAK) {\n                    $this->skipping[$i] = true;\n                    continue;\n                }\n            } elseif ($this->skipping[$i] === $node) {\n                unset($this->skipping[$i]);\n            }\n        }\n\n        return $VisitorResult ?? new VisitorResult(null);\n    }\n}\n"
  },
  {
    "path": "src/Language/Visitor/SpecificKindVisitor.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NonNullTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\n\nclass SpecificKindVisitor implements VisitorInterface\n{\n    /**\n     * @inheritdoc\n     */\n    public function enterNode(NodeInterface $node): VisitorResult\n    {\n        $enterMethod = 'enter' . $node->getKind();\n        return $this->{$enterMethod}($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function leaveNode(NodeInterface $node): VisitorResult\n    {\n        $leaveMethod = 'leave' . $node->getKind();\n        return $this->{$leaveMethod}($node);\n    }\n\n    /**\n     * @param ArgumentNode $node\n     * @return VisitorResult\n     */\n    protected function enterArgument(ArgumentNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ArgumentNode $node\n     * @return VisitorResult\n     */\n    protected function leaveArgument(ArgumentNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param BooleanValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterBooleanValue(BooleanValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param BooleanValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveBooleanValue(BooleanValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param DirectiveDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterDirectiveDefinition(DirectiveDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param DirectiveDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveDirectiveDefinition(DirectiveDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param DirectiveNode $node\n     * @return VisitorResult\n     */\n    protected function enterDirective(DirectiveNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param DirectiveNode $node\n     * @return VisitorResult\n     */\n    protected function leaveDirective(DirectiveNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param DocumentNode $node\n     * @return VisitorResult\n     */\n    protected function enterDocument(DocumentNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param DocumentNode $node\n     * @return VisitorResult\n     */\n    protected function leaveDocument(DocumentNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterEnumTypeDefinition(EnumTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveEnumTypeDefinition(EnumTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterEnumTypeExtension(EnumTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveEnumTypeExtension(EnumTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumValueDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterEnumValueDefinition(EnumValueDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumValueDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveEnumValueDefinition(EnumValueDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterEnumValue(EnumValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param EnumValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveEnumValue(EnumValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FieldDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterFieldDefinition(FieldDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FieldDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveFieldDefinition(FieldDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FieldNode $node\n     * @return VisitorResult\n     */\n    protected function enterField(FieldNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FieldNode $node\n     * @return VisitorResult\n     */\n    protected function leaveField(FieldNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FloatValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterFloatValue(FloatValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FloatValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveFloatValue(FloatValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FragmentDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FragmentDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FragmentSpreadNode $node\n     * @return VisitorResult\n     */\n    protected function enterFragmentSpread(FragmentSpreadNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param FragmentSpreadNode $node\n     * @return VisitorResult\n     */\n    protected function leaveFragmentSpread(FragmentSpreadNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InlineFragmentNode $node\n     * @return VisitorResult\n     */\n    protected function enterInlineFragment(InlineFragmentNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InlineFragmentNode $node\n     * @return VisitorResult\n     */\n    protected function leaveInlineFragment(InlineFragmentNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InputObjectTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterInputObjectTypeDefinition(InputObjectTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InputObjectTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveInputObjectTypeDefinition(InputObjectTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InputObjectTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterInputObjectTypeExtension(InputObjectTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InputObjectTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveInputObjectTypeExtension(InputObjectTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InputValueDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterInputValueDefinition(InputValueDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InputValueDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveInputValueDefinition(InputValueDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param IntValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterIntValue(IntValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param IntValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveIntValue(IntValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InterfaceTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterInterfaceTypeDefinition(InterfaceTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InterfaceTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveInterfaceTypeDefinition(InterfaceTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InterfaceTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterInterfaceTypeExtension(InterfaceTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param InterfaceTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveInterfaceTypeExtension(InterfaceTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ListTypeNode $node\n     * @return VisitorResult\n     */\n    protected function enterListType(ListTypeNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ListTypeNode $node\n     * @return VisitorResult\n     */\n    protected function leaveListType(ListTypeNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ListValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterListValue(ListValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ListValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveListValue(ListValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NamedTypeNode $node\n     * @return VisitorResult\n     */\n    protected function enterNamedType(NamedTypeNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NamedTypeNode $node\n     * @return VisitorResult\n     */\n    protected function leaveNamedType(NamedTypeNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NameNode $node\n     * @return VisitorResult\n     */\n    protected function enterName(NameNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NameNode $node\n     * @return VisitorResult\n     */\n    protected function leaveName(NameNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NonNullTypeNode $node\n     * @return VisitorResult\n     */\n    protected function enterNonNullType(NonNullTypeNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NonNullTypeNode $node\n     * @return VisitorResult\n     */\n    protected function leaveNonNullType(NonNullTypeNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NullValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterNullValue(NullValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NullValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveNullValue(NullValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectFieldNode $node\n     * @return VisitorResult\n     */\n    protected function enterObjectField(ObjectFieldNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectFieldNode $node\n     * @return VisitorResult\n     */\n    protected function leaveObjectField(ObjectFieldNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterObjectTypeDefinition(ObjectTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveObjectTypeDefinition(ObjectTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterObjectTypeExtension(ObjectTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveObjectTypeExtension(ObjectTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterObjectValue(ObjectValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ObjectValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveObjectValue(ObjectValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param OperationDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param OperationDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param OperationTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterOperationTypeDefinition(OperationTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param OperationTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveOperationTypeDefinition(OperationTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ScalarTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterScalarTypeDefinition(ScalarTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ScalarTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveScalarTypeDefinition(ScalarTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ScalarTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterScalarTypeExtension(ScalarTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param ScalarTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveScalarTypeExtension(ScalarTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param SchemaDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterSchemaDefinition(SchemaDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param SchemaDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveSchemaDefinition(SchemaDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param SchemaExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterSchemaExtension(SchemaExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param SchemaExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveSchemaExtension(SchemaExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param SelectionSetNode $node\n     * @return VisitorResult\n     */\n    protected function enterSelectionSet(SelectionSetNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param SelectionSetNode $node\n     * @return VisitorResult\n     */\n    protected function leaveSelectionSet(SelectionSetNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param StringValueNode $node\n     * @return VisitorResult\n     */\n    protected function enterStringValue(StringValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param StringValueNode $node\n     * @return VisitorResult\n     */\n    protected function leaveStringValue(StringValueNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param UnionTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterUnionTypeDefinition(UnionTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param UnionTypeDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveUnionTypeDefinition(UnionTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param UnionTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function enterUnionTypeExtension(UnionTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param UnionTypeExtensionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveUnionTypeExtension(UnionTypeExtensionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param VariableDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param VariableDefinitionNode $node\n     * @return VisitorResult\n     */\n    protected function leaveVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param VariableNode $node\n     * @return VisitorResult\n     */\n    protected function enterVariable(VariableNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param VariableNode $node\n     * @return VisitorResult\n     */\n    protected function leaveVariable(VariableNode $node): VisitorResult\n    {\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Language/Visitor/TypeInfoVisitor.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\CompositeTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Util\\TypeInfo;\nuse function Digia\\GraphQL\\Type\\getNamedType;\nuse function Digia\\GraphQL\\Type\\getNullableType;\nuse function Digia\\GraphQL\\Type\\isInputType;\nuse function Digia\\GraphQL\\Type\\isOutputType;\nuse function Digia\\GraphQL\\Util\\find;\n\nclass TypeInfoVisitor implements VisitorInterface\n{\n    /**\n     * @var TypeInfo\n     */\n    protected $typeInfo;\n\n    /**\n     * @var VisitorInterface\n     */\n    protected $visitor;\n\n    /**\n     * TypeInfoVisitor constructor.\n     * @param TypeInfo         $typeInfo\n     * @param VisitorInterface $visitor\n     */\n    public function __construct(TypeInfo $typeInfo, VisitorInterface $visitor)\n    {\n        $this->typeInfo = $typeInfo;\n        $this->visitor  = $visitor;\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * @throws ConversionException\n     * @throws InvariantException\n     */\n    public function enterNode(NodeInterface $node): VisitorResult\n    {\n        $schema = $this->typeInfo->getSchema();\n\n        if ($node instanceof SelectionSetNode) {\n            $namedType = getNamedType($this->typeInfo->getType());\n            $this->typeInfo->pushParentType($namedType instanceof CompositeTypeInterface ? $namedType : null);\n        } elseif ($node instanceof FieldNode) {\n            $parentType      = $this->typeInfo->getParentType();\n            $fieldDefinition = null;\n            $fieldType       = null;\n            if (null !== $parentType) {\n                $fieldDefinition = $this->typeInfo->resolveFieldDefinition($schema, $parentType, $node);\n                if (null !== $fieldDefinition) {\n                    $fieldType = $fieldDefinition->getType();\n                }\n            }\n            $this->typeInfo->pushFieldDefinition($fieldDefinition);\n            $this->typeInfo->pushType(isOutputType($fieldType) ? $fieldType : null);\n        } elseif ($node instanceof DirectiveNode) {\n            $this->typeInfo->setDirective($schema->getDirective($node->getNameValue()));\n        } elseif ($node instanceof OperationDefinitionNode) {\n            $type      = null;\n            $operation = $node->getOperation();\n            if ($operation === 'query') {\n                $type = $schema->getQueryType();\n            } elseif ($operation === 'mutation') {\n                $type = $schema->getMutationType();\n            } elseif ($operation === 'subscription') {\n                $type = $schema->getSubscriptionType();\n            }\n            $this->typeInfo->pushType($type instanceof ObjectType ? $type : null);\n        } elseif ($node instanceof InlineFragmentNode || $node instanceof FragmentDefinitionNode) {\n            $typeCondition = $node->getTypeCondition();\n            $outputType    = null !== $typeCondition\n                ? TypeASTConverter::convert($schema, $typeCondition)\n                : getNamedType($this->typeInfo->getType());\n            $this->typeInfo->pushType(isOutputType($outputType) ? $outputType : null);\n        } elseif ($node instanceof VariableDefinitionNode) {\n            $inputType = TypeASTConverter::convert($schema, $node->getType());\n            /** @noinspection PhpParamsInspection */\n            $this->typeInfo->pushInputType(isInputType($inputType) ? $inputType : null);\n        } elseif ($node instanceof ArgumentNode) {\n            $argumentType = null;\n            /** @var Argument|null $argumentDefinition */\n            $argumentDefinition = null;\n            $fieldOrDirective   = $this->typeInfo->getDirective() ?: $this->typeInfo->getFieldDefinition();\n            if (null !== $fieldOrDirective) {\n                $argumentDefinition = find(\n                    $fieldOrDirective->getArguments(),\n                    function (Argument $argument) use ($node) {\n                        return $argument->getName() === $node->getNameValue();\n                    }\n                );\n                if (null !== $argumentDefinition) {\n                    $argumentType = $argumentDefinition->getType();\n                }\n            }\n            $this->typeInfo->setArgument($argumentDefinition);\n            $this->typeInfo->pushDefaultValue(null !== $argumentDefinition\n                ? $argumentDefinition->getDefaultValue()\n                : null);\n            $this->typeInfo->pushInputType(isInputType($argumentType) ? $argumentType : null);\n        } elseif ($node instanceof ListValueNode) {\n            $listType = getNullableType($this->typeInfo->getInputType());\n            $itemType = $listType instanceof ListType ? $listType->getOfType() : $listType;\n            // List positions never have a default value.\n            $this->typeInfo->pushDefaultValue(null);\n            $this->typeInfo->pushInputType(isInputType($itemType) ? $itemType : null);\n        } elseif ($node instanceof ObjectFieldNode) {\n            $objectType     = getNamedType($this->typeInfo->getInputType());\n            $inputField     = null;\n            $inputFieldType = null;\n            if ($objectType instanceof InputObjectType) {\n                $fields     = $objectType->getFields();\n                $inputField = $fields[$node->getNameValue()] ?? null;\n                if (null !== $inputField) {\n                    $inputFieldType = $inputField->getType();\n                }\n            }\n            $this->typeInfo->pushDefaultValue(null !== $inputField ? $inputField->getDefaultValue() : null);\n            /** @noinspection PhpParamsInspection */\n            $this->typeInfo->pushInputType(isInputType($inputFieldType) ? $inputFieldType : null);\n        } elseif ($node instanceof EnumValueNode) {\n            $enumType  = getNamedType($this->typeInfo->getInputType());\n            $enumValue = null;\n            if ($enumType instanceof EnumType) {\n                $enumValue = $enumType->getValue($node->getValue());\n            }\n            $this->typeInfo->setEnumValue($enumValue);\n        }\n\n        return $this->visitor->enterNode($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function leaveNode(NodeInterface $node): VisitorResult\n    {\n        $VisitorResult = $this->visitor->leaveNode($node);\n        $newNode       = $VisitorResult->getValue();\n\n        if ($newNode instanceof SelectionSetNode) {\n            $this->typeInfo->popParentType();\n        } elseif ($newNode instanceof FieldNode) {\n            $this->typeInfo->popFieldDefinition();\n            $this->typeInfo->popType();\n        } elseif ($newNode instanceof DirectiveNode) {\n            $this->typeInfo->setDirective(null);\n        } elseif ($newNode instanceof OperationDefinitionNode) {\n            $this->typeInfo->popType();\n        } elseif ($newNode instanceof InlineFragmentNode || $newNode instanceof FragmentDefinitionNode) {\n            $this->typeInfo->popType();\n        } elseif ($newNode instanceof VariableDefinitionNode) {\n            $this->typeInfo->popInputType();\n        } elseif ($newNode instanceof ArgumentNode) {\n            $this->typeInfo->setArgument(null);\n            $this->typeInfo->popDefaultValue();\n            $this->typeInfo->popInputType();\n        } elseif ($newNode instanceof ListValueNode) {\n            $this->typeInfo->popInputType();\n        } elseif ($newNode instanceof ObjectFieldNode) {\n            $this->typeInfo->popDefaultValue();\n            $this->typeInfo->popInputType();\n        } elseif ($newNode instanceof EnumValueNode) {\n            $this->typeInfo->setEnumValue(null);\n        }\n\n        return $VisitorResult;\n    }\n}\n"
  },
  {
    "path": "src/Language/Visitor/Visitor.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass Visitor implements VisitorInterface\n{\n    /**\n     * @var callable|null\n     */\n    protected $enterCallback;\n\n    /**\n     * @var callable|null\n     */\n    protected $leaveCallback;\n\n    /**\n     * Visitor constructor.\n     *\n     * @param callable|null $enterCallback\n     * @param callable|null $leaveCallback\n     */\n    public function __construct(?callable $enterCallback = null, ?callable $leaveCallback = null)\n    {\n        $this->enterCallback = $enterCallback;\n        $this->leaveCallback = $leaveCallback;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function enterNode(NodeInterface $node): VisitorResult\n    {\n        return null !== $this->enterCallback\n            ? \\call_user_func($this->enterCallback, $node)\n            : new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function leaveNode(NodeInterface $node): VisitorResult\n    {\n        return null !== $this->leaveCallback\n            ? \\call_user_func($this->leaveCallback, $node)\n            : new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Language/Visitor/VisitorBreak.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nclass VisitorBreak extends \\Exception\n{\n\n}\n"
  },
  {
    "path": "src/Language/Visitor/VisitorInfo.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass VisitorInfo\n{\n    /**\n     * @var VisitorInterface\n     */\n    protected $visitor;\n\n    /**\n     * @var string|int|null\n     */\n    protected $key;\n\n    /**\n     * @var NodeInterface|null\n     */\n    protected $parent;\n\n    /**\n     * @var array\n     */\n    protected $path;\n\n    /**\n     * @var array\n     */\n    protected $ancestors;\n\n    /**\n     * VisitorInfo constructor.\n     * @param VisitorInterface   $visitor\n     * @param int|null|string    $key\n     * @param NodeInterface|null $parent\n     * @param array              $path\n     * @param array              $ancestors\n     */\n    public function __construct(\n        VisitorInterface $visitor,\n        $key = null,\n        ?NodeInterface $parent = null,\n        array $path = [],\n        array $ancestors = []\n    ) {\n        $this->visitor   = $visitor;\n        $this->key       = $key;\n        $this->parent    = $parent;\n        $this->path      = $path;\n        $this->ancestors = $ancestors;\n    }\n\n    /**\n     * Appends a key to the path.\n     * @param string $key\n     */\n    public function addOneToPath(string $key)\n    {\n        $this->path[] = $key;\n    }\n\n    /**\n     * Removes the last item from the path.\n     */\n    public function removeOneFromPath()\n    {\n        $this->path = \\array_slice($this->path, 0, -1);\n    }\n\n    /**\n     * Adds an ancestor.\n     * @param NodeInterface $node\n     */\n    public function addAncestor(NodeInterface $node)\n    {\n        $this->ancestors[] = $node;\n    }\n\n    /**\n     *  Removes the last ancestor.\n     */\n    public function removeAncestor()\n    {\n        $this->ancestors = \\array_slice($this->ancestors, 0, -1);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getAncestor(int $depth = 1): ?NodeInterface\n    {\n        if (empty($this->ancestors)) {\n            return null;\n        }\n\n        $index = \\count($this->ancestors) - $depth;\n\n        return $this->ancestors[$index] ?? null;\n    }\n\n    /**\n     * @return VisitorInterface\n     */\n    public function getVisitor(): VisitorInterface\n    {\n        return $this->visitor;\n    }\n\n    /**\n     * @return int|null|string\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * @return NodeInterface|null\n     */\n    public function getParent(): ?NodeInterface\n    {\n        return $this->parent;\n    }\n\n    /**\n     * @return array\n     */\n    public function getPath(): array\n    {\n        return $this->path;\n    }\n\n    /**\n     * @return array\n     */\n    public function getAncestors(): array\n    {\n        return $this->ancestors;\n    }\n}\n"
  },
  {
    "path": "src/Language/Visitor/VisitorInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\ninterface VisitorInterface\n{\n    /**\n     * @param NodeInterface $node\n     * @return VisitorResult\n     */\n    public function enterNode(NodeInterface $node): VisitorResult;\n\n    /**\n     * @param NodeInterface $node\n     * @return VisitorResult\n     */\n    public function leaveNode(NodeInterface $node): VisitorResult;\n}\n"
  },
  {
    "path": "src/Language/Visitor/VisitorResult.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language\\Visitor;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass VisitorResult\n{\n\n    public const ACTION_NO_ACTION = 'NO_ACTION';\n    public const ACTION_BREAK     = 'BREAK';\n    public const ACTION_REPLACE   = 'REPLACE';\n\n    /**\n     * @var NodeInterface|null\n     */\n    protected $value;\n\n    /**\n     * @var string\n     */\n    protected $action;\n\n    /**\n     * @param NodeInterface|null $value\n     * @param string             $action\n     */\n    public function __construct(?NodeInterface $value = null, string $action = self::ACTION_NO_ACTION)\n    {\n        $this->value  = $value;\n        $this->action = $action;\n    }\n\n    /**\n     * @return NodeInterface|null\n     */\n    public function getValue(): ?NodeInterface\n    {\n        return $this->value;\n    }\n\n    /**\n     * @return string\n     */\n    public function getAction(): string\n    {\n        return $this->action;\n    }\n\n    /**\n     * @param string $action\n     * @return self\n     */\n    public function setAction(string $action): self\n    {\n        $this->action = $action;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Language/blockStringValue.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\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 * This implements the GraphQL spec's BlockStringValue() static algorithm.\n *\n * @param string $rawString\n * @return string\n */\nfunction blockStringValue(string $rawString): string\n{\n    $lines        = \\preg_split(\"/\\r\\n|[\\n\\r]/\", $rawString);\n    $lines        = false === $lines ? [] : $lines;\n    $lineCount    = \\count($lines);\n    $commonIndent = null;\n\n    for ($i = 1; $i < $lineCount; $i++) {\n        $line   = $lines[$i];\n        $indent = leadingWhitespace($line);\n\n        if ($indent < \\mb_strlen($line) && (null === $commonIndent || $indent < $commonIndent)) {\n            $commonIndent = $indent;\n\n            if ($commonIndent === 0) {\n                break;\n            }\n        }\n    }\n\n    if (null !== $commonIndent && $commonIndent > 0) {\n        for ($i = 1; $i < $lineCount; $i++) {\n            $lines[$i] = sliceString($lines[$i], $commonIndent);\n        }\n    }\n\n    while (\\count($lines) > 0 && isBlank($lines[0])) {\n        \\array_shift($lines);\n    }\n\n    while (($lineCount = \\count($lines)) > 0 && isBlank($lines[$lineCount - 1])) {\n        \\array_pop($lines);\n    }\n\n    return \\implode(\"\\n\", $lines);\n}\n\n/**\n * @param string $string\n * @return int\n */\nfunction leadingWhitespace(string $string): int\n{\n    $i      = 0;\n    $length = \\mb_strlen($string);\n\n    while ($i < $length && ($string[$i] === ' ' || $string[$i] === \"\\t\")) {\n        $i++;\n    }\n\n    return $i;\n}\n\n/**\n * @param string $string\n * @return bool\n */\nfunction isBlank(string $string): bool\n{\n    return leadingWhitespace($string) === \\mb_strlen($string);\n}\n"
  },
  {
    "path": "src/Language/utils.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Language;\n\nuse function Digia\\GraphQL\\Schema\\escapeQuotes;\n\n/**\n * @param int $code\n * @return string\n */\nfunction printCharCode(int $code): string\n{\n    if ($code === 0x0000) {\n        return '<EOF>';\n    }\n\n    return $code < 0x007F\n        // Trust JSON for ASCII.\n        ? \\json_encode(\\mb_chr($code, 'UTF-8'))\n        // Otherwise print the escaped form.\n        : '\"\\\\u' . \\dechex($code) . '\"';\n}\n\n/**\n * @param string   $string\n * @param int      $start\n * @param int|null $end\n * @return string\n */\nfunction sliceString(string $string, int $start, int $end = null): string\n{\n    $length = $end !== null ? $end - $start : \\mb_strlen($string) - $start;\n    return \\mb_substr($string, $start, $length);\n}\n\n/**\n * @param int $code\n * @return bool\n */\nfunction isLetter(int $code): bool\n{\n    return ($code >= 65 && $code <= 90) || ($code >= 97 && $code <= 122); // a-z or A-Z\n}\n\n/**\n * @param int $code\n * @return bool\n */\nfunction isNumber(int $code): bool\n{\n    return $code >= 48 && $code <= 57; // 0-9\n}\n\n/**\n * @param int $code\n * @return bool\n */\nfunction isUnderscore(int $code): bool\n{\n    return $code === 95; // _\n}\n\n/**\n * @param int $code\n * @return bool\n */\nfunction isAlphaNumeric(int $code): bool\n{\n    return isLetter($code) || isNumber($code) || isUnderscore($code);\n}\n\n/**\n * @param int $code\n * @return bool\n */\nfunction isLineTerminator(int $code): bool\n{\n    return $code === 0x000a || $code === 0x000d;\n}\n\n/**\n * @param int $code\n * @return bool\n */\nfunction isSourceCharacter(int $code): bool\n{\n    return $code < 0x0020 && $code !== 0x0009; // any source character EXCEPT HT (Horizontal Tab)\n}\n\n/**\n * @param string $value\n * @return bool\n */\nfunction isOperation(string $value): bool\n{\n    return $value === 'query' || $value === 'mutation' || $value === 'subscription';\n}\n\n/**\n * @param array $location\n * @return array|null\n */\nfunction locationShorthandToArray(array $location): ?array\n{\n    return isset($location[0], $location[1]) ? ['line' => $location[0], 'column' => $location[1]] : null;\n}\n\n/**\n * @param array $locations\n * @return array\n */\nfunction locationsShorthandToArray(array $locations): array\n{\n    return array_map(function ($shorthand) {\n        return locationShorthandToArray($shorthand);\n    }, $locations);\n}\n\n/**\n * @param array $array\n * @return string\n */\nfunction block(array $array): string\n{\n    return !empty($array) ? \"{\\n\" . indent(implode(\"\\n\", $array)) . \"\\n}\" : '';\n}\n\n/**\n * @param string      $start\n * @param null|string $maybeString\n * @param null|string $end\n * @return string\n */\nfunction wrap(string $start, ?string $maybeString = null, ?string $end = null): string\n{\n    return null !== $maybeString ? ($start . $maybeString . ($end ?? '')) : '';\n}\n\n/**\n * @param null|string $maybeString\n * @return string\n */\nfunction indent(?string $maybeString): string\n{\n    return null !== $maybeString ? '  ' . preg_replace(\"/\\n/\", \"\\n  \", $maybeString) : '';\n}\n\n/**\n * @param string $str\n * @return string\n */\nfunction dedent(string $str): string\n{\n    $trimmed = \\preg_replace(\"/^\\n*|[ \\t]*$/\", '', $str); // Remove leading newline and trailing whitespace\n    $matches = [];\n    \\preg_match(\"/^[ \\t]*/\", $trimmed, $matches); // Figure out indent\n    $indent = $matches[0];\n    return \\str_replace($indent, '', $trimmed); // Remove indent\n}\n\n/**\n * @param string $value\n * @param string $indentation\n * @param bool   $preferMultipleLines\n * @return string\n */\nfunction printBlockString(string $value, string $indentation = '', bool $preferMultipleLines = false): string {\n    $isSingleLine = false === \\strpos($value, \"\\n\");\n    $hasLeadingSpace = $value[0] === ' ' || $value[0] === \"\\t\";\n    $hasTrailingQuote = $value[\\strlen($value) - 1] === '\"';\n    $printAsMultipleLines = !$isSingleLine || $hasTrailingQuote || $preferMultipleLines;\n\n    $result = '';\n\n    // Format a multi-line block quote to account for leading space.\n    if ($printAsMultipleLines && !($isSingleLine && $hasLeadingSpace)) {\n        $result .= \"\\n\" . $indentation;\n    }\n\n    $result .= \\strlen($indentation) > 0\n        ? \\str_replace(\"\\n\", \"\\n\" . $indentation, $value)\n        : $value;\n\n    if ($printAsMultipleLines) {\n        $result .= \"\\n\";\n    }\n\n    return '\"\"\"' . escapeQuotes($result) . '\"\"\"';\n}\n"
  },
  {
    "path": "src/Schema/Building/BuildInfo.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\OperationTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\n\nclass BuildInfo\n{\n    /**\n     * @var DocumentNode\n     */\n    protected $document;\n\n    /**\n     * @var TypeNodeInterface[]\n     */\n    protected $typeDefinitionMap;\n\n    /**\n     * @var DirectiveDefinitionNode[]\n     */\n    protected $directiveDefinitions;\n\n    /**\n     * @var OperationTypeDefinitionNode[]\n     */\n    protected $operationTypeDefinitions;\n\n    /**\n     * @var SchemaDefinitionNode|null\n     */\n    protected $schemaDefinition;\n\n    /**\n     * BuildingInfo constructor.\n     * @param DocumentNode                  $document\n     * @param TypeNodeInterface[]           $typeDefinitionMap\n     * @param DirectiveDefinitionNode[]     $directiveDefinitions\n     * @param OperationTypeDefinitionNode[] $operationTypeDefinitions\n     * @param SchemaDefinitionNode|null     $schemaDefinition\n     */\n    public function __construct(\n        DocumentNode $document,\n        array $typeDefinitionMap,\n        array $directiveDefinitions,\n        array $operationTypeDefinitions,\n        ?SchemaDefinitionNode $schemaDefinition = null\n    ) {\n        $this->document                 = $document;\n        $this->typeDefinitionMap        = $typeDefinitionMap;\n        $this->directiveDefinitions     = $directiveDefinitions;\n        $this->operationTypeDefinitions = $operationTypeDefinitions;\n        $this->schemaDefinition         = $schemaDefinition;\n    }\n\n    /**\n     * @param string $typeName\n     * @return TypeNodeInterface|null\n     */\n    public function getTypeDefinition(string $typeName): ?TypeNodeInterface\n    {\n        return $this->typeDefinitionMap[$typeName] ?? null;\n    }\n\n    /**\n     * @param string $operation\n     * @return NodeInterface|null\n     */\n    public function getOperationTypeDefinition(string $operation): ?NodeInterface\n    {\n        // If we have a schema definition, see if it defines a type, if not we should return null.\n        // Otherwise, see if we there is a suitable type available in the type definition map.\n        return null !== $this->schemaDefinition\n            ? $this->operationTypeDefinitions[$operation] ?? null\n            : $this->typeDefinitionMap[\\ucfirst($operation)] ?? null;\n    }\n\n    /**\n     * @return DocumentNode\n     */\n    public function getDocument(): DocumentNode\n    {\n        return $this->document;\n    }\n\n    /**\n     * @return SchemaDefinitionNode|null\n     */\n    public function getSchemaDefinition(): ?SchemaDefinitionNode\n    {\n        return $this->schemaDefinition;\n    }\n\n    /**\n     * @return TypeNodeInterface[]\n     */\n    public function getTypeDefinitionMap(): array\n    {\n        return $this->typeDefinitionMap;\n    }\n\n    /**\n     * @return DirectiveDefinitionNode[]\n     */\n    public function getDirectiveDefinitions(): array\n    {\n        return $this->directiveDefinitions;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Building/BuildingContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeSystemDefinitionNodeInterface;\nuse Digia\\GraphQL\\Schema\\DefinitionBuilderInterface;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\Util\\arraySome;\n\nclass BuildingContext implements BuildingContextInterface\n{\n    /**\n     * @var ResolverRegistryInterface\n     */\n    protected $resolverRegistry;\n\n    /**\n     * @var DefinitionBuilderInterface\n     */\n    protected $definitionBuilder;\n\n    /**\n     * @var BuildInfo\n     */\n    protected $info;\n\n    /**\n     * BuilderContext constructor.\n     * @param ResolverRegistryInterface  $resolverRegistry\n     * @param DefinitionBuilderInterface $definitionBuilder\n     * @param BuildInfo                  $info\n     */\n    public function __construct(\n        ResolverRegistryInterface $resolverRegistry,\n        DefinitionBuilderInterface $definitionBuilder,\n        BuildInfo $info\n    ) {\n        $this->resolverRegistry  = $resolverRegistry;\n        $this->definitionBuilder = $definitionBuilder;\n        $this->info              = $info;\n    }\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function buildQueryType(): ?TypeInterface\n    {\n        $definition = $this->info->getOperationTypeDefinition('query');\n        return null !== $definition ? $this->definitionBuilder->buildType($definition) : null;\n    }\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function buildMutationType(): ?TypeInterface\n    {\n        $definition = $this->info->getOperationTypeDefinition('mutation');\n        return null !== $definition ? $this->definitionBuilder->buildType($definition) : null;\n    }\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function buildSubscriptionType(): ?TypeInterface\n    {\n        $definition = $this->info->getOperationTypeDefinition('subscription');\n        return null !== $definition ? $this->definitionBuilder->buildType($definition) : null;\n    }\n\n    /**\n     * @return TypeInterface[]\n     */\n    public function buildTypes(): array\n    {\n        return \\array_map(function (NamedTypeNodeInterface $definition) {\n            return $this->definitionBuilder->buildType($definition);\n        }, \\array_values($this->info->getTypeDefinitionMap()));\n    }\n\n    /**\n     * @return Directive[]\n     */\n    public function buildDirectives(): array\n    {\n        $directives = \\array_map(function (DirectiveDefinitionNode $definition) {\n            return $this->definitionBuilder->buildDirective($definition);\n        }, $this->info->getDirectiveDefinitions());\n\n        $specifiedDirectivesMap = [\n            'skip'       => SkipDirective(),\n            'include'    => IncludeDirective(),\n            'deprecated' => DeprecatedDirective(),\n        ];\n\n        foreach ($specifiedDirectivesMap as $name => $directive) {\n            if (!arraySome($directives, function (Directive $directive) use ($name) {\n                return $directive->getName() === $name;\n            })) {\n                $directives[] = $directive;\n            }\n        }\n\n        return $directives;\n    }\n\n    /**\n     * @return SchemaDefinitionNode|null\n     */\n    public function getSchemaDefinition(): ?SchemaDefinitionNode\n    {\n        return $this->info->getSchemaDefinition();\n    }\n}\n"
  },
  {
    "path": "src/Schema/Building/BuildingContextInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\ninterface BuildingContextInterface\n{\n    /**\n     * @return TypeInterface|null\n     */\n    public function buildQueryType(): ?TypeInterface;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function buildMutationType(): ?TypeInterface;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function buildSubscriptionType(): ?TypeInterface;\n\n    /**\n     * @return TypeInterface[]\n     */\n    public function buildTypes(): array;\n\n    /**\n     * @return Directive[]\n     */\n    public function buildDirectives(): array;\n\n    /**\n     * @return SchemaDefinitionNode|null\n     */\n    public function getSchemaDefinition(): ?SchemaDefinitionNode;\n}\n"
  },
  {
    "path": "src/Schema/Building/SchemaBuilder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeSystemDefinitionNodeInterface;\nuse Digia\\GraphQL\\Schema\\DefinitionBuilder;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse function Digia\\GraphQL\\Type\\newSchema;\n\nclass SchemaBuilder implements SchemaBuilderInterface\n{\n    /**\n     * @inheritdoc\n     */\n    public function build(\n        DocumentNode $document,\n        ResolverRegistryInterface $resolverRegistry,\n        array $options = []\n    ): Schema {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $context = $this->createContext($document, $resolverRegistry, $options);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newSchema([\n            'query'        => $context->buildQueryType(),\n            'mutation'     => $context->buildMutationType(),\n            'subscription' => $context->buildSubscriptionType(),\n            'types'        => $context->buildTypes(),\n            'directives'   => $context->buildDirectives(),\n            'astNode'      => $context->getSchemaDefinition(),\n            'assumeValid'  => $options['assumeValid'] ?? false,\n        ]);\n    }\n\n    /**\n     * @param DocumentNode              $document\n     * @param ResolverRegistryInterface $resolverRegistry\n     * @param array                     $options\n     * @return BuildingContextInterface\n     * @throws SchemaBuildingException\n     */\n    protected function createContext(\n        DocumentNode $document,\n        ResolverRegistryInterface $resolverRegistry,\n        array $options\n    ): BuildingContextInterface {\n        $info = $this->createInfo($document);\n\n        $definitionBuilder = new DefinitionBuilder(\n            $info->getTypeDefinitionMap(),\n            $resolverRegistry,\n            $options['types'] ?? [],\n            $options['directives'] ?? [],\n            null // use the default resolveType-function\n        );\n\n        return new BuildingContext($resolverRegistry, $definitionBuilder, $info);\n    }\n\n    /**\n     * @param DocumentNode $document\n     * @return BuildInfo\n     * @throws SchemaBuildingException\n     */\n    protected function createInfo(DocumentNode $document): BuildInfo\n    {\n        $schemaDefinition     = null;\n        $typeDefinitionMap    = [];\n        $directiveDefinitions = [];\n\n        foreach ($document->getDefinitions() as $definition) {\n            if ($definition instanceof SchemaDefinitionNode) {\n                if (null !== $schemaDefinition) {\n                    throw new SchemaBuildingException('Must provide only one schema definition.');\n                }\n\n                $schemaDefinition = $definition;\n\n                continue;\n            }\n\n            if ($definition instanceof DirectiveDefinitionNode) {\n                $directiveDefinitions[] = $definition;\n\n                continue;\n            }\n\n            if ($definition instanceof TypeSystemDefinitionNodeInterface && $definition instanceof NameAwareInterface) {\n                $typeName = $definition->getNameValue();\n\n                if (isset($typeDefinitionMap[$typeName])) {\n                    throw new SchemaBuildingException(\\sprintf('Type \"%s\" was defined more than once.', $typeName));\n                }\n\n                $typeDefinitionMap[$typeName] = $definition;\n\n                continue;\n            }\n        }\n\n        return new BuildInfo(\n            $document,\n            $typeDefinitionMap,\n            $directiveDefinitions,\n            null !== $schemaDefinition ? $this->getOperationTypeDefinitions($schemaDefinition, $typeDefinitionMap) : [],\n            $schemaDefinition\n        );\n    }\n\n    /**\n     * @param SchemaDefinitionNode $node\n     * @return array\n     * @throws SchemaBuildingException\n     */\n    protected function getOperationTypeDefinitions(SchemaDefinitionNode $node, array $typeDefinitionMap): array\n    {\n        $definitions = [];\n\n        foreach ($node->getOperationTypes() as $operationTypeDefinition) {\n            $operationType = $operationTypeDefinition->getType();\n\n            if (!$operationType instanceof NamedTypeNode) {\n                continue; // TODO: Throw exception?\n            }\n\n            $typeName  = $operationType->getNameValue();\n            $operation = $operationTypeDefinition->getOperation();\n\n            if (isset($definitions[$typeName])) {\n                throw new SchemaBuildingException(\n                    \\sprintf('Must provide only one %s type in schema.', $operation)\n                );\n            }\n\n            if (!isset($typeDefinitionMap[$typeName])) {\n                throw new SchemaBuildingException(\n                    \\sprintf('Specified %s type %s not found in document.', $operation, $typeName)\n                );\n            }\n\n            $definitions[$operation] = $operationType;\n\n        }\n\n        return $definitions;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Building/SchemaBuilderInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\n\ninterface SchemaBuilderInterface\n{\n    /**\n     * @param DocumentNode              $document\n     * @param ResolverRegistryInterface $resolverRegistry\n     * @param array                     $options\n     * @return Schema\n     */\n    public function build(\n        DocumentNode $document,\n        ResolverRegistryInterface $resolverRegistry,\n        array $options = []\n    ): Schema;\n}\n"
  },
  {
    "path": "src/Schema/Building/SchemaBuildingException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass SchemaBuildingException extends GraphQLException\n{\n}\n"
  },
  {
    "path": "src/Schema/Building/SchemaBuildingProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Building;\n\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass SchemaBuildingProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        SchemaBuilderInterface::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->add(SchemaBuilderInterface::class, SchemaBuilder::class);\n    }\n}\n"
  },
  {
    "path": "src/Schema/DefinitionBuilder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Execution\\ValuesResolver;\nuse Digia\\GraphQL\\Language\\LanguageException;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NonNullTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse Digia\\GraphQL\\Util\\ValueASTConverter;\nuse function Digia\\GraphQL\\Type\\introspectionTypes;\nuse function Digia\\GraphQL\\Type\\newDirective;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\nuse function Digia\\GraphQL\\Type\\specifiedScalarTypes;\nuse function Digia\\GraphQL\\Util\\keyMap;\nuse function Digia\\GraphQL\\Util\\keyValueMap;\n\nclass DefinitionBuilder implements DefinitionBuilderInterface\n{\n    /**\n     * @var NamedTypeNodeInterface[]\n     */\n    protected $typeDefinitionsMap;\n\n    /**\n     * @var ResolverRegistryInterface\n     */\n    protected $resolverRegistry;\n\n    /**\n     * @var callable\n     */\n    protected $resolveTypeFunction;\n\n    /**\n     * @var NamedTypeInterface[]\n     */\n    protected $types;\n\n    /**\n     * @var Directive[]\n     */\n    protected $directives;\n\n    /**\n     * DefinitionBuilder constructor.\n     * @param array                          $typeDefinitionsMap\n     * @param ResolverRegistryInterface|null $resolverRegistry\n     * @param array                          $types\n     * @param array                          $directives\n     * @param callable|null                  $resolveTypeCallback\n     */\n    public function __construct(\n        array $typeDefinitionsMap,\n        ?ResolverRegistryInterface $resolverRegistry = null,\n        array $types = [],\n        array $directives = [],\n        ?callable $resolveTypeCallback = null\n    ) {\n        $this->typeDefinitionsMap  = $typeDefinitionsMap;\n        $this->resolverRegistry    = $resolverRegistry;\n        $this->resolveTypeFunction = $resolveTypeCallback ?? [$this, 'defaultTypeResolver'];\n\n        $this->registerTypes($types);\n        $this->registerDirectives($directives);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function buildTypes(array $nodes): array\n    {\n        return \\array_map(function (NamedTypeNodeInterface $node) {\n            return $this->buildType($node);\n        }, $nodes);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function buildType(NamedTypeNodeInterface $node): NamedTypeInterface\n    {\n        $typeName = $node->getNameValue();\n\n        if (isset($this->types[$typeName])) {\n            return $this->types[$typeName];\n        }\n\n        if ($node instanceof NamedTypeNode) {\n            $definition = $this->getTypeDefinition($typeName);\n\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $type = null !== $definition\n                ? $this->buildNamedType($definition)\n                : $this->resolveType($node);\n        } else {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $type = $this->buildNamedType($node);\n        }\n\n        return $this->types[$typeName] = $type;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function buildDirective(DirectiveDefinitionNode $node): Directive\n    {\n        $directiveName = $node->getNameValue();\n\n        if (isset($this->directives[$directiveName])) {\n            return $this->directives[$directiveName];\n        }\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $directive = newDirective([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'locations'   => \\array_map(function (NameNode $node) {\n                return $node->getValue();\n            }, $node->getLocations()),\n            'args'        => $node->hasArguments() ? $this->buildArguments($node->getArguments()) : [],\n            'astNode'     => $node,\n        ]);\n\n        return $this->directives[$directiveName] = $directive;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function buildField($node, ?callable $resolve = null): array\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return [\n            'type'              => $this->buildWrappedType($node->getType()),\n            'description'       => $node->getDescriptionValue(),\n            'args'              => $node->hasArguments() ? $this->buildArguments($node->getArguments()) : [],\n            'deprecationReason' => $this->getDeprecationReason($node),\n            'resolve'           => $resolve,\n            'astNode'           => $node,\n        ];\n    }\n\n    /**\n     * @param TypeNodeInterface $typeNode\n     * @return TypeInterface\n     * @throws InvariantException\n     * @throws InvalidTypeException\n     */\n    protected function buildWrappedType(TypeNodeInterface $typeNode): TypeInterface\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $typeDefinition = $this->buildType($this->getNamedTypeNode($typeNode));\n        return $this->buildWrappedTypeRecursive($typeDefinition, $typeNode);\n    }\n\n    /**\n     * @param NamedTypeInterface $innerType\n     * @param TypeNodeInterface  $inputTypeNode\n     * @return TypeInterface\n     * @throws InvariantException\n     * @throws InvalidTypeException\n     */\n    protected function buildWrappedTypeRecursive(\n        NamedTypeInterface $innerType,\n        TypeNodeInterface $inputTypeNode\n    ): TypeInterface {\n        if ($inputTypeNode instanceof ListTypeNode) {\n            return newList($this->buildWrappedTypeRecursive($innerType, $inputTypeNode->getType()));\n        }\n\n        if ($inputTypeNode instanceof NonNullTypeNode) {\n            return newNonNull($this->buildWrappedTypeRecursive($innerType, $inputTypeNode->getType()));\n        }\n\n        return $innerType;\n    }\n\n    /**\n     * @param array $customTypes\n     */\n    protected function registerTypes(array $customTypes)\n    {\n        $typesMap = keyMap(\n            \\array_merge($customTypes, specifiedScalarTypes(), introspectionTypes()),\n            function (NamedTypeInterface $type) {\n                return $type->getName();\n            }\n        );\n\n        foreach ($typesMap as $typeName => $type) {\n            $this->types[$typeName] = $type;\n        }\n    }\n\n    /**\n     * @param array $customDirectives\n     */\n    protected function registerDirectives(array $customDirectives)\n    {\n        $directivesMap = keyMap(\n            \\array_merge($customDirectives, specifiedDirectives()),\n            function (Directive $directive) {\n                return $directive->getName();\n            }\n        );\n\n        foreach ($directivesMap as $directiveName => $directive) {\n            $this->directives[$directiveName] = $directive;\n        }\n    }\n\n    /**\n     * @param array $nodes\n     * @return array\n     */\n    protected function buildArguments(array $nodes): array\n    {\n        return keyValueMap(\n            $nodes,\n            function (InputValueDefinitionNode $value) {\n                return $value->getNameValue();\n            },\n            function (InputValueDefinitionNode $value): array {\n                $type         = $this->buildWrappedType($value->getType());\n                $defaultValue = $value->getDefaultValue();\n                return [\n                    'type'         => $type,\n                    'description'  => $value->getDescriptionValue(),\n                    'defaultValue' => null !== $defaultValue\n                        ? ValueASTConverter::convert($defaultValue, $type)\n                        : null,\n                    'astNode'      => $value,\n                ];\n            });\n    }\n\n    /**\n     * @param TypeNodeInterface $node\n     * @return NamedTypeInterface\n     * @throws LanguageException\n     */\n    protected function buildNamedType(TypeNodeInterface $node): NamedTypeInterface\n    {\n        if ($node instanceof ObjectTypeDefinitionNode) {\n            return $this->buildObjectType($node);\n        }\n        if ($node instanceof InterfaceTypeDefinitionNode) {\n            return $this->buildInterfaceType($node);\n        }\n        if ($node instanceof EnumTypeDefinitionNode) {\n            return $this->buildEnumType($node);\n        }\n        if ($node instanceof UnionTypeDefinitionNode) {\n            return $this->buildUnionType($node);\n        }\n        if ($node instanceof ScalarTypeDefinitionNode) {\n            return $this->buildScalarType($node);\n        }\n        if ($node instanceof InputObjectTypeDefinitionNode) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            return $this->buildInputObjectType($node);\n        }\n\n        throw new LanguageException(\\sprintf('Type kind \"%s\" not supported.', $node->getKind()));\n    }\n\n    /**\n     * @param ObjectTypeDefinitionNode $node\n     * @return ObjectType\n     */\n    protected function buildObjectType(ObjectTypeDefinitionNode $node): ObjectType\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newObjectType([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'fields'      => $node->hasFields() ? function () use ($node) {\n                return $this->buildFields($node);\n            } : [],\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            'interfaces'  => function () use ($node) {\n                return $node->hasInterfaces() ? \\array_map(function (NamedTypeNodeInterface $interface) {\n                    return $this->buildType($interface);\n                }, $node->getInterfaces()) : [];\n            },\n            'astNode'     => $node,\n        ]);\n    }\n\n    /**\n     * @param ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode|InputObjectTypeDefinitionNode $node\n     * @return array\n     */\n    protected function buildFields($node): array\n    {\n        return keyValueMap(\n            $node->getFields(),\n            function ($value) {\n                /** @var FieldDefinitionNode|InputValueDefinitionNode $value */\n                return $value->getNameValue();\n            },\n            function ($value) use ($node) {\n                /** @var FieldDefinitionNode|InputValueDefinitionNode $value */\n                return $this->buildField($value,\n                    $this->getFieldResolver($node->getNameValue(), $value->getNameValue()));\n            }\n        );\n    }\n\n    /**\n     * @param string $typeName\n     * @param string $fieldName\n     * @return callable|null\n     */\n    protected function getFieldResolver(string $typeName, string $fieldName): ?callable\n    {\n        return null !== $this->resolverRegistry\n            ? $this->resolverRegistry->getFieldResolver($typeName, $fieldName)\n            : null;\n    }\n\n    /**\n     * @param InterfaceTypeDefinitionNode $node\n     * @return InterfaceType\n     */\n    protected function buildInterfaceType(InterfaceTypeDefinitionNode $node): InterfaceType\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newInterfaceType([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'fields'      => $node->hasFields() ? function () use ($node): array {\n                return $this->buildFields($node);\n            } : [],\n            'resolveType' => $this->getTypeResolver($node->getNameValue()),\n            'astNode'     => $node,\n        ]);\n    }\n\n    /**\n     * @param EnumTypeDefinitionNode $node\n     * @return EnumType\n     */\n    protected function buildEnumType(EnumTypeDefinitionNode $node): EnumType\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newEnumType([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'values'      => $node->hasValues() ? keyValueMap(\n                $node->getValues(),\n                function (EnumValueDefinitionNode $value): ?string {\n                    return $value->getNameValue();\n                },\n                function (EnumValueDefinitionNode $value): array {\n                    return [\n                        'description'       => $value->getDescriptionValue(),\n                        'deprecationReason' => $this->getDeprecationReason($value),\n                        'astNode'           => $value,\n                    ];\n                }\n            ) : [],\n            'astNode'     => $node,\n        ]);\n    }\n\n    /**\n     * @param UnionTypeDefinitionNode $node\n     * @return UnionType\n     */\n    protected function buildUnionType(UnionTypeDefinitionNode $node): UnionType\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newUnionType([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'types'       => $node->hasTypes() ? \\array_map(function (NamedTypeNodeInterface $type) {\n                return $this->buildType($type);\n            }, $node->getTypes()) : [],\n            'resolveType' => $this->getTypeResolver($node->getNameValue()),\n            'astNode'     => $node,\n        ]);\n    }\n\n    /**\n     * @param string $typeName\n     * @return callable|null\n     */\n    protected function getTypeResolver(string $typeName): ?callable\n    {\n        return null !== $this->resolverRegistry\n            ? $this->resolverRegistry->getTypeResolver($typeName)\n            : null;\n    }\n\n    /**\n     * @param ScalarTypeDefinitionNode $node\n     * @return ScalarType\n     */\n    protected function buildScalarType(ScalarTypeDefinitionNode $node): ScalarType\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newScalarType([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'serialize'   => function ($value) {\n                return $value;\n            },\n            'astNode'     => $node,\n        ]);\n    }\n\n    /**\n     * @param InputObjectTypeDefinitionNode $node\n     * @return InputObjectType\n     * @throws InvariantException\n     */\n    protected function buildInputObjectType(InputObjectTypeDefinitionNode $node): InputObjectType\n    {\n        return newInputObjectType([\n            'name'        => $node->getNameValue(),\n            'description' => $node->getDescriptionValue(),\n            'fields'      => $node->hasFields() ? function () use ($node) {\n                return keyValueMap(\n                    $node->getFields(),\n                    function (InputValueDefinitionNode $value): ?string {\n                        return $value->getNameValue();\n                    },\n                    function (InputValueDefinitionNode $value): array {\n                        $type         = $this->buildWrappedType($value->getType());\n                        $defaultValue = $value->getDefaultValue();\n                        return [\n                            'type'         => $type,\n                            'description'  => $value->getDescriptionValue(),\n                            'defaultValue' => null !== $defaultValue\n                                ? ValueASTConverter::convert($defaultValue, $type)\n                                : null,\n                            'astNode'      => $value,\n                        ];\n                    }\n                );\n            } : [],\n            'astNode'     => $node,\n        ]);\n    }\n\n    /**\n     * @param NamedTypeNode $node\n     * @return NamedTypeInterface\n     */\n    protected function resolveType(NamedTypeNode $node): NamedTypeInterface\n    {\n        return \\call_user_func($this->resolveTypeFunction, $node);\n    }\n\n    /**\n     * @param NamedTypeNode $node\n     * @return NamedTypeInterface|null\n     */\n    public function defaultTypeResolver(NamedTypeNode $node): ?NamedTypeInterface\n    {\n        return $this->types[$node->getNameValue()] ?? null;\n    }\n\n    /**\n     * @param string $typeName\n     * @return NamedTypeNodeInterface|null\n     */\n    protected function getTypeDefinition(string $typeName): ?NamedTypeNodeInterface\n    {\n        return $this->typeDefinitionsMap[$typeName] ?? null;\n    }\n\n    /**\n     * @param TypeNodeInterface $typeNode\n     * @return NamedTypeNodeInterface\n     */\n    protected function getNamedTypeNode(TypeNodeInterface $typeNode): NamedTypeNodeInterface\n    {\n        $namedType = $typeNode;\n\n        while ($namedType instanceof ListTypeNode || $namedType instanceof NonNullTypeNode) {\n            $namedType = $namedType->getType();\n        }\n\n        /** @var NamedTypeNodeInterface $namedType */\n        return $namedType;\n    }\n\n    /**\n     * @param NodeInterface|EnumValueDefinitionNode|FieldDefinitionNode $node\n     * @return null|string\n     * @throws InvariantException\n     * @throws ExecutionException\n     */\n    protected function getDeprecationReason(NodeInterface $node): ?string\n    {\n        if (isset($this->directives['deprecated'])) {\n            $deprecated = ValuesResolver::coerceDirectiveValues($this->directives['deprecated'], $node);\n\n            return $deprecated['reason'] ?? null;\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/Schema/DefinitionBuilderInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\ninterface DefinitionBuilderInterface\n{\n    /**\n     * @param NodeInterface[] $nodes\n     * @return TypeInterface[]\n     */\n    public function buildTypes(array $nodes): array;\n\n    /**\n     * @param NamedTypeNodeInterface $node\n     * @return NamedTypeInterface\n     */\n    public function buildType(NamedTypeNodeInterface $node): NamedTypeInterface;\n\n    /**\n     * @param DirectiveDefinitionNode $node\n     * @return Directive\n     */\n    public function buildDirective(DirectiveDefinitionNode $node): Directive;\n\n    // TODO: Introduce an interface for FieldDefinitionNode and InputValueDefinitionNode\n\n    /**\n     * @param FieldDefinitionNode|InputValueDefinitionNode $node\n     * @param callable|null                                $resolve\n     * @return array\n     */\n    public function buildField($node, ?callable $resolve = null): array;\n}\n"
  },
  {
    "path": "src/Schema/DefinitionInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\n/**\n * Tagging interface for GraphQL definitions (schema, types, directive, etc.).\n */\ninterface DefinitionInterface\n{\n}\n"
  },
  {
    "path": "src/Schema/DefinitionPrinter.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\PrintException;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\DeprecationAwareInterface;\nuse Digia\\GraphQL\\Type\\Definition\\DescriptionAwareInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\EnumValue;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\InputField;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InputValueInterface;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse Digia\\GraphQL\\Util\\ValueConverter;\nuse function Digia\\GraphQL\\Language\\printBlockString;\nuse function Digia\\GraphQL\\printNode;\nuse function Digia\\GraphQL\\Type\\isIntrospectionType;\nuse function Digia\\GraphQL\\Type\\isSpecifiedScalarType;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Util\\arrayEvery;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass DefinitionPrinter implements DefinitionPrinterInterface\n{\n    /**\n     * @var array\n     */\n    protected $options;\n\n    /**\n     * @inheritdoc\n     * @throws PrintException\n     * @throws InvariantException\n     */\n    public function printSchema(Schema $schema, array $options = []): string\n    {\n        $this->options = $options;\n\n        return $this->printFilteredSchema(\n            $schema,\n            function (Directive $directive): bool {\n                return !isSpecifiedDirective($directive);\n            },\n            function (NamedTypeInterface $type): bool {\n                return !isSpecifiedScalarType($type) && !isIntrospectionType($type);\n            }\n        );\n    }\n\n    /**\n     * @inheritdoc\n     * @throws PrintException\n     * @throws InvariantException\n     */\n    public function printIntrospectionSchema(Schema $schema, array $options = []): string\n    {\n        $this->options = $options;\n\n        return $this->printFilteredSchema(\n            $schema,\n            function (Directive $directive): bool {\n                return isSpecifiedDirective($directive);\n            },\n            function (NamedTypeInterface $type): bool {\n                return isIntrospectionType($type);\n            }\n        );\n    }\n\n    /**\n     * @param DefinitionInterface $definition\n     * @return string\n     * @throws PrintException\n     * @throws InvariantException\n     */\n    public function print(DefinitionInterface $definition): string\n    {\n        if ($definition instanceof Schema) {\n            return $this->printSchemaDefinition($definition);\n        }\n\n        if ($definition instanceof Directive) {\n            return $this->printDirectiveDefinition($definition);\n        }\n\n        if ($definition instanceof NamedTypeInterface) {\n            return $this->printType($definition);\n        }\n\n        throw new PrintException(\\sprintf('Invalid definition object: %s.', toString($definition)));\n    }\n\n    /**\n     * @param Schema   $schema\n     * @param callable $directiveFilter\n     * @param callable $typeFilter\n     * @return string\n     * @throws PrintException\n     * @throws InvariantException\n     */\n    protected function printFilteredSchema(\n        Schema $schema,\n        callable $directiveFilter,\n        callable $typeFilter\n    ): string {\n        /** @noinspection PhpParamsInspection */\n        $lines = \\array_filter(\\array_merge(\n            [$this->printOne($schema)],\n            $this->printMany($this->getSchemaDirectives($schema, $directiveFilter)),\n            $this->printMany($this->getSchemaTypes($schema, $typeFilter))\n        ));\n\n        return printArray(\"\\n\\n\", $lines) . \"\\n\";\n    }\n\n    /**\n     * @param Schema   $schema\n     * @param callable $filter\n     * @return array\n     */\n    protected function getSchemaDirectives(Schema $schema, callable $filter): array\n    {\n        return \\array_filter($schema->getDirectives(), $filter);\n    }\n\n    /**\n     * @param Schema   $schema\n     * @param callable $filter\n     * @return array\n     */\n    protected function getSchemaTypes(Schema $schema, callable $filter): array\n    {\n        $types = \\array_filter(\\array_values($schema->getTypeMap()), $filter);\n\n        \\usort($types, function (NamedTypeInterface $typeA, NamedTypeInterface $typeB) {\n            return \\strcasecmp($typeA->getName(), $typeB->getName());\n        });\n\n        return $types;\n    }\n\n    /**\n     * @param Schema $definition\n     * @return string\n     */\n    protected function printSchemaDefinition(Schema $definition): string\n    {\n        if ($this->isSchemaOfCommonNames($definition)) {\n            return '';\n        }\n\n        $operationTypes = [];\n\n        if (null !== ($queryType = $definition->getQueryType())) {\n            $operationTypes[] = \"  query: {$queryType->getName()}\";\n        }\n\n        if (null !== ($mutationType = $definition->getMutationType())) {\n            $operationTypes[] = \"  mutation: {$mutationType->getName()}\";\n        }\n\n        if (null !== ($subscriptionType = $definition->getSubscriptionType())) {\n            $operationTypes[] = \"  subscription: {$subscriptionType->getName()}\";\n        }\n\n        return printLines([\n            'schema {',\n            printLines($operationTypes),\n            '}'\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     *     subscription: Subscription\n     *   }\n     *\n     * When using this naming convention, the schema description can be omitted.\n     *\n     * @param Schema $schema\n     * @return bool\n     */\n    protected function isSchemaOfCommonNames(Schema $schema): bool\n    {\n        if (null !== ($queryType = $schema->getQueryType()) &&\n            $queryType->getName() !== 'Query') {\n            return false;\n        }\n\n        if (null !== ($mutationType = $schema->getMutationType()) &&\n            $mutationType->getName() !== 'Mutation') {\n            return false;\n        }\n\n        if (null !== ($subscriptionType = $schema->getSubscriptionType()) &&\n            $subscriptionType->getName() !== 'Subscription') {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * @param Directive $directive\n     * @return string\n     */\n    public function printDirectiveDefinition(Directive $directive): string\n    {\n        $description = $this->printDescription($directive);\n        $name        = $directive->getName();\n        $arguments   = $this->printArguments($directive->getArguments());\n        $locations   = implode(' | ', $directive->getLocations());\n\n        return printLines([\n            $description,\n            \"directive @{$name}{$arguments} on {$locations}\",\n        ]);\n    }\n\n    /**\n     * @param NamedTypeInterface $type\n     * @return string\n     * @throws PrintException\n     * @throws InvariantException\n     */\n    protected function printType(NamedTypeInterface $type): string\n    {\n        if ($type instanceof ScalarType) {\n            return $this->printScalarType($type);\n        }\n        if ($type instanceof ObjectType) {\n            return $this->printObjectType($type);\n        }\n        if ($type instanceof InterfaceType) {\n            return $this->printInterfaceType($type);\n        }\n        if ($type instanceof UnionType) {\n            return $this->printUnionType($type);\n        }\n        if ($type instanceof EnumType) {\n            return $this->printEnumType($type);\n        }\n        if ($type instanceof InputObjectType) {\n            return $this->printInputObjectType($type);\n        }\n\n        throw new PrintException(\\sprintf('Unknown type: %s', (string)$type));\n    }\n\n    /**\n     * @param ScalarType $type\n     * @return string\n     */\n    protected function printScalarType(ScalarType $type): string\n    {\n        return printLines([\n            $this->printDescription($type),\n            \"scalar {$type->getName()}\"\n        ]);\n    }\n\n    /**\n     * @param ObjectType $type\n     * @return string\n     * @throws InvariantException\n     */\n    protected function printObjectType(ObjectType $type): string\n    {\n        $description = $this->printDescription($type);\n        $name        = $type->getName();\n        $implements  = $type->hasInterfaces()\n            ? ' implements ' . printArray(' & ', \\array_map(function (InterfaceType $interface) {\n                return $interface->getName();\n            }, $type->getInterfaces()))\n            : '';\n        $fields      = $this->printFields($type->getFields());\n\n        return printLines([\n            $description,\n            \"type {$name}{$implements} {\",\n            $fields,\n            '}'\n        ]);\n    }\n\n    /**\n     * @param InterfaceType $type\n     * @return string\n     * @throws InvariantException\n     */\n    protected function printInterfaceType(InterfaceType $type): string\n    {\n        $description = $this->printDescription($type);\n        $fields      = $this->printFields($type->getFields());\n\n        return printLines([\n            $description,\n            \"interface {$type->getName()} {\",\n            $fields,\n            '}'\n        ]);\n    }\n\n    /**\n     * @param UnionType $type\n     * @return string\n     * @throws InvariantException\n     */\n    protected function printUnionType(UnionType $type): string\n    {\n        $description = $this->printDescription($type);\n        $types       = printArray(' | ', $type->getTypes());\n\n        return printLines([\n            $description,\n            \"union {$type->getName()} = {$types}\"\n        ]);\n    }\n\n    /**\n     * @param EnumType $type\n     * @return string\n     * @throws InvariantException\n     */\n    protected function printEnumType(EnumType $type): string\n    {\n        $description = $this->printDescription($type);\n        $values      = $this->printEnumValues($type->getValues());\n\n        return printLines([\n            $description,\n            \"enum {$type->getName()} {\",\n            $values,\n            '}'\n        ]);\n    }\n\n    /**\n     * @param array $values\n     * @return string\n     */\n    protected function printEnumValues(array $values): string\n    {\n        // The first item is always the first in block, all item after that are not.\n        // This is important for getting the linebreaks correct between the items.\n        $firstInBlock = true;\n\n        return printLines(\\array_map(function (EnumValue $value) use (&$firstInBlock): string {\n            $description  = $this->printDescription($value, '  ', $firstInBlock);\n            $name         = $value->getName();\n            $deprecated   = $this->printDeprecated($value);\n            $enum         = empty($deprecated) ? $name : \"{$name} {$deprecated}\";\n            $firstInBlock = false;\n\n            return printLines([\n                $description,\n                \"  {$enum}\"\n            ]);\n        }, $values));\n    }\n\n    /**\n     * @param InputObjectType $type\n     * @return string\n     * @throws InvariantException\n     */\n    protected function printInputObjectType(InputObjectType $type): string\n    {\n        $description = $this->printDescription($type);\n        $fields      = \\array_map(function (InputField $field): string {\n            $description = $this->printDescription($field, '  ');\n            $inputValue  = $this->printInputValue($field);\n            return printLines([\n                $description,\n                \"  {$inputValue}\"\n            ]);\n        }, \\array_values($type->getFields()));\n\n        return printLines([\n            $description,\n            \"input {$type->getName()} {\",\n            printLines($fields),\n            '}'\n        ]);\n    }\n\n    /**\n     * @param InputValueInterface $inputValue\n     * @return string\n     * @throws InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     * @throws \\Digia\\GraphQL\\Util\\ConversionException\n     */\n    protected function printInputValue(InputValueInterface $inputValue): string\n    {\n        $type = $inputValue->getType();\n        $name = $inputValue->getName();\n\n        $defaultValue = $inputValue->hasDefaultValue()\n            ? printNode(ValueConverter::convert($inputValue->getDefaultValue(), $type))\n            : null;\n\n        return null !== $defaultValue\n            ? \"{$name}: {$type} = {$defaultValue}\"\n            : \"{$name}: {$type}\";\n    }\n\n    /**\n     * @param array $fields\n     * @return string\n     */\n    protected function printFields(array $fields): string\n    {\n        // The first item is always the first in block, all item after that are not.\n        // This is important for getting the linebreaks correct between the items.\n        $firstInBlock = true;\n\n        return printLines(\\array_map(function (Field $field) use (&$firstInBlock): string {\n            $description  = $this->printDescription($field, '  ', $firstInBlock);\n            $name         = $field->getName();\n            $arguments    = $this->printArguments($field->getArguments());\n            $type         = (string)$field->getType();\n            $deprecated   = $this->printDeprecated($field);\n            $firstInBlock = false;\n\n            return printLines([\n                $description,\n                \"  {$name}{$arguments}: {$type}{$deprecated}\"\n            ]);\n        }, $fields));\n    }\n\n    /**\n     * @param array  $arguments\n     * @param string $indentation\n     * @return string\n     */\n    protected function printArguments(array $arguments, string $indentation = ''): string\n    {\n        if (empty($arguments)) {\n            return '';\n        }\n\n        // If every arg does not have a description, print them on one line.\n        if (arrayEvery($arguments, function (Argument $argument): bool {\n            return !$argument->hasDescription();\n        })) {\n            return printInputFields(\\array_map(function (Argument $argument) {\n                return $this->printInputValue($argument);\n            }, $arguments));\n        }\n\n        $args = \\array_map(function (Argument $argument) use ($indentation) {\n            $description = $this->printDescription($argument, '  ');\n            $inputValue  = $this->printInputValue($argument);\n            return printLines([\n                \"{$indentation}{$description}\",\n                \"  {$indentation}{$inputValue}\"\n            ]);\n        }, $arguments);\n\n        return printLines([\n            '(',\n            \\implode(\", \", $args),\n            $indentation . ')'\n        ]);\n    }\n\n    /**\n     * @param DeprecationAwareInterface $fieldOrEnumValue\n     * @return string\n     * @throws InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     * @throws \\Digia\\GraphQL\\Util\\ConversionException\n     */\n    protected function printDeprecated(DeprecationAwareInterface $fieldOrEnumValue): string\n    {\n        if (!$fieldOrEnumValue->isDeprecated()) {\n            return '';\n        }\n\n        $reason = $fieldOrEnumValue->getDeprecationReason();\n\n        if (null === $reason || '' === $reason || DEFAULT_DEPRECATION_REASON === $reason) {\n            return '@deprecated';\n        }\n\n        $reasonValue = printNode(ValueConverter::convert($reason, stringType()));\n\n        return \"@deprecated(reason: {$reasonValue})\";\n    }\n\n    /**\n     * @param DescriptionAwareInterface $definition\n     * @param string                    $indentation\n     * @param bool                      $isFirstInBlock\n     * @return string\n     */\n    protected function printDescription(\n        DescriptionAwareInterface $definition,\n        string $indentation = '',\n        bool $isFirstInBlock = true\n    ): string {\n        // Don't print anything if the type has no description\n        if ($definition->getDescription() === null) {\n            return '';\n        }\n\n        $lines = descriptionLines($definition->getDescription(), 120 - \\strlen($indentation));\n\n        if (isset($this->options['commentDescriptions']) && true === $this->options['commentDescriptions']) {\n            return $this->printDescriptionWithComments($lines, $indentation, $isFirstInBlock);\n        }\n\n        $text                = \\implode(\"\\n\", $lines);\n        $preferMultipleLines = \\strlen($text) > 70;\n        $blockString         = printBlockString($text, '', $preferMultipleLines);\n        $prefix              = strlen($indentation) > 0 && !$isFirstInBlock ? \"\\n\" . $indentation : $indentation;\n\n        return $prefix . \\str_replace(\"\\n\", \"\\n\" . $indentation, $blockString);\n    }\n\n    /**\n     * @param array  $lines\n     * @param string $indentation\n     * @param bool   $isFirstInBlock\n     * @return string\n     */\n    protected function printDescriptionWithComments(array $lines, string $indentation, bool $isFirstInBlock): string\n    {\n        $description = \\strlen($indentation) > 0 && !$isFirstInBlock ? \"\\n\" : '';\n        $linesCount  = \\count($lines);\n\n        for ($i = 0; $i < $linesCount; $i++) {\n            $description .= $lines[$i] === ''\n                ? $indentation . '#' . \"\\n\"\n                : $indentation . '# ' . $lines[$i] . \"\\n\";\n        }\n\n        return $description;\n    }\n\n    /**\n     * @param DefinitionInterface $definition\n     * @return string\n     * @throws PrintException\n     * @throws InvariantException\n     */\n    protected function printOne(DefinitionInterface $definition): string\n    {\n        return $this->print($definition);\n    }\n\n    /**\n     * @param DefinitionInterface[] $definitions\n     * @return array\n     */\n    protected function printMany(array $definitions): array\n    {\n        return \\array_map(function ($definition) {\n            return $this->print($definition);\n        }, $definitions);\n    }\n}\n"
  },
  {
    "path": "src/Schema/DefinitionPrinterInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\ninterface DefinitionPrinterInterface\n{\n    /**\n     * Prints a schema.\n     *\n     * Accepts options as a second argument:\n     *\n     *    - commentDescriptions:\n     *        Provide true to use preceding comments as the description.\n     *\n     * @param Schema $schema\n     * @param array  $options\n     * @return string\n     */\n    public function printSchema(Schema $schema, array $options = []): string;\n\n    /**\n     * Prints an introspection schema.\n     *\n     * Accepts options as a second argument:\n     *\n     *    - commentDescriptions:\n     *        Provide true to use preceding comments as the description.\n     *\n     * @param Schema $schema\n     * @param array  $options\n     * @return string\n     */\n    public function printIntrospectionSchema(Schema $schema, array $options = []): string;\n\n    /**\n     * Prints a GraphQL definition.\n     *\n     * Accepts options as a second argument:\n     *\n     *    - commentDescriptions:\n     *        Provide true to use preceding comments as the description.\n     *\n     * @param DefinitionInterface $definition\n     * @return string\n     */\n    public function print(DefinitionInterface $definition): string;\n}\n"
  },
  {
    "path": "src/Schema/Extension/ExtendInfo.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeSystemDefinitionNodeInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\n\nclass ExtendInfo\n{\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @var DocumentNode\n     */\n    protected $document;\n\n    /**\n     * @var TypeSystemDefinitionNodeInterface[]\n     */\n    protected $typeDefinitionMap;\n\n    /**\n     * @var InterfaceTypeExtensionNode[][]|ObjectTypeExtensionNode[][]\n     */\n    protected $typeExtensionsMap;\n\n    /**\n     * @var DirectiveDefinitionNode[]\n     */\n    protected $directiveDefinitions;\n\n    /**\n     * @var SchemaExtensionNode[]\n     */\n    protected $schemaExtensions;\n\n    /**\n     * ExtensionInfo constructor.\n     * @param Schema                                                     $schema\n     * @param DocumentNode                                               $document\n     * @param TypeSystemDefinitionNodeInterface[]                        $typeDefinitionMap\n     * @param InterfaceTypeExtensionNode[][]|ObjectTypeExtensionNode[][] $typeExtensionsMap\n     * @param DirectiveDefinitionNode[]                                  $directiveDefinitions\n     * @param SchemaExtensionNode[]                                      $schemaExtensions\n     */\n    public function __construct(\n        Schema $schema,\n        DocumentNode $document,\n        array $typeDefinitionMap,\n        array $typeExtensionsMap,\n        array $directiveDefinitions,\n        array $schemaExtensions\n    ) {\n        $this->schema               = $schema;\n        $this->document             = $document;\n        $this->typeDefinitionMap    = $typeDefinitionMap;\n        $this->typeExtensionsMap    = $typeExtensionsMap;\n        $this->directiveDefinitions = $directiveDefinitions;\n        $this->schemaExtensions     = $schemaExtensions;\n    }\n\n    /**\n     * @param string $typeName\n     * @return bool\n     */\n    public function hasTypeExtensions(string $typeName): bool\n    {\n        return isset($this->typeExtensionsMap[$typeName]);\n    }\n\n    /**\n     * @param string $typeName\n     * @return ObjectTypeExtensionNode[]|InterfaceTypeExtensionNode[]\n     */\n    public function getTypeExtensions(string $typeName): array\n    {\n        return $this->typeExtensionsMap[$typeName] ?? [];\n    }\n\n    /**\n     * @return Schema\n     */\n    public function getSchema(): Schema\n    {\n        return $this->schema;\n    }\n\n    /**\n     * @return DocumentNode\n     */\n    public function getDocument(): DocumentNode\n    {\n        return $this->document;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasTypeDefinitionMap(): bool\n    {\n        return !empty($this->typeDefinitionMap);\n    }\n\n    /**\n     * @return TypeSystemDefinitionNodeInterface[]\n     */\n    public function getTypeDefinitionMap(): array\n    {\n        return $this->typeDefinitionMap;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasTypeExtensionsMap(): bool\n    {\n        return !empty($this->typeExtensionsMap);\n    }\n\n    /**\n     * @return InterfaceTypeExtensionNode[][]|ObjectTypeExtensionNode[][]\n     */\n    public function getTypeExtensionsMap()\n    {\n        return $this->typeExtensionsMap;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasDirectiveDefinitions(): bool\n    {\n        return !empty($this->directiveDefinitions);\n    }\n\n    /**\n     * @return DirectiveDefinitionNode[]\n     */\n    public function getDirectiveDefinitions(): array\n    {\n        return $this->directiveDefinitions;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasSchemaExtensions(): bool\n    {\n        return !empty($this->schemaExtensions);\n    }\n\n    /**\n     * @return SchemaExtensionNode[]\n     */\n    public function getSchemaExtensions(): array\n    {\n        return $this->schemaExtensions;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Extension/ExtensionContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Schema\\DefinitionBuilderInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\FieldsAwareInterface;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse function Digia\\GraphQL\\Type\\isIntrospectionType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\n\nclass ExtensionContext implements ExtensionContextInterface\n{\n    /**\n     * @var ExtendInfo\n     */\n    protected $info;\n\n    /**\n     * @var DefinitionBuilderInterface\n     */\n    protected $definitionBuilder;\n\n    /**\n     * @var TypeInterface[]\n     */\n    protected $extendTypeCache = [];\n\n    /**\n     * ExtensionContext constructor.\n     * @param ExtendInfo $info\n     */\n    public function __construct(ExtendInfo $info)\n    {\n        $this->info = $info;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isSchemaExtended(): bool\n    {\n        return\n            $this->info->hasTypeExtensionsMap() ||\n            $this->info->hasTypeDefinitionMap() ||\n            $this->info->hasDirectiveDefinitions() ||\n            $this->info->hasSchemaExtensions();\n    }\n\n    /**\n     * @return ObjectType[]\n     * @throws SchemaExtensionException\n     * @throws InvariantException\n     */\n    public function getExtendedOperationTypes(): array\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $operationTypes = [\n            'query'        => $this->getExtendedQueryType(),\n            'mutation'     => $this->getExtendedMutationType(),\n            'subscription' => $this->getExtendedSubscriptionType(),\n        ];\n\n        foreach ($this->info->getSchemaExtensions() as $schemaExtension) {\n            foreach ($schemaExtension->getOperationTypes() as $operationType) {\n                $operation = $operationType->getOperation();\n\n                if (isset($operationTypes[$operation])) {\n                    throw new SchemaExtensionException(\\sprintf('Must provide only one %s type in schema.', $operation));\n                }\n\n                $operationTypes[$operation] = $this->definitionBuilder->buildType($operationType->getType());\n            }\n        }\n\n        return $operationTypes;\n    }\n\n    /**\n     * @return TypeInterface|null\n     * @throws InvariantException\n     */\n    protected function getExtendedQueryType(): ?TypeInterface\n    {\n        $existingQueryType = $this->info->getSchema()->getQueryType();\n\n        return null !== $existingQueryType\n            ? $this->getExtendedType($existingQueryType)\n            : null;\n    }\n\n    /**\n     * @return TypeInterface|null\n     * @throws InvariantException\n     */\n    protected function getExtendedMutationType(): ?TypeInterface\n    {\n        $existingMutationType = $this->info->getSchema()->getMutationType();\n\n        return null !== $existingMutationType\n            ? $this->getExtendedType($existingMutationType)\n            : null;\n    }\n\n    /**\n     * @return TypeInterface|null\n     * @throws InvariantException\n     */\n    protected function getExtendedSubscriptionType(): ?TypeInterface\n    {\n        $existingSubscriptionType = $this->info->getSchema()->getSubscriptionType();\n\n        return null !== $existingSubscriptionType\n            ? $this->getExtendedType($existingSubscriptionType)\n            : null;\n    }\n\n    /**\n     * @return TypeInterface[]\n     */\n    public function getExtendedTypes(): array\n    {\n        $extendedTypes = \\array_map(function ($type) {\n            return $this->getExtendedType($type);\n        }, $this->info->getSchema()->getTypeMap());\n\n        return \\array_merge(\n            $extendedTypes,\n            $this->definitionBuilder->buildTypes($this->info->getTypeDefinitionMap())\n        );\n    }\n\n    /**\n     * @return Directive[]\n     * @throws InvariantException\n     */\n    public function getExtendedDirectives(): array\n    {\n        $existingDirectives = $this->info->getSchema()->getDirectives();\n\n        if (empty($existingDirectives)) {\n            throw new InvariantException('schema must have default directives');\n        }\n\n        return \\array_merge(\n            $existingDirectives,\n            \\array_map(function (DirectiveDefinitionNode $node) {\n                return $this->definitionBuilder->buildDirective($node);\n            }, $this->info->getDirectiveDefinitions())\n        );\n    }\n\n    /**\n     * @param DefinitionBuilderInterface $definitionBuilder\n     * @return ExtensionContext\n     */\n    public function setDefinitionBuilder(DefinitionBuilderInterface $definitionBuilder): ExtensionContext\n    {\n        $this->definitionBuilder = $definitionBuilder;\n        return $this;\n    }\n\n    /**\n     * @param NamedTypeNode $node\n     * @return TypeInterface|null\n     * @throws SchemaExtensionException\n     * @throws InvariantException\n     */\n    public function resolveType(NamedTypeNode $node): ?TypeInterface\n    {\n        $typeName     = $node->getNameValue();\n        $existingType = $this->info->getSchema()->getType($typeName);\n\n        if ($existingType instanceof NamedTypeInterface) {\n            return $this->getExtendedType($existingType);\n        }\n\n        throw new SchemaExtensionException(\n            \\sprintf(\n                'Unknown type: \"%s\". Ensure that this type exists ' .\n                'either in the original schema, or is added in a type definition.',\n                $typeName\n            ),\n            [$node]\n        );\n    }\n\n    /**\n     * @param NamedTypeInterface $type\n     * @return TypeInterface\n     * @throws InvariantException\n     */\n    protected function getExtendedType(NamedTypeInterface $type): TypeInterface\n    {\n        $typeName = $type->getName();\n\n        if (isset($this->extendTypeCache[$typeName])) {\n            return $this->extendTypeCache[$typeName];\n        }\n\n        return $this->extendTypeCache[$typeName] = $this->extendType($type);\n    }\n\n    /**\n     * @param TypeInterface $type\n     * @return TypeInterface\n     * @throws InvariantException\n     */\n    protected function extendType(TypeInterface $type): TypeInterface\n    {\n        /** @noinspection PhpParamsInspection */\n        if (isIntrospectionType($type)) {\n            // Introspection types are not extended.\n            return $type;\n        }\n\n        if ($type instanceof ObjectType) {\n            return $this->extendObjectType($type);\n        }\n\n        if ($type instanceof InterfaceType) {\n            return $this->extendInterfaceType($type);\n        }\n\n        if ($type instanceof UnionType) {\n            return $this->extendUnionType($type);\n        }\n\n        // This type is not yet extendable.\n        return $type;\n    }\n\n    /**\n     * @param ObjectType $type\n     * @return ObjectType\n     * @throws InvariantException\n     */\n    protected function extendObjectType(ObjectType $type): ObjectType\n    {\n        $typeName          = $type->getName();\n        $extensionASTNodes = $type->getExtensionAstNodes();\n\n        if ($this->info->hasTypeExtensions($typeName)) {\n            $extensionASTNodes = $this->extendExtensionASTNodes($typeName, $extensionASTNodes);\n        }\n\n        return newObjectType([\n            'name'              => $typeName,\n            'description'       => $type->getDescription(),\n            'interfaces'        => function () use ($type) {\n                return $this->extendImplementedInterfaces($type);\n            },\n            'fields'            => function () use ($type) {\n                return $this->extendFieldMap($type);\n            },\n            'astNode'           => $type->getAstNode(),\n            'extensionASTNodes' => $extensionASTNodes,\n            'isTypeOf'          => $type->getIsTypeOfCallback(),\n        ]);\n    }\n\n    /**\n     * @param InterfaceType $type\n     * @return InterfaceType\n     * @throws InvariantException\n     */\n    protected function extendInterfaceType(InterfaceType $type): InterfaceType\n    {\n        $typeName          = $type->getName();\n        $extensionASTNodes = $this->info->getTypeExtensions($typeName);\n\n        if ($this->info->hasTypeExtensions($typeName)) {\n            $extensionASTNodes = $this->extendExtensionASTNodes($typeName, $extensionASTNodes);\n        }\n\n        return newInterfaceType([\n            'name'              => $typeName,\n            'description'       => $type->getDescription(),\n            'fields'            => function () use ($type) {\n                return $this->extendFieldMap($type);\n            },\n            'astNode'           => $type->getAstNode(),\n            'extensionASTNodes' => $extensionASTNodes,\n            'resolveType'       => $type->getResolveTypeCallback(),\n        ]);\n    }\n\n    /**\n     * @param string $typeName\n     * @param array  $nodes\n     * @return array\n     */\n    protected function extendExtensionASTNodes(string $typeName, array $nodes): array\n    {\n        $typeExtensions = $this->info->getTypeExtensions($typeName);\n        return !empty($nodes) ? \\array_merge($typeExtensions, $nodes) : $typeExtensions;\n    }\n\n    /**\n     * @param UnionType $type\n     * @return UnionType\n     * @throws InvariantException\n     */\n    protected function extendUnionType(UnionType $type): UnionType\n    {\n        return newUnionType([\n            'name'        => $type->getName(),\n            'description' => $type->getDescription(),\n            'types'       => \\array_map(function ($unionType) {\n                return $this->getExtendedType($unionType);\n            }, $type->getTypes()),\n            'astNode'     => $type->getAstNode(),\n            'resolveType' => $type->getResolveTypeCallback(),\n        ]);\n    }\n\n    /**\n     * @param ObjectType $type\n     * @return array\n     * @throws InvariantException\n     */\n    protected function extendImplementedInterfaces(ObjectType $type): array\n    {\n        $typeName = $type->getName();\n\n        $interfaces = \\array_map(function (InterfaceType $interface) {\n            return $this->getExtendedType($interface);\n        }, $type->getInterfaces());\n\n        // If there are any extensions to the interfaces, apply those here.\n        $extensions = $this->info->getTypeExtensions($typeName);\n\n        foreach ($extensions as $extension) {\n            foreach ($extension->getInterfaces() as $namedType) {\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                $interfaces[] = $this->definitionBuilder->buildType($namedType);\n            }\n        }\n\n        return $interfaces;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @return array\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws SchemaExtensionException\n     */\n    protected function extendFieldMap(FieldsAwareInterface $type): array\n    {\n        $typeName    = $type->getName();\n        $newFieldMap = [];\n        $oldFieldMap = $type->getFields();\n\n        foreach (\\array_keys($oldFieldMap) as $fieldName) {\n            $field = $oldFieldMap[$fieldName];\n\n            $newFieldMap[$fieldName] = [\n                'description'       => $field->getDescription(),\n                'deprecationReason' => $field->getDeprecationReason(),\n                'type'              => $this->extendFieldType($field->getType()),\n                'args'              => $field->getRawArguments(),\n                'astNode'           => $field->getAstNode(),\n                'resolve'           => $field->getResolveCallback(),\n            ];\n        }\n\n        // If there are any extensions to the fields, apply those here.\n        $extensions = $this->info->getTypeExtensions($typeName);\n\n        foreach ($extensions as $extension) {\n            foreach ($extension->getFields() as $field) {\n                $fieldName = $field->getNameValue();\n\n                if (isset($oldFieldMap[$fieldName])) {\n                    throw new SchemaExtensionException(\n                        \\sprintf(\n                            'Field \"%s.%s\" already exists in the schema. ' .\n                            'It cannot also be defined in this type extension.',\n                            $typeName, $fieldName\n                        ),\n                        [$field]\n                    );\n                }\n\n                $newFieldMap[$fieldName] = $this->definitionBuilder->buildField($field);\n            }\n        }\n\n        return $newFieldMap;\n    }\n\n    /**\n     * @param TypeInterface $typeDefinition\n     * @return TypeInterface\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function extendFieldType(TypeInterface $typeDefinition): TypeInterface\n    {\n        if ($typeDefinition instanceof ListType) {\n            return newList($this->extendFieldType($typeDefinition->getOfType()));\n        }\n\n        if ($typeDefinition instanceof NonNullType) {\n            return newNonNull($this->extendFieldType($typeDefinition->getOfType()));\n        }\n\n        return $this->getExtendedType($typeDefinition);\n    }\n}\n"
  },
  {
    "path": "src/Schema/Extension/ExtensionContextInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\ninterface ExtensionContextInterface\n{\n    /**\n     * @return bool\n     */\n    public function isSchemaExtended(): bool;\n\n    /**\n     * @return array\n     */\n    public function getExtendedOperationTypes(): array;\n\n    /**\n     * @return TypeInterface[]\n     */\n    public function getExtendedTypes(): array;\n\n    /**\n     * @return Directive[]\n     */\n    public function getExtendedDirectives(): array;\n}\n"
  },
  {
    "path": "src/Schema/Extension/SchemaExtender.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeSystemDefinitionNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeExtensionNode;\nuse Digia\\GraphQL\\Schema\\DefinitionBuilder;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass SchemaExtender implements SchemaExtenderInterface\n{\n    /**\n     * @inheritdoc\n     */\n    public function extend(\n        Schema $schema,\n        DocumentNode $document,\n        ?ResolverRegistryInterface $resolverRegistry = null,\n        array $options = []\n    ): Schema {\n        $context = $this->createContext($schema, $document, $resolverRegistry, $options);\n\n        // If this document contains no new types, extensions, or directives then\n        // return the same unmodified GraphQLSchema instance.\n        if (!$context->isSchemaExtended()) {\n            return $schema;\n        }\n\n        $operationTypes = $context->getExtendedOperationTypes();\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newSchema([\n            'query'        => $operationTypes['query'] ?? null,\n            'mutation'     => $operationTypes['mutation'] ?? null,\n            'subscription' => $operationTypes['subscription'] ?? null,\n            'types'        => $context->getExtendedTypes(),\n            'directives'   => $context->getExtendedDirectives(),\n            'astNode'      => $schema->getAstNode(),\n        ]);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function createContext(\n        Schema $schema,\n        DocumentNode $document,\n        ?ResolverRegistryInterface $resolverRegistry,\n        array $options\n    ): ExtensionContextInterface {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $info = $this->createInfo($schema, $document);\n\n        // Context has to be created in order to create the definition builder,\n        // because we are using its `resolveType` function to resolve types.\n        $context = new ExtensionContext($info);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $definitionBuilder = new DefinitionBuilder(\n            $info->getTypeDefinitionMap(),\n            $resolverRegistry,\n            $options['types'] ?? [],\n            $options['directives'] ?? [],\n            [$context, 'resolveType']\n        );\n\n        return $context->setDefinitionBuilder($definitionBuilder);\n    }\n\n    /**\n     * @param Schema       $schema\n     * @param DocumentNode $document\n     * @return ExtendInfo\n     * @throws SchemaExtensionException\n     */\n    protected function createInfo(Schema $schema, DocumentNode $document): ExtendInfo\n    {\n        $typeDefinitionMap    = [];\n        $typeExtensionsMap    = [];\n        $directiveDefinitions = [];\n        $schemaExtensions     = [];\n\n        foreach ($document->getDefinitions() as $definition) {\n            if ($definition instanceof SchemaDefinitionNode) {\n                // Sanity check that a schema extension is not defining a new schema\n                throw new SchemaExtensionException('Cannot define a new schema within a schema extension.', [$definition]);\n            }\n\n            if ($definition instanceof SchemaExtensionNode) {\n                $schemaExtensions[] = $definition;\n\n                continue;\n            }\n\n            if ($definition instanceof DirectiveDefinitionNode) {\n                $directiveName     = $definition->getNameValue();\n                $existingDirective = $schema->getDirective($directiveName);\n\n                if (null !== $existingDirective) {\n                    throw new SchemaExtensionException(\n                        \\sprintf(\n                            'Directive \"%s\" already exists in the schema. It cannot be redefined.',\n                            $directiveName\n                        ),\n                        [$definition]\n                    );\n                }\n\n                $directiveDefinitions[] = $definition;\n\n                continue;\n            }\n\n            if ($definition instanceof TypeSystemDefinitionNodeInterface && $definition instanceof NameAwareInterface) {\n                // Sanity check that none of the defined types conflict with the schema's existing types.\n                $typeName     = $definition->getNameValue();\n                $existingType = $schema->getType($typeName);\n\n                if (null !== $existingType) {\n                    throw new SchemaExtensionException(\n                        \\sprintf(\n                            'Type \"%s\" already exists in the schema. It cannot also ' .\n                            'be defined in this type definition.',\n                            $typeName\n                        ),\n                        [$definition]\n                    );\n                }\n\n                $typeDefinitionMap[$typeName] = $definition;\n\n                continue;\n            }\n\n            if ($definition instanceof ObjectTypeExtensionNode || $definition instanceof InterfaceTypeExtensionNode) {\n                // Sanity check that this type extension exists within the schema's existing types.\n                $extendedTypeName = $definition->getNameValue();\n                $existingType     = $schema->getType($extendedTypeName);\n\n                if (null === $existingType) {\n                    throw new SchemaExtensionException(\n                        \\sprintf(\n                            'Cannot extend type \"%s\" because it does not exist in the existing schema.',\n                            $extendedTypeName\n                        ),\n                        [$definition]\n                    );\n                }\n\n                $this->checkExtensionNode($existingType, $definition);\n\n                $typeExtensionsMap[$extendedTypeName] = \\array_merge(\n                    $typeExtensionsMap[$extendedTypeName] ?? [],\n                    [$definition]\n                );\n\n                continue;\n            }\n\n            if ($definition instanceof ScalarTypeExtensionNode ||\n                $definition instanceof UnionTypeExtensionNode ||\n                $definition instanceof EnumTypeExtensionNode ||\n                $definition instanceof InputObjectTypeExtensionNode) {\n                throw new SchemaExtensionException(\n                    \\sprintf('The %s kind is not yet supported by extendSchema().', $definition->getKind())\n                );\n            }\n        }\n\n        return new ExtendInfo(\n            $schema,\n            $document,\n            $typeDefinitionMap,\n            $typeExtensionsMap,\n            $directiveDefinitions,\n            $schemaExtensions\n        );\n    }\n\n    /**\n     * @param TypeInterface $type\n     * @param NodeInterface $node\n     * @throws SchemaExtensionException\n     */\n    protected function checkExtensionNode(TypeInterface $type, NodeInterface $node): void\n    {\n        if ($node instanceof ObjectTypeExtensionNode && !($type instanceof ObjectType)) {\n            throw new SchemaExtensionException(\n                \\sprintf('Cannot extend non-object type \"%s\".', toString($type)),\n                [$node]\n            );\n        }\n\n        if ($node instanceof InterfaceTypeExtensionNode && !($type instanceof InterfaceType)) {\n            throw new SchemaExtensionException(\n                \\sprintf('Cannot extend non-interface type \"%s\".', toString($type)),\n                [$node]\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Schema/Extension/SchemaExtenderInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\n\ninterface SchemaExtenderInterface\n{\n    /**\n     * @param Schema                         $schema\n     * @param DocumentNode                   $document\n     * @param ResolverRegistryInterface|null $resolverRegistry\n     * @param array                          $options\n     * @return Schema\n     */\n    public function extend(\n        Schema $schema,\n        DocumentNode $document,\n        ?ResolverRegistryInterface $resolverRegistry = null,\n        array $options = []\n    ): Schema;\n}\n"
  },
  {
    "path": "src/Schema/Extension/SchemaExtensionException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass SchemaExtensionException extends GraphQLException\n{\n}\n"
  },
  {
    "path": "src/Schema/Extension/SchemaExtensionProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Extension;\n\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass SchemaExtensionProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        SchemaExtenderInterface::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->add(SchemaExtenderInterface::class, SchemaExtender::class);\n    }\n}\n"
  },
  {
    "path": "src/Schema/Resolver/AbstractFieldResolver.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\n\nabstract class AbstractFieldResolver implements ResolverInterface\n{\n    use ResolverTrait;\n\n    /**\n     * @param mixed            $rootValue\n     * @param array            $arguments\n     * @param mixed            $context\n     * @param ResolveInfo|null $info\n     * @return mixed\n     */\n    abstract public function resolve($rootValue, array $arguments, $context = null, ?ResolveInfo $info = null);\n\n    /**\n     * @return mixed\n     */\n    public function __invoke()\n    {\n        return $this->resolve(...\\func_get_args());\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getResolveCallback(): ?callable\n    {\n        return function ($rootValue, array $arguments, $context = null, ?ResolveInfo $info = null) {\n            return $this->resolve($rootValue, $arguments, $context, $info);\n        };\n    }\n}\n"
  },
  {
    "path": "src/Schema/Resolver/AbstractTypeResolver.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\nabstract class AbstractTypeResolver implements ResolverCollectionInterface\n{\n    use ResolverTrait;\n\n    /**\n     * @return callable|null\n     */\n    public function getResolveCallback(): ?callable\n    {\n        return function (string $fieldName) {\n            return $this->getResolver($fieldName);\n        };\n    }\n\n    /**\n     * @param string $fieldName\n     * @return callable|null\n     */\n    public function getResolver(string $fieldName): ?callable\n    {\n        $resolveMethod = 'resolve' . \\ucfirst($fieldName);\n\n        if (\\method_exists($this, $resolveMethod)) {\n            return [$this, $resolveMethod];\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverCollectionInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\ninterface ResolverCollectionInterface extends ResolverInterface\n{\n    /**\n     * @param string $fieldName\n     * @return callable|null\n     */\n    public function getResolver(string $fieldName): ?callable;\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\ninterface ResolverInterface\n{\n    /**\n     * @return callable|null\n     */\n    public function getResolveCallback(): ?callable;\n\n    /**\n     * @return callable|null\n     */\n    public function getTypeResolver(): ?callable;\n\n    /**\n     * @return array|null\n     */\n    public function getMiddleware(): ?array;\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverMap.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\nclass ResolverMap implements ResolverCollectionInterface\n{\n    protected const TYPE_RESOLVER_KEY = '__resolveType';\n\n    /**\n     * @var callable[]\n     */\n    protected $resolvers;\n\n    /**\n     * ResolverCollection constructor.\n     * @param callable[] $resolvers\n     */\n    public function __construct(array $resolvers)\n    {\n        $this->registerResolvers($resolvers);\n    }\n\n    /**\n     * @param string   $fieldName\n     * @param callable $resolver\n     */\n    public function addResolver(string $fieldName, callable $resolver)\n    {\n        $this->resolvers[$fieldName] = $resolver;\n    }\n\n    /**\n     * @param string $fieldName\n     * @return callable|null\n     */\n    public function getResolver(string $fieldName): ?callable\n    {\n        return $this->resolvers[$fieldName] ?? null;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getResolveCallback(): ?callable\n    {\n        return function (string $fieldName) {\n            $resolver = $this->getResolver($fieldName);\n\n            return $resolver instanceof ResolverInterface\n                ? $resolver->getResolveCallback()\n                : $resolver;\n        };\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getTypeResolver(): ?callable\n    {\n        return $this->resolvers[static::TYPE_RESOLVER_KEY] ?? null;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getMiddleware(): ?array\n    {\n        return null;\n    }\n\n    /**\n     * @param array $resolvers\n     */\n    protected function registerResolvers(array $resolvers): void\n    {\n        foreach ($resolvers as $typeName => $resolver) {\n            if (\\is_array($resolver)) {\n                $resolver = new ResolverMap($resolver);\n            }\n\n            $this->addResolver($typeName, $resolver);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverMiddlewareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\n\ninterface ResolverMiddlewareInterface\n{\n    /**\n     * @param callable         $resolveCallback\n     * @param mixed            $rootValue\n     * @param array            $arguments\n     * @param mixed            $context\n     * @param ResolveInfo|null $info\n     * @return mixed\n     */\n    public function resolve(\n        callable $resolveCallback,\n        $rootValue,\n        array $arguments,\n        $context = null,\n        ?ResolveInfo $info = null\n    );\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverRegistry.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\n\nclass ResolverRegistry implements ResolverRegistryInterface\n{\n    /**\n     * @var ResolverInterface[]\n     */\n    protected $resolverMap;\n\n    /**\n     * @var ResolverMiddlewareInterface[]|null\n     */\n    protected $middleware;\n\n    /**\n     * ResolverRegistry constructor.\n     * @param ResolverInterface[]                $resolvers\n     * @param ResolverMiddlewareInterface[]|null $middleware\n     */\n    public function __construct(array $resolvers = [], ?array $middleware = null)\n    {\n        $this->middleware = $middleware;\n\n        $this->registerResolvers($resolvers);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function register(string $typeName, ResolverInterface $resolver): void\n    {\n        $this->resolverMap[$typeName] = $resolver;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getFieldResolver(string $typeName, string $fieldName): ?callable\n    {\n        $resolver = $this->getResolver($typeName);\n\n        $resolver = $resolver instanceof ResolverCollectionInterface\n            ? $resolver->getResolver($fieldName)\n            : $resolver;\n\n        $resolveCallback = $resolver instanceof ResolverInterface\n            ? $resolver->getResolveCallback()\n            : $resolver;\n\n        if (null === $resolveCallback) {\n            return null;\n        }\n\n        if (null !== $this->middleware) {\n            $middleware = $resolver instanceof ResolverInterface\n                ? $this->getMiddlewareToApply($resolver, $this->middleware)\n                : $this->middleware;\n\n            return $this->applyMiddleware($resolveCallback, \\array_reverse($middleware));\n        }\n\n        return $resolveCallback;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getTypeResolver(string $typeName): ?callable\n    {\n        $resolver = $this->getResolver($typeName);\n\n        if ($resolver instanceof ResolverInterface) {\n            return $resolver->getTypeResolver();\n        }\n\n        return null;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getResolver(string $typeName): ?ResolverInterface\n    {\n        return $this->resolverMap[$typeName] ?? null;\n    }\n\n    /**\n     * @param array $resolvers\n     */\n    protected function registerResolvers(array $resolvers): void\n    {\n        foreach ($resolvers as $typeName => $resolver) {\n            if (\\is_array($resolver)) {\n                $resolver = new ResolverMap($resolver);\n            }\n\n            $this->register($typeName, $resolver);\n        }\n    }\n\n    /**\n     * @param ResolverInterface             $resolver\n     * @param ResolverMiddlewareInterface[] $middleware\n     * @return array\n     */\n    protected function getMiddlewareToApply(ResolverInterface $resolver, array $middleware): array\n    {\n        $resolverMiddleware = $resolver->getMiddleware();\n\n        if (null === $resolverMiddleware) {\n            return $middleware;\n        }\n\n        return \\array_filter($middleware, function (ResolverMiddlewareInterface $mw) use ($resolverMiddleware) {\n            return \\in_array(\\get_class($mw), $resolverMiddleware, true);\n        });\n    }\n\n    /**\n     * @param callable $resolveCallback\n     * @param array    $middleware\n     * @return callable\n     */\n    protected function applyMiddleware(callable $resolveCallback, array $middleware): callable\n    {\n        return \\array_reduce(\n            $middleware,\n            function (callable $resolveCallback, ResolverMiddlewareInterface $middleware) {\n                return function ($rootValue, array $arguments, $context = null, ?ResolveInfo $info = null) use (\n                    $resolveCallback,\n                    $middleware\n                ) {\n                    return $middleware->resolve($resolveCallback, $rootValue, $arguments, $context, $info);\n                };\n            },\n            $resolveCallback\n        );\n    }\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverRegistryInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\ninterface ResolverRegistryInterface\n{\n    /**\n     * @param string            $typeName\n     * @param ResolverInterface $resolver\n     */\n    public function register(string $typeName, ResolverInterface $resolver): void;\n\n    /**\n     * @param string $typeName\n     * @param string $fieldName\n     * @return callable|null\n     */\n    public function getFieldResolver(string $typeName, string $fieldName): ?callable;\n\n    /**\n     * @param string $typeName\n     * @return callable|null\n     */\n    public function getTypeResolver(string $typeName): ?callable;\n\n    /**\n     * @param string $typeName\n     * @return ResolverInterface|null\n     */\n    public function getResolver(string $typeName): ?ResolverInterface;\n}\n"
  },
  {
    "path": "src/Schema/Resolver/ResolverTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Resolver;\n\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\n\ntrait ResolverTrait\n{\n    /**\n     * @return callable|null\n     */\n    public function getTypeResolver(): ?callable\n    {\n        return function ($rootValue, $context = null, ?ResolveInfo $info = null) {\n            return $this->resolveType($rootValue, $context, $info);\n        };\n    }\n\n    /**\n     * @param mixed            $rootValue\n     * @param mixed            $context\n     * @param ResolveInfo|null $info\n     * @return callable|null\n     */\n    public function resolveType($rootValue, $context = null, ?ResolveInfo $info = null): ?callable\n    {\n        // Override this method when your resolver returns an interface or an union type.\n        return null;\n    }\n\n    /**\n     * @return array|null\n     */\n    public function getMiddleware(): ?array\n    {\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Schema.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\ExtensionASTNodesTrait;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse Digia\\GraphQL\\Type\\Definition\\WrappingTypeInterface;\nuse function Digia\\GraphQL\\Type\\__Schema;\nuse function Digia\\GraphQL\\Util\\find;\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 *     $MyAppSchema = GraphQLSchema([\n *       'query'    => $MyAppQueryRootType,\n *       'mutation' => $MyAppMutationRootType,\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 *     $MyAppSchema = GraphQLSchema([\n *       ...\n *       'directives' => \\array_merge(specifiedDirectives(), [$myCustomDirective]),\n *     ])\n */\nclass Schema implements DefinitionInterface\n{\n    use ExtensionASTNodesTrait;\n    use ASTNodeTrait;\n\n    /**\n     * @var ObjectType|null\n     */\n    protected $queryType;\n\n    /**\n     * @var ObjectType|null\n     */\n    protected $mutationType;\n\n    /**\n     * @var ObjectType|null\n     */\n    protected $subscriptionType;\n\n    /**\n     * @var TypeInterface[]\n     */\n    protected $types = [];\n\n    /**\n     * @var array\n     */\n    protected $directives = [];\n\n    /**\n     * @var bool\n     */\n    protected $assumeValid = false;\n\n    /**\n     * @var TypeInterface[]\n     */\n    protected $typeMap = [];\n\n    /**\n     * @var array\n     */\n    protected $implementations = [];\n\n    /**\n     * @var NamedTypeInterface[]\n     */\n    protected $possibleTypesMap = [];\n\n    /**\n     * Schema constructor.\n     *\n     * @param ObjectType|null                                        $queryType\n     * @param ObjectType|null                                        $mutationType\n     * @param ObjectType|null                                        $subscriptionType\n     * @param TypeInterface[]                                        $types\n     * @param Directive[]                                            $directives\n     * @param bool                                                   $assumeValid\n     * @param SchemaDefinitionNode|null                              $astNode\n     * @param ObjectTypeExtensionNode[]|InterfaceTypeExtensionNode[] $extensionASTNodes\n     * @throws InvariantException\n     */\n    public function __construct(\n        ?ObjectType $queryType,\n        ?ObjectType $mutationType,\n        ?ObjectType $subscriptionType,\n        array $types,\n        array $directives,\n        bool $assumeValid,\n        ?SchemaDefinitionNode $astNode,\n        array $extensionASTNodes\n    ) {\n        $this->queryType         = $queryType;\n        $this->mutationType      = $mutationType;\n        $this->subscriptionType  = $subscriptionType;\n        $this->types             = $types;\n        $this->directives        = !empty($directives)\n            ? $directives\n            : specifiedDirectives();\n        $this->assumeValid       = $assumeValid;\n        $this->astNode           = $astNode;\n        $this->extensionAstNodes = $extensionASTNodes;\n\n        $this->buildTypeMap();\n        $this->buildImplementations();\n    }\n\n    /**\n     * @return ObjectType|null\n     */\n    public function getQueryType(): ?ObjectType\n    {\n        return $this->queryType;\n    }\n\n    /**\n     * @return ObjectType|null\n     */\n    public function getMutationType(): ?ObjectType\n    {\n        return $this->mutationType;\n    }\n\n    /**\n     * @return ObjectType|null\n     */\n    public function getSubscriptionType(): ?ObjectType\n    {\n        return $this->subscriptionType;\n    }\n\n    /**\n     * @param string $name\n     * @return Directive|null\n     */\n    public function getDirective(string $name): ?Directive\n    {\n        return find($this->directives, function (Directive $directive) use ($name) {\n            return $directive->getName() === $name;\n        });\n    }\n\n    /**\n     * @return array\n     */\n    public function getDirectives(): array\n    {\n        return $this->directives;\n    }\n\n    /**\n     * @return array\n     */\n    public function getTypeMap(): array\n    {\n        return $this->typeMap;\n    }\n\n    /**\n     * @return bool\n     */\n    public function getAssumeValid(): bool\n    {\n        return $this->assumeValid;\n    }\n\n    /**\n     * @param NamedTypeInterface $abstractType\n     * @param NamedTypeInterface $possibleType\n     * @return bool\n     * @throws InvariantException\n     */\n    public function isPossibleType(NamedTypeInterface $abstractType, NamedTypeInterface $possibleType): bool\n    {\n        $abstractTypeName = $abstractType->getName();\n        $possibleTypeName = $possibleType->getName();\n\n        if (!isset($this->possibleTypesMap[$abstractTypeName])) {\n            $possibleTypes = $this->getPossibleTypes($abstractType);\n\n            if (!\\is_array($possibleTypes)) {\n                throw new InvariantException(\\sprintf(\n                    'Could not find possible implementing types for %s ' .\n                    'in schema. Check that schema.types is defined and is an array of ' .\n                    'all possible types in the schema.',\n                    $abstractTypeName\n                ));\n            }\n\n            $this->possibleTypesMap[$abstractTypeName] = \\array_reduce(\n                $possibleTypes,\n                function (array $map, NamedTypeInterface $type) {\n                    $map[$type->getName()] = true;\n                    return $map;\n                },\n                []\n            );\n        }\n\n        return isset($this->possibleTypesMap[$abstractTypeName][$possibleTypeName]);\n    }\n\n    /**\n     * @param NamedTypeInterface $abstractType\n     * @return NamedTypeInterface[]|null\n     * @throws InvariantException\n     */\n    public function getPossibleTypes(NamedTypeInterface $abstractType): ?array\n    {\n        if ($abstractType instanceof UnionType) {\n            return $abstractType->getTypes();\n        }\n\n        return $this->implementations[$abstractType->getName()] ?? null;\n    }\n\n    /**\n     * @param string $name\n     * @return TypeInterface|null\n     */\n    public function getType(string $name): ?TypeInterface\n    {\n        return $this->typeMap[$name] ?? null;\n    }\n\n    /**\n     *\n     */\n    protected function buildTypeMap(): void\n    {\n        $initialTypes = [\n            $this->queryType,\n            $this->mutationType,\n            $this->subscriptionType,\n            __Schema(), // Introspection schema\n        ];\n\n        if (!empty($this->types)) {\n            $initialTypes = \\array_merge($initialTypes, $this->types);\n        }\n\n        // Keep track of all types referenced within the schema.\n        $typeMap = [];\n\n        // First by deeply visiting all initial types.\n        $typeMap = \\array_reduce($initialTypes, [$this, 'typeMapReducer'], $typeMap);\n\n        // Then by deeply visiting all directive types.\n        $typeMap = \\array_reduce($this->directives, [$this, 'typeMapDirectiveReducer'], $typeMap);\n\n        // Storing the resulting map for reference by the schema.\n        $this->typeMap = $typeMap;\n    }\n\n    /**\n     * @throws InvariantException\n     */\n    protected function buildImplementations(): void\n    {\n        $implementations = [];\n\n        // Keep track of all implementations by interface name.\n        foreach ($this->typeMap as $typeName => $type) {\n            if ($type instanceof ObjectType) {\n                foreach ($type->getInterfaces() as $interface) {\n                    if (!($interface instanceof InterfaceType)) {\n                        continue;\n                    }\n\n                    $interfaceName = $interface->getName();\n\n                    if (!isset($implementations[$interfaceName])) {\n                        $implementations[$interfaceName] = [];\n                    }\n\n                    $implementations[$interfaceName][] = $type;\n                }\n            }\n        }\n\n        $this->implementations = $implementations;\n    }\n\n    /**\n     * @param array              $map\n     * @param TypeInterface|null $type\n     * @return array\n     * @throws InvariantException\n     */\n    protected function typeMapReducer(array $map, ?TypeInterface $type): array\n    {\n        if (null === $type) {\n            return $map;\n        }\n\n        if ($type instanceof WrappingTypeInterface) {\n            return $this->typeMapReducer($map, $type->getOfType());\n        }\n\n        if ($type instanceof NamedTypeInterface) {\n            $typeName = $type->getName();\n\n            if (isset($map[$typeName])) {\n                if ($type !== $map[$typeName]) {\n                    throw new InvariantException(\\sprintf(\n                        'Schema must contain unique named types but contains multiple types named \"%s\".',\n                        $type->getName()\n                    ));\n                }\n\n                return $map;\n            }\n\n            $map[$typeName] = $type;\n\n            $reducedMap = $map;\n\n            if ($type instanceof UnionType) {\n                $reducedMap = \\array_reduce($type->getTypes(), [$this, 'typeMapReducer'], $reducedMap);\n            }\n\n            if ($type instanceof ObjectType) {\n                $reducedMap = \\array_reduce($type->getInterfaces(), [$this, 'typeMapReducer'], $reducedMap);\n            }\n\n            if ($type instanceof ObjectType || $type instanceof InterfaceType) {\n                foreach ($type->getFields() as $field) {\n                    if ($field->hasArguments()) {\n                        $fieldArgTypes = \\array_map(function (Argument $argument) {\n                            return $argument->getType();\n                        }, $field->getArguments());\n\n                        $reducedMap = \\array_reduce($fieldArgTypes, [$this, 'typeMapReducer'], $reducedMap);\n                    }\n\n                    $reducedMap = $this->typeMapReducer($reducedMap, $field->getType());\n                }\n            }\n\n            if ($type instanceof InputObjectType) {\n                foreach ($type->getFields() as $field) {\n                    $reducedMap = $this->typeMapReducer($reducedMap, $field->getType());\n                }\n            }\n\n            return $reducedMap;\n        }\n\n        return $map;\n    }\n\n    /**\n     * @param array     $map\n     * @param Directive $directive\n     * @return array\n     * @throws InvariantException\n     */\n    protected function typeMapDirectiveReducer(array $map, Directive $directive): array\n    {\n        if (!$directive->hasArguments()) {\n            return $map;\n        }\n\n        return \\array_reduce($directive->getArguments(), function ($map, Argument $argument) {\n            return $this->typeMapReducer($map, $argument->getType());\n        }, $map);\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/Rule/AbstractRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Schema\\Validation\\ValidationContextInterface;\n\nabstract class AbstractRule implements RuleInterface\n{\n    /**\n     * @var ValidationContextInterface\n     */\n    protected $context;\n\n    /**\n     * @param ValidationContextInterface $context\n     * @return $this\n     */\n    public function setContext(ValidationContextInterface $context)\n    {\n        $this->context = $context;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/Rule/DirectivesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidationException;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Util\\NameHelper;\nuse function Digia\\GraphQL\\Type\\isInputType;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass DirectivesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     * @throws InvariantException\n     */\n    public function evaluate(): void\n    {\n        $directives = $this->context->getSchema()->getDirectives();\n\n        foreach ($directives as $directive) {\n            if (!($directive instanceof Directive)) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf('Expected directive but got: %s.', toString($directive)),\n                        $directive instanceof ASTNodeAwareInterface ? [$directive->getAstNode()] : null\n                    )\n                );\n\n                return;\n            }\n\n            // Ensure they are named correctly.\n            $this->validateName($directive);\n\n            // TODO: Ensure proper locations.\n\n            // Ensure the arguments are valid.\n            $argumentNames = [];\n\n            foreach ($directive->getArguments() as $argument) {\n                $argumentName = $argument->getName();\n\n                // Ensure they are named correctly.\n                $this->validateName($argument);\n\n                // Ensure they are unique per directive.\n                if (isset($argumentNames[$argumentName])) {\n                    $this->context->reportError(\n                        new SchemaValidationException(\n                            \\sprintf(\n                                'Argument @%s(%s:) can only be defined once.',\n                                $directive->getName(),\n                                $argumentName\n                            ),\n                            $this->getAllDirectiveArgumentNodes($directive, $argumentName)\n                        )\n                    );\n\n                    continue;\n                }\n\n                $argumentNames[$argumentName] = true;\n\n                // Ensure the type is an input type.\n                if (!isInputType($argument->getType())) {\n                    $this->context->reportError(\n                        new SchemaValidationException(\n                            \\sprintf(\n                                'The type of @%s(%s:) must be Input Type but got: %s.',\n                                $directive->getName(),\n                                $argumentName,\n                                (string)$argument->getType()\n                            ),\n                            $this->getAllDirectiveArgumentNodes($directive, $argumentName)\n                        )\n                    );\n                }\n            }\n        }\n    }\n\n    /**\n     * @param Directive $directive\n     * @param string    $argumentName\n     * @return array\n     */\n    protected function getAllDirectiveArgumentNodes(Directive $directive, string $argumentName)\n    {\n        $nodes = [];\n\n        /** @var DirectiveNode|null $directiveNode */\n        $directiveNode = $directive->getAstNode();\n\n        if (null !== $directiveNode) {\n            foreach ($directiveNode->getArguments() as $node) {\n                if ($node->getNameValue() === $argumentName) {\n                    $nodes[] = $node;\n                }\n            }\n        }\n\n        return $nodes;\n    }\n\n    /**\n     * @param mixed $node\n     */\n    protected function validateName($node): void\n    {\n        // Ensure names are valid, however introspection types opt out.\n        $error = NameHelper::isValidError($node->getName(), $node);\n\n        if (null !== $error) {\n            $this->context->reportError($error);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/Rule/RootTypesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidationException;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\n\nclass RootTypesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    public function evaluate(): void\n    {\n        $schema = $this->context->getSchema();\n\n        $rootTypes = [\n            'query'        => $schema->getQueryType(),\n            'mutation'     => $schema->getMutationType(),\n            'subscription' => $schema->getSubscriptionType(),\n        ];\n\n        foreach ($rootTypes as $operation => $rootType) {\n            $this->validateRootType($rootType, $operation);\n        }\n    }\n\n    /**\n     * @param NamedTypeInterface|ObjectType|null $rootType\n     * @param string                             $operation\n     */\n    protected function validateRootType(?NamedTypeInterface $rootType, string $operation): void\n    {\n        $schema = $this->context->getSchema();\n\n        if ($operation === 'query' && null === $rootType) {\n            $this->context->reportError(\n                new SchemaValidationException(\n                    \\sprintf('%s root type must be provided.', \\ucfirst($operation)),\n                    $schema->hasAstNode() ? [$schema->getAstNode()] : null\n                )\n            );\n\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/Rule/RuleInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Schema\\Validation\\ValidationContextInterface;\n\ninterface RuleInterface\n{\n    /**\n     * @param ValidationContextInterface $context\n     * @return $this\n     */\n    public function setContext(ValidationContextInterface $context);\n\n    /**\n     *\n     */\n    public function evaluate(): void;\n}\n"
  },
  {
    "path": "src/Schema/Validation/Rule/SupportedRules.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation\\Rule;\n\nuse Digia\\GraphQL\\GraphQL;\n\nclass SupportedRules\n{\n    /**\n     * @var array\n     */\n    private static $supportedRules = [\n        RootTypesRule::class,\n        DirectivesRule::class,\n        TypesRule::class,\n    ];\n\n    /**\n     * Rules maintain state so they should always be re-instantiated.\n     *\n     * @return RuleInterface[]\n     */\n    public static function build(): array\n    {\n        $rules = [];\n\n        foreach (self::$supportedRules as $className) {\n            $rules[] = GraphQL::make($className);\n        }\n\n        return $rules;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/Rule/TypesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidationException;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\FieldsAwareInterface;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse Digia\\GraphQL\\Util\\NameHelper;\nuse Digia\\GraphQL\\Util\\TypeHelper;\nuse function Digia\\GraphQL\\Type\\isInputType;\nuse function Digia\\GraphQL\\Type\\isIntrospectionType;\nuse function Digia\\GraphQL\\Type\\isOutputType;\nuse function Digia\\GraphQL\\Util\\find;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass TypesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     *\n     * @throws InvariantException\n     */\n    public function evaluate(): void\n    {\n        $typeMap = $this->context->getSchema()->getTypeMap();\n\n        foreach ($typeMap as $type) {\n            if (!($type instanceof NamedTypeInterface)) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf('Expected GraphQL named type but got: %s.', toString($type)),\n                        $type instanceof ASTNodeAwareInterface ? [$type->getAstNode()] : null\n                    )\n                );\n\n                continue;\n            }\n\n            // Ensure it is named correctly (excluding introspection types).\n            /** @noinspection PhpParamsInspection */\n            if (!isIntrospectionType($type)) {\n                $this->validateName($type);\n            }\n\n            if ($type instanceof ObjectType) {\n                // Ensure fields are valid.\n                $this->validateFields($type);\n                // Ensure objects implement the interfaces they claim to.\n                $this->validateObjectInterfaces($type);\n                continue;\n            }\n\n            if ($type instanceof InterfaceType) {\n                // Ensure fields are valid.\n                $this->validateFields($type);\n                continue;\n            }\n\n            if ($type instanceof UnionType) {\n                // Ensure Unions include valid member types.\n                $this->validateUnionMembers($type);\n                continue;\n            }\n\n            if ($type instanceof EnumType) {\n                // Ensure Enums have valid values.\n                $this->validateEnumValues($type);\n                continue;\n            }\n\n            if ($type instanceof InputObjectType) {\n                // Ensure Input Object fields are valid.\n                $this->validateInputFields($type);\n                continue;\n            }\n        }\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @throws InvariantException\n     */\n    protected function validateFields(FieldsAwareInterface $type): void\n    {\n        $fields = $type->getFields();\n\n        // Objects and Interfaces both must define one or more fields.\n        if (empty($fields)) {\n            $this->context->reportError(\n                new SchemaValidationException(\n                    \\sprintf('Type %s must define one or more fields.', $type->getName()),\n                    $this->getAllObjectOrInterfaceNodes($type)\n                )\n            );\n        }\n\n        foreach ($fields as $fieldName => $field) {\n            // Ensure they are named correctly.\n            $this->validateName($field);\n\n            // Ensure they were defined at most once.\n            $fieldNodes = $this->getAllFieldNodes($type, $fieldName);\n\n            if (\\count($fieldNodes) > 1) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf('Field %s.%s can only be defined once.', $type->getName(), $fieldName),\n                        $fieldNodes\n                    )\n                );\n\n                return; // continue loop\n            }\n\n            $fieldType = $field->getType();\n\n            // Ensure the type is an output type\n            if (!isOutputType($fieldType)) {\n                $fieldTypeNode = $this->getFieldTypeNode($type, $fieldName);\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'The type of %s.%s must be Output Type but got: %s.',\n                            $type->getName(),\n                            $fieldName,\n                            toString($fieldType)\n                        ),\n                        [$fieldTypeNode]\n                    )\n                );\n            }\n\n            // Ensure the arguments are valid\n            $argumentNames = [];\n\n            foreach ($field->getArguments() as $argument) {\n                $argumentName = $argument->getName();\n\n                // Ensure they are named correctly.\n                $this->validateName($argument);\n\n                // Ensure they are unique per field.\n                if (isset($argumentNames[$argumentName])) {\n                    $this->context->reportError(\n                        new SchemaValidationException(\n                            \\sprintf(\n                                'Field argument %s.%s(%s:) can only be defined once.',\n                                $type->getName(),\n                                $field->getName(),\n                                $argumentName\n                            ),\n                            $this->getAllFieldArgumentNodes($type, $fieldName, $argumentName)\n                        )\n                    );\n                }\n\n                $argumentNames[$argumentName] = true;\n\n                // Ensure the type is an input type\n                if (!isInputType($argument->getType())) {\n                    $this->context->reportError(\n                        new SchemaValidationException(\n                            \\sprintf(\n                                'The type of %s.%s(%s:) must be Input Type but got: %s.',\n                                $type->getName(),\n                                $fieldName,\n                                $argumentName,\n                                toString($argument->getType())\n                            ),\n                            $this->getAllFieldArgumentNodes($type, $fieldName, $argumentName)\n                        )\n                    );\n                }\n            }\n        }\n    }\n\n    /**\n     * @param ObjectType $objectType\n     * @throws InvariantException\n     */\n    protected function validateObjectInterfaces(ObjectType $objectType): void\n    {\n        $implementedTypeNames = [];\n\n        foreach ($objectType->getInterfaces() as $interface) {\n            if (!($interface instanceof InterfaceType)) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'Type %s must only implement Interface types, it cannot implement %s.',\n                            toString($objectType),\n                            toString($interface)\n                        ),\n                        null !== $interface\n                            ? [$this->getImplementsInterfaceNode($objectType, $interface->getName())]\n                            : null\n                    )\n                );\n\n                continue;\n            }\n\n            $interfaceName = $interface->getName();\n\n            if (isset($implementedTypeNames[$interfaceName])) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf('Type %s can only implement %s once.', $objectType->getName(), $interfaceName),\n                        $this->getAllImplementsInterfaceNodes($objectType, $interfaceName)\n                    )\n                );\n\n                continue;\n            }\n\n            $implementedTypeNames[$interfaceName] = true;\n\n            $this->validateObjectImplementsInterface($objectType, $interface);\n        }\n    }\n\n    /**\n     * @param ObjectType    $objectType\n     * @param InterfaceType $interfaceType\n     * @throws InvariantException\n     */\n    protected function validateObjectImplementsInterface(ObjectType $objectType, InterfaceType $interfaceType): void\n    {\n        $objectFields    = $objectType->getFields();\n        $interfaceFields = $interfaceType->getFields();\n\n        // Assert each interface field is implemented.\n        foreach (\\array_keys($interfaceFields) as $fieldName) {\n            $interfaceField = $interfaceFields[$fieldName];\n            $objectField    = $objectFields[$fieldName] ?? null;\n\n            // Assert interface field exists on object.\n            if (null === $objectField) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'Interface field %s.%s expected but %s does not provide it.',\n                            $interfaceType->getName(),\n                            $fieldName,\n                            $objectType->getName()\n                        ),\n                        [$this->getFieldNode($interfaceType, $fieldName), $objectType->getAstNode()]\n                    )\n                );\n\n                continue;\n            }\n\n            // Assert interface field type is satisfied by object field type, by being\n            // a valid subtype. (covariant)\n            if (!TypeHelper::isTypeSubtypeOf(\n                $this->context->getSchema(), $objectField->getType(), $interfaceField->getType())) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'Interface field %s.%s expects type %s but %s.%s is type %s.',\n                            $interfaceType->getName(),\n                            $fieldName,\n                            toString($interfaceField->getType()),\n                            $objectType->getName(),\n                            $fieldName,\n                            toString($objectField->getType())\n                        ),\n                        [\n                            $this->getFieldTypeNode($interfaceType, $fieldName),\n                            $this->getFieldTypeNode($objectType, $fieldName),\n                        ]\n                    )\n                );\n            }\n\n            // Assert each interface field arg is implemented.\n            foreach ($interfaceField->getArguments() as $interfaceArgument) {\n                $argumentName   = $interfaceArgument->getName();\n                $objectArgument = find($objectField->getArguments(), function (Argument $argument) use ($argumentName) {\n                    return $argument->getName() === $argumentName;\n                });\n\n                // Assert interface field arg exists on object field.\n                if (null === $objectArgument) {\n                    $this->context->reportError(\n                        new SchemaValidationException(\n                            \\sprintf(\n                                'Interface field argument %s.%s(%s:) expected but %s.%s does not provide it.',\n                                $interfaceType->getName(),\n                                $fieldName,\n                                $argumentName,\n                                $objectType->getName(),\n                                $fieldName\n                            ),\n                            [\n                                $this->getFieldArgumentNode($interfaceType, $fieldName, $argumentName),\n                                $this->getFieldNode($objectType, $fieldName),\n                            ]\n                        )\n                    );\n\n                    continue;\n                }\n\n                // Assert interface field arg type matches object field arg type.\n                // (invariant)\n                // TODO: change to contravariant?\n                if (!TypeHelper::isEqualType($interfaceArgument->getType(), $objectArgument->getType())) {\n                    $this->context->reportError(\n                        new SchemaValidationException(\n                            \\sprintf(\n                                'Interface field argument %s.%s(%s:) expects type %s but %s.%s(%s:) is type %s.',\n                                $interfaceType->getName(),\n                                $fieldName,\n                                $argumentName,\n                                toString($interfaceArgument->getType()),\n                                $objectType->getName(),\n                                $fieldName,\n                                $argumentName,\n                                toString($objectArgument->getType())\n                            ),\n                            [\n                                $this->getFieldArgumentTypeNode($interfaceType, $fieldName, $argumentName),\n                                $this->getFieldArgumentTypeNode($objectType, $fieldName, $argumentName),\n                            ]\n                        )\n                    );\n\n                    continue;\n                }\n\n                // TODO: validate default values?\n\n                foreach ($objectField->getArguments() as $objectArgument) {\n                    $argumentName      = $objectArgument->getName();\n                    $interfaceArgument = find(\n                        $interfaceField->getArguments(),\n                        function (Argument $argument) use ($argumentName) {\n                            return $argument->getName() === $argumentName;\n                        }\n                    );\n\n                    if (null === $interfaceArgument && $objectArgument->getType() instanceof NonNullType) {\n                        $this->context->reportError(\n                            new SchemaValidationException(\n                                \\sprintf(\n                                    'Object field argument %s.%s(%s:) is of required type %s ' .\n                                    'but is not also provided by the Interface field %s.%s.',\n                                    $objectType->getName(),\n                                    $fieldName,\n                                    $argumentName,\n                                    toString($objectArgument->getType()),\n                                    $interfaceType->getName(),\n                                    $fieldName\n                                ),\n                                [\n                                    $this->getFieldArgumentNode($objectType, $fieldName, $argumentName),\n                                    $this->getFieldNode($interfaceType, $fieldName),\n                                ]\n                            )\n                        );\n\n                        continue;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * @param UnionType $unionType\n     * @throws InvariantException\n     */\n    protected function validateUnionMembers(UnionType $unionType): void\n    {\n        $memberTypes = $unionType->getTypes();\n\n        if (empty($memberTypes)) {\n            $this->context->reportError(\n                new SchemaValidationException(\n                    sprintf('Union type %s must define one or more member types.', $unionType->getName()),\n                    [$unionType->getAstNode()]\n                )\n            );\n        }\n\n        $includedTypeNames = [];\n\n        foreach ($memberTypes as $memberType) {\n            $memberTypeName = (string)$memberType;\n            if (isset($includedTypeNames[$memberTypeName])) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'Union type %s can only include type %s once.',\n                            $unionType->getName(),\n                            $memberTypeName\n                        ),\n                        $this->getUnionMemberTypeNodes($unionType, $memberTypeName)\n                    )\n                );\n\n                continue;\n            }\n\n            $includedTypeNames[$memberTypeName] = true;\n\n            if (!($memberType instanceof ObjectType)) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'Union type %s can only include Object types, it cannot include %s.',\n                            $unionType->getName(),\n                            toString($memberType)\n                        ),\n                        $this->getUnionMemberTypeNodes($unionType, $memberTypeName)\n                    )\n                );\n            }\n        }\n    }\n\n    /**\n     * @param EnumType $enumType\n     * @throws InvariantException\n     */\n    protected function validateEnumValues(EnumType $enumType): void\n    {\n        $enumValues = $enumType->getValues();\n\n        if (empty($enumValues)) {\n            $this->context->reportError(\n                new SchemaValidationException(\n                    \\sprintf('Enum type %s must define one or more values.', $enumType->getName()),\n                    [$enumType->getAstNode()]\n                )\n            );\n        }\n\n        foreach ($enumValues as $enumValue) {\n            $valueName = $enumValue->getName();\n\n            // Ensure no duplicates.\n            $allNodes = $this->getEnumValueNodes($enumType, $valueName);\n\n            if (null !== $allNodes && \\count($allNodes) > 1) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        sprintf('Enum type %s can include value %s only once.', $enumType->getName(), $valueName),\n                        $allNodes\n                    )\n                );\n\n                continue;\n            }\n\n            // Ensure valid name.\n            $this->validateName($enumValue);\n\n            if ($valueName === 'true' || $valueName === 'false' || $valueName === 'null') {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        sprintf('Enum type %s cannot include value: %s.', $enumType->getName(), $valueName),\n                        [$enumValue->getAstNode()]\n                    )\n                );\n\n                continue;\n            }\n        }\n    }\n\n    /**\n     * @param InputObjectType $inputObjectType\n     * @throws InvariantException\n     */\n    protected function validateInputFields(InputObjectType $inputObjectType): void\n    {\n        $fields = $inputObjectType->getFields();\n\n        if (empty($fields)) {\n            $this->context->reportError(\n                new SchemaValidationException(\n                    \\sprintf('Input Object type %s must define one or more fields.', $inputObjectType->getName()),\n                    [$inputObjectType->getAstNode()]\n                )\n            );\n        }\n\n        // Ensure the arguments are valid\n        foreach ($fields as $fieldName => $field) {\n            // Ensure they are named correctly.\n            $this->validateName($field);\n\n            // TODO: Ensure they are unique per field.\n\n            // Ensure the type is an input type\n            if (!isInputType($field->getType())) {\n                $this->context->reportError(\n                    new SchemaValidationException(\n                        \\sprintf(\n                            'The type of %s.%s must be Input Type but got: %s.',\n                            $inputObjectType->getName(),\n                            $fieldName,\n                            toString($field->getType())\n                        ),\n                        [$field->getAstNode()]\n                    )\n                );\n            }\n        }\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @return ObjectTypeDefinitionNode[]|ObjectTypeExtensionNode[]|InterfaceTypeDefinitionNode[]\n     * |InterfaceTypeExtensionNode[]\n     */\n    protected function getAllObjectOrInterfaceNodes(FieldsAwareInterface $type): array\n    {\n        $node              = $type->getAstNode();\n        $extensionASTNodes = $type->getExtensionAstNodes();\n\n        if (null !== $node) {\n            return !empty($extensionASTNodes)\n                ? \\array_merge([$node], $extensionASTNodes)\n                : [$node];\n        }\n\n        return $extensionASTNodes;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @param string               $fieldName\n     * @return TypeNodeInterface|null\n     */\n    protected function getFieldTypeNode(FieldsAwareInterface $type, string $fieldName): ?TypeNodeInterface\n    {\n        $fieldNode = $this->getFieldNode($type, $fieldName);\n        return null !== $fieldNode ? $fieldNode->getType() : null;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @param string               $fieldName\n     * @return FieldDefinitionNode|null\n     */\n    protected function getFieldNode(FieldsAwareInterface $type, string $fieldName): ?FieldDefinitionNode\n    {\n        return $this->getAllFieldNodes($type, $fieldName)[0] ?? null;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @param string               $fieldName\n     * @return FieldDefinitionNode[]\n     */\n    protected function getAllFieldNodes(FieldsAwareInterface $type, string $fieldName): array\n    {\n        $nodes = [];\n\n        foreach ($this->getAllObjectOrInterfaceNodes($type) as $objectOrInterface) {\n            foreach ($objectOrInterface->getFields() as $node) {\n                if ($node->getNameValue() === $fieldName) {\n                    $nodes[] = $node;\n                }\n            }\n        }\n\n        return $nodes;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @param string               $fieldName\n     * @param string               $argumentName\n     * @return InputValueDefinitionNode|null\n     */\n    protected function getFieldArgumentNode(\n        FieldsAwareInterface $type,\n        string $fieldName,\n        string $argumentName\n    ): ?InputValueDefinitionNode {\n        return $this->getAllFieldArgumentNodes($type, $fieldName, $argumentName)[0] ?? null;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @param string               $fieldName\n     * @param string               $argumentName\n     * @return InputValueDefinitionNode[]\n     */\n    protected function getAllFieldArgumentNodes(\n        FieldsAwareInterface $type,\n        string $fieldName,\n        string $argumentName\n    ): array {\n        $nodes = [];\n\n        $fieldNode = $this->getFieldNode($type, $fieldName);\n\n        if (null !== $fieldNode) {\n            foreach ($fieldNode->getArguments() as $node) {\n                if ($node->getNameValue() === $argumentName) {\n                    $nodes[] = $node;\n                }\n            }\n        }\n\n        return $nodes;\n    }\n\n    /**\n     * @param ObjectType $type\n     * @param string     $interfaceName\n     * @return NamedTypeNode|null\n     */\n    protected function getImplementsInterfaceNode(ObjectType $type, string $interfaceName): ?NamedTypeNode\n    {\n        return $this->getAllImplementsInterfaceNodes($type, $interfaceName)[0] ?? null;\n    }\n\n    /**\n     * @param ObjectType $type\n     * @param string     $interfaceName\n     * @return NamedTypeNode[]\n     */\n    protected function getAllImplementsInterfaceNodes(ObjectType $type, string $interfaceName): array\n    {\n        $nodes = [];\n\n        foreach ($this->getAllObjectOrInterfaceNodes($type) as $object) {\n            foreach ($object->getInterfaces() as $node) {\n                if ($node->getNameValue() === $interfaceName) {\n                    $nodes[] = $node;\n                }\n            }\n        }\n\n        return $nodes;\n    }\n\n    /**\n     * @param FieldsAwareInterface $type\n     * @param string               $fieldName\n     * @param string               $argumentName\n     * @return TypeNodeInterface|null\n     */\n    protected function getFieldArgumentTypeNode(\n        FieldsAwareInterface $type,\n        string $fieldName,\n        string $argumentName\n    ): ?TypeNodeInterface {\n        $node = $this->getFieldArgumentNode($type, $fieldName, $argumentName);\n        return null !== $node ? $node->getType() : null;\n    }\n\n    /**\n     * @param UnionType $unionType\n     * @param string    $memberTypeName\n     * @return array|null\n     */\n    protected function getUnionMemberTypeNodes(UnionType $unionType, string $memberTypeName): ?array\n    {\n        /** @var UnionTypeDefinitionNode|null $node */\n        $node = $unionType->getAstNode();\n\n        if (null === $node) {\n            return null;\n        }\n\n        return \\array_filter($node->getTypes(), function (NamedTypeNode $type) use ($memberTypeName) {\n            return $type->getNameValue() === $memberTypeName;\n        });\n    }\n\n    /**\n     * @param EnumType $enumType\n     * @param string   $valueName\n     * @return array|null\n     */\n    protected function getEnumValueNodes(EnumType $enumType, string $valueName): ?array\n    {\n        /** @var EnumTypeDefinitionNode|null $node */\n        $node = $enumType->getAstNode();\n\n        if (null === $node) {\n            return null;\n        }\n\n        return \\array_filter($node->getValues(), function (NameAwareInterface $type) use ($valueName) {\n            return $type->getNameValue() === $valueName;\n        });\n    }\n\n    /**\n     * @param mixed $node\n     */\n    protected function validateName($node): void\n    {\n        // Ensure names are valid, however introspection types opt out.\n        $error = NameHelper::isValidError($node->getName(), $node);\n\n        if (null !== $error) {\n            $this->context->reportError($error);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/SchemaValidationException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Validation\\ValidationExceptionInterface;\n\nclass SchemaValidationException extends GraphQLException implements ValidationExceptionInterface\n{\n}\n"
  },
  {
    "path": "src/Schema/Validation/SchemaValidationProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation;\n\nuse Digia\\GraphQL\\Schema\\Validation\\Rule\\DirectivesRule;\nuse Digia\\GraphQL\\Schema\\Validation\\Rule\\RootTypesRule;\nuse Digia\\GraphQL\\Schema\\Validation\\Rule\\TypesRule;\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass SchemaValidationProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        SchemaValidatorInterface::class,\n        RootTypesRule::class,\n        DirectivesRule::class,\n        TypesRule::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->share(SchemaValidatorInterface::class, SchemaValidator::class);\n\n        // Rules\n        $this->container->add(RootTypesRule::class, RootTypesRule::class);\n        $this->container->add(DirectivesRule::class, DirectivesRule::class);\n        $this->container->add(TypesRule::class, TypesRule::class);\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/SchemaValidator.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Schema\\Validation\\Rule\\RuleInterface;\nuse Digia\\GraphQL\\Schema\\Validation\\Rule\\SupportedRules;\nuse Digia\\GraphQL\\Validation\\ValidationExceptionInterface;\n\nclass SchemaValidator implements SchemaValidatorInterface\n{\n    /**\n     * @param Schema               $schema\n     * @param RuleInterface[]|null $rules\n     * @return ValidationExceptionInterface[]\n     */\n    public function validate(Schema $schema, ?array $rules = null): array\n    {\n        $context = $this->createContext($schema);\n\n        $rules = $rules ?? SupportedRules::build();\n\n        foreach ($rules as $rule) {\n            $rule->setContext($context)->evaluate();\n        }\n\n        return $context->getErrors();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function createContext(Schema $schema): ValidationContextInterface\n    {\n        return new ValidationContext($schema);\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/SchemaValidatorInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Schema\\Validation\\Rule\\RuleInterface;\n\ninterface SchemaValidatorInterface\n{\n    /**\n     * @param Schema               $schema\n     * @param RuleInterface[]|null $rules\n     * @return SchemaValidationException[]\n     */\n    public function validate(Schema $schema, ?array $rules = null): array;\n\n    /**\n     * @param Schema $schema\n     * @return ValidationContextInterface\n     */\n    public function createContext(Schema $schema): ValidationContextInterface;\n}\n"
  },
  {
    "path": "src/Schema/Validation/ValidationContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Validation\\ValidationExceptionInterface;\n\nclass ValidationContext implements ValidationContextInterface\n{\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @var ValidationExceptionInterface[]\n     */\n    protected $errors = [];\n\n    /**\n     * SchemaValidationContext constructor.\n     * @param Schema $schema\n     */\n    public function __construct(Schema $schema)\n    {\n        $this->schema = $schema;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function reportError(ValidationExceptionInterface $error): void\n    {\n        $this->errors[] = $error;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getErrors(): array\n    {\n        return $this->errors;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getSchema(): Schema\n    {\n        return $this->schema;\n    }\n}\n"
  },
  {
    "path": "src/Schema/Validation/ValidationContextInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema\\Validation;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Validation\\ValidationExceptionInterface;\n\ninterface ValidationContextInterface\n{\n    /**\n     * @param ValidationExceptionInterface $error\n     */\n    public function reportError(ValidationExceptionInterface $error): void;\n\n    /**\n     * @return ValidationExceptionInterface[]\n     */\n    public function getErrors(): array;\n\n    /**\n     * @return Schema\n     */\n    public function getSchema(): Schema;\n}\n"
  },
  {
    "path": "src/Schema/utils.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Schema;\n\n/**\n * @param string $description\n * @param int    $maxLength\n * @return array\n */\nfunction descriptionLines(string $description, int $maxLength): array\n{\n    // Map over the description lines and merge them into a flat array.\n    return \\array_merge(...\\array_map(function (string $line) use ($maxLength) {\n        if (\\strlen($line) < ($maxLength + 5)) {\n            return [$line];\n        }\n\n        // For > 120 character long lines, cut at space boundaries into sublines of ~80 chars.\n        return breakLine($line, $maxLength);\n    }, \\explode(\"\\n\", $description)));\n}\n\n/**\n * @param string $line\n * @param int    $maxLength\n * @return array\n */\nfunction breakLine(string $line, int $maxLength): array\n{\n    if (\\strlen($line) < ($maxLength + 5)) {\n        return [$line];\n    }\n\n    $endPos = $maxLength - 40;\n\n    return \\array_map('trim', \\preg_split(\n        \"/((?: |^).{15,{$endPos}}(?= |$))/\",\n        $line,\n        0,\n        PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE\n    ));\n}\n\n/**\n * @param string $line\n * @return string\n */\nfunction escapeQuotes(string $line): string\n{\n    return \\strtr($line, ['\"\"\"' => '\\\\\"\"\"', '`' => '\\`']);\n}\n\n/**\n * @param array $lines\n * @return string\n */\nfunction printLines(array $lines): string\n{\n    // Don't print empty lines\n    $lines = \\array_filter($lines, function (string $line) {\n        return $line !== '';\n    });\n\n    return printArray(\"\\n\", $lines);\n}\n\n/**\n * @param array $fields\n * @return string\n */\nfunction printInputFields(array $fields): string\n{\n    return '(' . printArray(', ', $fields) . ')';\n}\n\n/**\n * @param string $glue\n * @param array  $items\n * @return string\n */\nfunction printArray(string $glue, array $items): string\n{\n    return \\implode($glue, $items);\n}\n"
  },
  {
    "path": "src/Type/Coercer/AbstractCoercer.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\nabstract class AbstractCoercer implements CoercerInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Coercer/BooleanCoercer.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\n\nclass BooleanCoercer extends AbstractCoercer\n{\n    /**\n     * @inheritdoc\n     */\n    public function coerce($value): bool\n    {\n        if (!\\is_scalar($value)) {\n            throw new InvalidTypeException(\\sprintf('Boolean cannot represent a non-scalar value: %s', $value));\n        }\n\n        return (bool)$value;\n    }\n}\n"
  },
  {
    "path": "src/Type/Coercer/CoercerInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\ninterface CoercerInterface\n{\n    /**\n     * @param mixed $value\n     * @return mixed\n     */\n    public function coerce($value);\n}\n"
  },
  {
    "path": "src/Type/Coercer/CoercingException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass CoercingException extends GraphQLException\n{\n}\n"
  },
  {
    "path": "src/Type/Coercer/FloatCoercer.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\n\nclass FloatCoercer extends AbstractCoercer\n{\n    /**\n     * @inheritdoc\n     */\n    public function coerce($value): float\n    {\n        if ($value === '') {\n            throw new InvalidTypeException('Float cannot represent non numeric value: (empty string)');\n        }\n\n        if (\\is_numeric($value) || \\is_bool($value)) {\n            return (float)$value;\n        }\n\n        throw new InvalidTypeException(\\sprintf('Float cannot represent non numeric value: %s', $value));\n    }\n}\n"
  },
  {
    "path": "src/Type/Coercer/IntCoercer.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\n\nclass IntCoercer extends AbstractCoercer\n{\n    /**\n     * @inheritdoc\n     *\n     * @throws InvalidTypeException\n     */\n    public function coerce($value): int\n    {\n        if ($value === '') {\n            throw new InvalidTypeException('Int cannot represent non 32-bit signed integer value: (empty string)');\n        }\n\n        if (\\is_bool($value)) {\n            $value = (int)$value;\n        }\n\n        if (!\\is_numeric($value) || $value > PHP_INT_MAX || $value < PHP_INT_MIN) {\n            throw new InvalidTypeException(\n                \\sprintf('Int cannot represent non 32-bit signed integer value: %s', $value)\n            );\n        }\n\n        $floatValue = (float)$value;\n\n        if ($floatValue != $value || \\floor($floatValue) !== $floatValue) {\n            throw new InvalidTypeException(\\sprintf('Int cannot represent non-integer value: %s', $value));\n        }\n\n        return (int)$value;\n    }\n}\n"
  },
  {
    "path": "src/Type/Coercer/StringCoercer.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\n\nclass StringCoercer extends AbstractCoercer\n{\n    /**\n     * @inheritdoc\n     */\n    public function coerce($value): string\n    {\n        if ($value === null) {\n            return 'null';\n        }\n\n        if ($value === true) {\n            return 'true';\n        }\n\n        if ($value === false) {\n            return 'false';\n        }\n\n        if (!\\is_scalar($value)) {\n            throw new InvalidTypeException('String cannot represent a non-scalar value');\n        }\n\n        return (string)$value;\n    }\n}\n"
  },
  {
    "path": "src/Type/CoercerProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\Type\\Coercer\\BooleanCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\FloatCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\IntCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\StringCoercer;\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass CoercerProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        BooleanCoercer::class,\n        FloatCoercer::class,\n        IntCoercer::class,\n        StringCoercer::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->share(BooleanCoercer::class, BooleanCoercer::class);\n        $this->container->share(FloatCoercer::class, FloatCoercer::class);\n        $this->container->share(IntCoercer::class, IntCoercer::class);\n        $this->container->share(StringCoercer::class, StringCoercer::class);\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/AbstractTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ninterface AbstractTypeInterface extends NamedTypeInterface\n{\n    /**\n     * @param array ...$args\n     * @return mixed\n     */\n    public function resolveType(...$args);\n\n    /**\n     * @return bool\n     */\n    public function hasResolveTypeCallback(): bool;\n}\n"
  },
  {
    "path": "src/Type/Definition/Argument.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\n\nclass Argument implements InputValueInterface, ASTNodeAwareInterface, DescriptionAwareInterface\n{\n    use NameTrait;\n    use TypeTrait;\n    use DefaultValueTrait;\n    use DescriptionTrait;\n    use ASTNodeTrait;\n\n    /**\n     * Argument constructor.\n     *\n     * @param string                        $name\n     * @param null|string                   $description\n     * @param TypeInterface|null            $type\n     * @param mixed|null                    $defaultValue\n     * @param InputValueDefinitionNode|null $astNode\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        ?TypeInterface $type,\n        $defaultValue,\n        ?InputValueDefinitionNode $astNode\n    ) {\n        $this->name         = $name;\n        $this->description  = $description;\n        $this->type         = $type;\n        $this->defaultValue = $defaultValue;\n        $this->astNode      = $astNode;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/ArgumentsAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ninterface ArgumentsAwareInterface\n{\n    /**\n     * @return bool\n     */\n    public function hasArguments(): bool;\n\n    /**\n     * @return Argument[]\n     */\n    public function getArguments(): array;\n}\n"
  },
  {
    "path": "src/Type/Definition/ArgumentsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse function Digia\\GraphQL\\Type\\isAssocArray;\nuse function Digia\\GraphQL\\Type\\newArgument;\n\ntrait ArgumentsTrait\n{\n    /**\n     * @var array\n     */\n    protected $rawArguments = [];\n\n    /**\n     * @var Argument[]\n     */\n    protected $arguments;\n\n    /**\n     * @return string\n     */\n    public abstract function getName(): string;\n\n    /**\n     * @return array\n     */\n    public function getRawArguments(): array\n    {\n        return $this->rawArguments;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasArguments(): bool\n    {\n        return !empty($this->arguments);\n    }\n\n    /**\n     * @return Argument[]\n     */\n    public function getArguments(): array\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * @param string $typeName\n     * @param array  $rawArguments\n     * @return Argument[]\n     * @throws InvariantException\n     */\n    protected function buildArguments(string $typeName, array $rawArguments): array\n    {\n        if (!isAssocArray($rawArguments)) {\n            throw new InvariantException(\\sprintf(\n                '%s.%s args must be an object with argument names as keys.',\n                $typeName,\n                $this->getName()\n            ));\n        }\n\n        $arguments = [];\n\n        foreach ($rawArguments as $argumentName => $argumentConfig) {\n            $argumentConfig['name'] = $argumentName;\n\n            $arguments[] = newArgument($argumentConfig);\n        }\n\n        return $arguments;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/CompositeTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Tagging interface for composite types.\n */\ninterface CompositeTypeInterface extends TypeInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Definition/DefaultValue.php",
    "content": "<?php\n\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n\nclass DefaultValue\n{\n\n}"
  },
  {
    "path": "src/Type/Definition/DefaultValueTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait DefaultValueTrait\n{\n    /**\n     * @var mixed\n     */\n    protected $defaultValue;\n\n    /**\n     * @return bool\n     */\n    public function hasDefaultValue(): bool\n    {\n        return null !== $this->defaultValue;\n    }\n\n    /**\n     * @return mixed|null\n     */\n    public function getDefaultValue()\n    {\n        return $this->defaultValue;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/DeprecationAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Interface for GraphQL definitions that can be deprecated.\n */\ninterface DeprecationAwareInterface\n{\n    /**\n     * @return null|string\n     */\n    public function getDeprecationReason(): ?string;\n\n    /**\n     * @return bool\n     */\n    public function isDeprecated(): bool;\n}\n"
  },
  {
    "path": "src/Type/Definition/DeprecationTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait DeprecationTrait\n{\n    /**\n     * @var string|null\n     */\n    protected $deprecationReason;\n\n    /**\n     * @return null|string\n     */\n    public function getDeprecationReason(): ?string\n    {\n        return $this->deprecationReason;\n    }\n\n    /**\n     * @return bool\n     */\n    public function isDeprecated(): bool\n    {\n        return null !== $this->deprecationReason;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/DescriptionAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ninterface DescriptionAwareInterface\n{\n    /**\n     * @return null|string\n     */\n    public function getDescription(): ?string;\n}\n"
  },
  {
    "path": "src/Type/Definition/DescriptionTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait DescriptionTrait\n{\n    /**\n     * @var string|null\n     */\n    protected $description;\n\n    /**\n     * @return bool\n     */\n    public function hasDescription(): bool\n    {\n        return null !== $this->description;\n    }\n\n    /**\n     * @return null|string\n     */\n    public function getDescription(): ?string\n    {\n        return $this->description;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/Directive.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveDefinitionNode;\nuse Digia\\GraphQL\\Schema\\DefinitionInterface;\n\nclass Directive implements DefinitionInterface, ASTNodeAwareInterface, ArgumentsAwareInterface,\n    DescriptionAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use ArgumentsTrait;\n    use ASTNodeTrait;\n\n    /**\n     * @var string[]\n     */\n    protected $locations;\n\n    /**\n     * Directive constructor.\n     *\n     * @param string                       $name\n     * @param null|string                  $description\n     * @param string[]                     $locations\n     * @param array                        $rawArguments\n     * @param DirectiveDefinitionNode|null $astNode\n     * @param string                       $typeName\n     * @throws InvariantException\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        array $locations,\n        array $rawArguments,\n        ?DirectiveDefinitionNode $astNode,\n        string $typeName\n    ) {\n        $this->name         = $name;\n        $this->description  = $description;\n        $this->locations    = $locations;\n        $this->rawArguments = $rawArguments;\n        $this->astNode      = $astNode;\n\n        $this->arguments = $this->buildArguments($typeName, $this->rawArguments);\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getLocations(): array\n    {\n        return $this->locations;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/EnumType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse function Digia\\GraphQL\\Type\\isAssocArray;\nuse function Digia\\GraphQL\\Type\\newEnumValue;\nuse function Digia\\GraphQL\\Util\\toString;\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 *     $RGBType = newEnumType([\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 */\nclass EnumType implements NamedTypeInterface, InputTypeInterface, LeafTypeInterface,\n    OutputTypeInterface, SerializableTypeInterface, DescriptionAwareInterface, ASTNodeAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use ASTNodeTrait;\n\n    /**\n     * @var array\n     */\n    protected $rawValues;\n\n    /**\n     * A list of enum value instances.\n     *\n     * @var EnumValue[]\n     */\n    protected $values;\n\n    /**\n     * EnumType constructor.\n     *\n     * @param string                      $name\n     * @param null|string                 $description\n     * @param EnumValue[]                 $rawValues\n     * @param EnumTypeDefinitionNode|null $astNode\n     */\n    public function __construct(string $name, ?string $description, array $rawValues, ?EnumTypeDefinitionNode $astNode)\n    {\n        $this->name        = $name;\n        $this->description = $description;\n        $this->astNode     = $astNode;\n        $this->rawValues   = $rawValues;\n    }\n\n    /**\n     * @param mixed $value\n     * @return null|string\n     * @throws InvariantException\n     */\n    public function serialize($value)\n    {\n        $enumValue = $this->getValueByValue($value);\n\n        if ($enumValue) {\n            return $enumValue->getName();\n        }\n\n        return null;\n    }\n\n    /**\n     * @param mixed $value\n     * @return mixed|null\n     * @throws InvariantException\n     */\n    public function parseValue($value)\n    {\n        if (\\is_string($value)) {\n            $enumValue = $this->getValueByName($value);\n\n            if ($enumValue !== null) {\n                return $enumValue->getValue();\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return mixed|null\n     * @throws InvariantException\n     */\n    public function parseLiteral(NodeInterface $node)\n    {\n        if ($node instanceof EnumValueNode) {\n            $enumValue = $this->getValueByName($node->getValue());\n\n            if ($enumValue !== null) {\n                return $enumValue->getValue();\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param string $name\n     * @return EnumValue|null\n     * @throws InvariantException\n     */\n    public function getValue(string $name): ?EnumValue\n    {\n        return $this->getValueByName($name);\n    }\n\n    /**\n     * @return EnumValue[]\n     * @throws InvariantException\n     */\n    public function getValues(): array\n    {\n        if (!isset($this->values)) {\n            $this->values = $this->buildValues($this->rawValues);\n        }\n        return $this->values;\n    }\n\n    /**\n     * @param string $name\n     * @return EnumValue|null\n     * @throws InvariantException\n     */\n    protected function getValueByName(string $name): ?EnumValue\n    {\n        foreach ($this->getValues() as $enumValue) {\n            if ($enumValue->getName() === $name) {\n                return $enumValue;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param mixed $value\n     * @return EnumValue|null\n     * @throws InvariantException\n     */\n    protected function getValueByValue($value): ?EnumValue\n    {\n        foreach ($this->getValues() as $enumValue) {\n            if ($enumValue->getValue() === $value) {\n                return $enumValue;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param array $rawValues\n     * @return array\n     * @throws InvariantException\n     */\n    protected function buildValues(array $rawValues): array\n    {\n        if (!isAssocArray($rawValues)) {\n            throw new InvariantException(\\sprintf('%s values must be an associative array with value names as keys.',\n                $this->name));\n        }\n\n        $values = [];\n\n        foreach ($rawValues as $valueName => $valueConfig) {\n            if (!isAssocArray($valueConfig)) {\n                throw new InvariantException(\\sprintf(\n                    '%s.%s must refer to an object with a \"value\" key representing an internal value but got: %s.',\n                    $this->name,\n                    $valueName,\n                    toString($valueConfig)\n                ));\n            }\n\n            if (isset($valueConfig['isDeprecated'])) {\n                throw new InvariantException(\\sprintf(\n                    '%s.%s should provide \"deprecationReason\" instead of \"isDeprecated\".',\n                    $this->name,\n                    $valueName\n                ));\n            }\n\n            $valueConfig['name']  = $valueName;\n            $valueConfig['value'] = \\array_key_exists('value', $valueConfig)\n                ? $valueConfig['value']\n                : $valueName;\n\n            $values[] = newEnumValue($valueConfig);\n        }\n\n        return $values;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/EnumValue.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueDefinitionNode;\nuse Digia\\GraphQL\\Schema\\DefinitionInterface;\n\nclass EnumValue implements DefinitionInterface, ASTNodeAwareInterface, DescriptionAwareInterface,\n    DeprecationAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use DeprecationTrait;\n    use ValueTrait;\n    use ASTNodeTrait;\n\n    /**\n     * EnumValue constructor.\n     *\n     * @param string                       $name\n     * @param null|string                  $description\n     * @param null|string                  $deprecationReason\n     * @param EnumValueDefinitionNode|null $astNode\n     * @param mixed                        $value\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        ?string $deprecationReason,\n        ?EnumValueDefinitionNode $astNode,\n        $value\n    ) {\n        $this->name              = $name;\n        $this->description       = $description;\n        $this->deprecationReason = $deprecationReason;\n        $this->astNode           = $astNode;\n        $this->value             = $value;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/ExtensionASTNodesTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\n\ntrait ExtensionASTNodesTrait\n{\n    /**\n     * @var ObjectTypeExtensionNode[]|InterfaceTypeExtensionNode[]\n     */\n    protected $extensionAstNodes = [];\n\n    /**\n     * @return bool\n     */\n    public function hasExtensionAstNodes(): bool\n    {\n        return !empty($this->extensionAstNodes);\n    }\n\n    /**\n     * @return ObjectTypeExtensionNode[]|InterfaceTypeExtensionNode[]\n     */\n    public function getExtensionAstNodes(): array\n    {\n        return $this->extensionAstNodes;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/Field.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\n\nclass Field implements FieldInterface, ASTNodeAwareInterface, ArgumentsAwareInterface, DescriptionAwareInterface,\n    DeprecationAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use TypeTrait;\n    use ArgumentsTrait;\n    use ResolveTrait;\n    use DeprecationTrait;\n    use ASTNodeTrait;\n\n    /**\n     * @var callable|null\n     */\n    protected $subscribeCallback;\n\n    /**\n     * Field constructor.\n     *\n     * @param string                   $name\n     * @param null|string              $description\n     * @param TypeInterface|null       $type\n     * @param Argument[]|array[]       $rawArguments\n     * @param callable|null            $resolveCallback\n     * @param callable|null            $subscribeCallback\n     * @param null|string              $deprecationReason\n     * @param FieldDefinitionNode|null $astNode\n     * @param string                   $typeName\n     * @throws InvariantException\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        ?TypeInterface $type,\n        array $rawArguments,\n        ?callable $resolveCallback,\n        ?callable $subscribeCallback,\n        ?string $deprecationReason,\n        ?FieldDefinitionNode $astNode,\n        string $typeName\n    ) {\n        $this->name              = $name;\n        $this->description       = $description;\n        $this->type              = $type;\n        $this->rawArguments      = $rawArguments;\n        $this->resolveCallback   = $resolveCallback;\n        $this->subscribeCallback = $subscribeCallback;\n        $this->deprecationReason = $deprecationReason;\n        $this->astNode           = $astNode;\n\n        $this->arguments = $this->buildArguments($typeName, $this->rawArguments);\n    }\n\n    /**\n     * @param array ...$args\n     * @return mixed\n     */\n    public function subscribe(...$args)\n    {\n        return null !== $this->subscribeCallback\n            ? \\call_user_func_array($this->subscribeCallback, $args)\n            : null;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasSubscribeCallback()\n    {\n        return null !== $this->subscribeCallback;\n    }\n\n    /**\n     * @return callable|null\n     */\n    public function getSubscribeCallback(): ?callable\n    {\n        return $this->subscribeCallback;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/FieldInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Schema\\DefinitionInterface;\n\ninterface FieldInterface extends DefinitionInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Definition/FieldsAwareInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\n\ninterface FieldsAwareInterface\n{\n    /**\n     * @return string\n     */\n    public function getName(): string;\n\n    /**\n     * @return NodeInterface|null\n     */\n    public function getAstNode(): ?NodeInterface;\n\n    /**\n     * @return ObjectTypeExtensionNode[]\n     */\n    public function getExtensionAstNodes(): array;\n\n    /**\n     * @param string $fieldName\n     * @return Field|null\n     */\n    public function getField(string $fieldName): ?Field;\n\n    /**\n     * @return Field[]\n     */\n    public function getFields(): array;\n}\n"
  },
  {
    "path": "src/Type/Definition/FieldsTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse function Digia\\GraphQL\\Type\\isAssocArray;\nuse function Digia\\GraphQL\\Type\\newField;\nuse function Digia\\GraphQL\\Type\\resolveThunk;\nuse function Digia\\GraphQL\\Util\\toString;\n\ntrait FieldsTrait\n{\n    /**\n     * Fields can be defined either as an array or as a thunk.\n     * Using thunks allows for cross-referencing of fields.\n     *\n     * @var array|callable\n     */\n    protected $rawFieldsOrThunk;\n\n    /**\n     * A key-value map over field names and their corresponding field instances.\n     *\n     * @var Field[]\n     */\n    protected $fieldMap;\n\n    /**\n     * @return string\n     */\n    abstract public function getName(): string;\n\n    /**\n     * @param string $fieldName\n     * @return Field|null\n     * @throws InvariantException\n     */\n    public function getField(string $fieldName): ?Field\n    {\n        return $this->getFields()[$fieldName] ?? null;\n    }\n\n    /**\n     * @return Field[]\n     * @throws InvariantException\n     */\n    public function getFields(): array\n    {\n        // Fields are built lazily to avoid concurrency issues.\n        if (!isset($this->fieldMap)) {\n            $this->fieldMap = $this->buildFieldMap($this->rawFieldsOrThunk);\n        }\n\n        return $this->fieldMap;\n    }\n\n    /**\n     * @param array|callable $rawFieldsOrThunk\n     * @return Field[]\n     * @throws InvariantException\n     */\n    protected function buildFieldMap($rawFieldsOrThunk): array\n    {\n        $rawFields = resolveThunk($rawFieldsOrThunk);\n\n        if (!isAssocArray($rawFields)) {\n            throw new InvariantException(\\sprintf(\n                '%s fields must be an associative array with field names as keys or a ' .\n                'callable which returns such an array.',\n                $this->getName()\n            ));\n        }\n\n        $fieldMap = [];\n\n        foreach ($rawFields as $fieldName => $fieldConfig) {\n            if (!\\is_array($fieldConfig)) {\n                throw new InvariantException(\\sprintf('%s.%s field config must be an associative array.',\n                    $this->getName(), $fieldName));\n            }\n\n            if (isset($fieldConfig['isDeprecated'])) {\n                throw new InvariantException(\\sprintf(\n                    '%s.%s should provide \"deprecationReason\" instead of \"isDeprecated\".',\n                    $this->getName(),\n                    $fieldName\n                ));\n            }\n\n            if (isset($fieldConfig['resolve']) && !\\is_callable($fieldConfig['resolve'])) {\n                throw new InvariantException(\\sprintf(\n                    '%s.%s field resolver must be a function if provided, but got: %s.',\n                    $this->getName(),\n                    $fieldName,\n                    toString($fieldConfig['resolve'])\n                ));\n            }\n\n            $fieldConfig['name']     = $fieldName;\n            $fieldConfig['typeName'] = $this->getName();\n\n            $fieldMap[$fieldName] = newField($fieldConfig);\n        }\n\n        return $fieldMap;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/InputField.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\n\nclass InputField implements InputValueInterface, FieldInterface, ASTNodeAwareInterface, DescriptionAwareInterface\n{\n    use NameTrait;\n    use TypeTrait;\n    use DefaultValueTrait;\n    use DescriptionTrait;\n    use ASTNodeTrait;\n\n    /**\n     * InputField constructor.\n     *\n     * @param string                        $name\n     * @param TypeInterface|null            $type\n     * @param mixed|null                    $defaultValue\n     * @param null|string                   $description\n     * @param InputValueDefinitionNode|null $astNode\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        ?TypeInterface $type,\n        $defaultValue,\n        ?InputValueDefinitionNode $astNode\n    ) {\n        $this->name         = $name;\n        $this->type         = $type;\n        $this->defaultValue = $defaultValue;\n        $this->description  = $description;\n        $this->astNode      = $astNode;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/InputObjectType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse function Digia\\GraphQL\\Type\\isAssocArray;\nuse function Digia\\GraphQL\\Type\\newInputField;\nuse function Digia\\GraphQL\\Type\\resolveThunk;\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 *     $GeoPoint = newInputObjectType([\n *       'name': 'GeoPoint',\n *       'fields': [\n *         'lat': ['type' => newNonNull(floatType())],\n *         'lon': ['type' => newNonNull(floatType())],\n *         'alt': ['type' => floatType(), 'defaultValue' => 0],\n *       ]\n *     ]);\n */\nclass InputObjectType implements NamedTypeInterface, InputTypeInterface, DescriptionAwareInterface,\n    ASTNodeAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use ASTNodeTrait;\n\n    /**\n     * Fields can be defined either as an array or as a thunk.\n     * Using thunks allows for cross-referencing of fields.\n     *\n     * @var array|callable\n     */\n    protected $rawFieldsOrThunk;\n\n    /**\n     * A key-value map over field names and their corresponding field instances.\n     *\n     * @var InputField[]\n     */\n    protected $fieldMap;\n\n    /**\n     * InputObjectType constructor.\n     *\n     * @param string                             $name\n     * @param null|string                        $description\n     * @param array|callable                     $rawFieldsOrThunk\n     * @param InputObjectTypeDefinitionNode|null $astNode\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        $rawFieldsOrThunk,\n        ?InputObjectTypeDefinitionNode $astNode\n    ) {\n        $this->name             = $name;\n        $this->description      = $description;\n        $this->rawFieldsOrThunk = $rawFieldsOrThunk;\n        $this->astNode          = $astNode;\n    }\n\n    /**\n     * @param string $fieldName\n     * @return InputField|null\n     * @throws InvariantException\n     */\n    public function getField(string $fieldName): ?InputField\n    {\n        return $this->getFields()[$fieldName] ?? null;\n    }\n\n    /**\n     * @return InputField[]\n     * @throws InvariantException\n     */\n    public function getFields(): array\n    {\n        if (!isset($this->fieldMap)) {\n            $this->fieldMap = $this->buildFieldMap($this->rawFieldsOrThunk);\n        }\n\n        return $this->fieldMap;\n    }\n\n    /**\n     * @param array|callable $rawFieldsOrThunk\n     * @return array\n     * @throws InvariantException\n     */\n    protected function buildFieldMap($rawFieldsOrThunk): array\n    {\n        $rawFields = resolveThunk($rawFieldsOrThunk);\n\n        if (!isAssocArray($rawFields)) {\n            throw new InvariantException(\\sprintf(\n                '%s fields must be an associative array with field names as keys or a function which returns such an array.',\n                $this->name\n            ));\n        }\n\n        $fieldMap = [];\n\n        foreach ($rawFields as $fieldName => $fieldConfig) {\n            if (isset($fieldConfig['resolve'])) {\n                throw new InvariantException(\\sprintf(\n                    '%s.%s field type has a resolve property, but Input Types cannot define resolvers.',\n                    $this->name,\n                    $fieldName\n                ));\n            }\n\n            $fieldConfig['name'] = $fieldName;\n\n            $fieldMap[$fieldName] = newInputField($fieldConfig);\n        }\n\n        return $fieldMap;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/InputTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Tagging interface for input types.\n */\ninterface InputTypeInterface extends TypeInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Definition/InputValueInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Schema\\DefinitionInterface;\n\ninterface InputValueInterface extends DefinitionInterface\n{\n    /**\n     * @return string\n     */\n    public function getName(): string;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getType(): ?TypeInterface;\n\n    /**\n     * @return bool\n     */\n    public function hasDefaultValue(): bool;\n\n    /**\n     * @return null|mixed\n     */\n    public function getDefaultValue();\n}\n"
  },
  {
    "path": "src/Type/Definition/InterfaceType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\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 *     $EntityType = newInterfaceType([\n *       'name' => 'Entity',\n *       'fields' => [\n *         'name' => ['type' => stringType()]\n *       ]\n *     ]);\n */\nclass InterfaceType implements AbstractTypeInterface, CompositeTypeInterface,\n    OutputTypeInterface, DescriptionAwareInterface, FieldsAwareInterface, ASTNodeAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use FieldsTrait;\n    use ResolveTypeTrait;\n    use ASTNodeTrait;\n    use ExtensionASTNodesTrait;\n\n    /**\n     * InterfaceType constructor.\n     *\n     * @param string                           $name\n     * @param null|string                      $description\n     * @param array|callable                   $rawFieldsOrThunk\n     * @param callable|null                    $resolveTypeCallback\n     * @param InterfaceTypeDefinitionNode|null $astNode\n     * @param InterfaceTypeExtensionNode[]     $extensionASTNodes\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        $rawFieldsOrThunk,\n        ?callable $resolveTypeCallback,\n        ?InterfaceTypeDefinitionNode $astNode,\n        array $extensionASTNodes\n    ) {\n        $this->name                = $name;\n        $this->description         = $description;\n        $this->rawFieldsOrThunk    = $rawFieldsOrThunk;\n        $this->resolveTypeCallback = $resolveTypeCallback;\n        $this->astNode             = $astNode;\n        $this->extensionAstNodes   = $extensionASTNodes;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/LeafTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Tagging interface for leaf types.\n */\ninterface LeafTypeInterface extends TypeInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Definition/ListType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nclass ListType implements TypeInterface, WrappingTypeInterface\n{\n    use OfTypeTrait;\n\n    /**\n     * ListType constructor.\n     *\n     * @param TypeInterface $ofType\n     */\n    public function __construct(TypeInterface $ofType)\n    {\n        $this->ofType = $ofType;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return '[' . (string)$this->ofType . ']';\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/NameTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait NameTrait\n{\n    /**\n     * @var string\n     */\n    protected $name;\n\n    /**\n     * @return string\n     */\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return $this->name;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/NamedTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Interface for all named types (everything except List and NonNull).\n */\ninterface NamedTypeInterface extends TypeInterface\n{\n    /**\n     * @return string\n     */\n    public function getName(): string;\n}\n"
  },
  {
    "path": "src/Type/Definition/NonNullType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nclass NonNullType implements TypeInterface, WrappingTypeInterface\n{\n    use OfTypeTrait;\n\n    /**\n     * NonNullType constructor.\n     *\n     * @param TypeInterface $ofType\n     */\n    public function __construct(TypeInterface $ofType)\n    {\n        $this->ofType = $ofType;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function __toString(): string\n    {\n        return (string)$this->ofType . '!';\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/ObjectType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse React\\Promise\\PromiseInterface;\nuse function Digia\\GraphQL\\Type\\resolveThunk;\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 *     $AddressType = newObjectType([\n *       'name'   => 'Address',\n *       'fields' => [\n *         'street'    => ['type' => stringType()],\n *         'number'    => ['type' => intType()],\n *         'formatted' => [\n *           'type'    => stringType(),\n *           'resolve' => function ($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 *     $PersonType = newObjectType([\n *       'name' => 'Person',\n *       'fields' => function () {\n *         return [\n *           'name'       => ['type' => stringType()],\n *           'bestFriend' => ['type' => $PersonType],\n *         ];\n *       }\n *     ]);\n */\nclass ObjectType implements NamedTypeInterface, CompositeTypeInterface, OutputTypeInterface,\n    ASTNodeAwareInterface, DescriptionAwareInterface, FieldsAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use FieldsTrait;\n    use ResolveTrait;\n    use ASTNodeTrait;\n    use ExtensionASTNodesTrait;\n\n    /**\n     * @var callable\n     */\n    protected $isTypeOfCallback;\n\n    /**\n     * Interfaces can be defined either as an array or as a thunk.\n     * Using thunks allows for cross-referencing of interfaces.\n     *\n     * @var array|callable\n     */\n    protected $interfacesOrThunk;\n\n    /**\n     * A list of interface instances.\n     *\n     * @var InterfaceType[]|null\n     */\n    protected $interfaces;\n\n    /**\n     * ObjectType constructor.\n     *\n     * @param string                        $name\n     * @param null|string                   $description\n     * @param array|callable                $fieldsOrThunk\n     * @param array|callable                $interfacesOrThunk\n     * @param callable|null                 $isTypeOfCallback\n     * @param ObjectTypeDefinitionNode|null $astNode\n     * @param ObjectTypeExtensionNode[]     $extensionASTNodes\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        $fieldsOrThunk,\n        $interfacesOrThunk,\n        ?callable $isTypeOfCallback,\n        ?ObjectTypeDefinitionNode $astNode,\n        array $extensionASTNodes\n    ) {\n        $this->name              = $name;\n        $this->description       = $description;\n        $this->rawFieldsOrThunk  = $fieldsOrThunk;\n        $this->interfacesOrThunk = $interfacesOrThunk;\n        $this->isTypeOfCallback  = $isTypeOfCallback;\n        $this->astNode           = $astNode;\n        $this->extensionAstNodes = $extensionASTNodes;\n    }\n\n    /**\n     * @param mixed $value\n     * @param mixed $context\n     * @param mixed $info\n     * @return bool|PromiseInterface\n     */\n    public function isTypeOf($value, $context, $info)\n    {\n        return null !== $this->isTypeOfCallback\n            ? \\call_user_func($this->isTypeOfCallback, $value, $context, $info)\n            : false;\n    }\n\n    /**\n     * @return bool\n     * @throws InvariantException\n     */\n    public function hasInterfaces(): bool\n    {\n        return !empty($this->getInterfaces());\n    }\n\n    /**\n     * @return InterfaceType[]\n     * @throws InvariantException\n     */\n    public function getInterfaces(): array\n    {\n        if ($this->interfaces === null) {\n            $this->interfaces = $this->buildInterfaces($this->interfacesOrThunk);\n        }\n        return $this->interfaces;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasIsTypeOfCallback(): bool\n    {\n        return null !== $this->isTypeOfCallback;\n    }\n\n    /**\n     * @return null|callable\n     */\n    public function getIsTypeOfCallback(): ?callable\n    {\n        return $this->isTypeOfCallback;\n    }\n\n    /**\n     * @param array|callable $interfacesOrThunk\n     * @return array\n     * @throws InvariantException\n     */\n    protected function buildInterfaces($interfacesOrThunk): array\n    {\n        $interfaces = resolveThunk($interfacesOrThunk);\n\n        if (!\\is_array($interfaces)) {\n            throw new InvariantException(\n                \\sprintf('%s interfaces must be an array or a function which returns an array.', $this->name)\n            );\n        }\n\n        return $interfaces;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/OfTypeTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait OfTypeTrait\n{\n    /**\n     * @var TypeInterface\n     */\n    protected $ofType;\n\n    /**\n     * @return TypeInterface\n     */\n    public function getOfType(): TypeInterface\n    {\n        return $this->ofType;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/OutputTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Tagging interface for output types.\n */\ninterface OutputTypeInterface extends TypeInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Definition/ResolveTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait ResolveTrait\n{\n    /**\n     * @var callable|null\n     */\n    protected $resolveCallback;\n\n    /**\n     * @param array ...$args\n     * @return mixed\n     */\n    public function resolve(...$args)\n    {\n        return null !== $this->resolveCallback\n            ? \\call_user_func_array($this->resolveCallback, $args)\n            : null;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasResolveCallback()\n    {\n        return null !== $this->resolveCallback;\n    }\n\n    /**\n     * @return callable|null\n     */\n    public function getResolveCallback(): ?callable\n    {\n        return $this->resolveCallback;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/ResolveTypeTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait ResolveTypeTrait\n{\n\n    /**\n     * @var callable|null\n     */\n    protected $resolveTypeCallback;\n\n    /**\n     * @param array ...$args\n     * @return TypeInterface|string|null\n     */\n    public function resolveType(...$args)\n    {\n        return null !== $this->resolveTypeCallback\n            ? \\call_user_func_array($this->resolveTypeCallback, $args)\n            : null;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasResolveTypeCallback(): bool\n    {\n        return null !== $this->resolveTypeCallback;\n    }\n\n    /**\n     * @return callable|null\n     */\n    public function getResolveTypeCallback(): ?callable\n    {\n        return $this->resolveTypeCallback;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/ScalarType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\n\nclass ScalarType implements NamedTypeInterface, LeafTypeInterface, InputTypeInterface,\n    OutputTypeInterface, SerializableTypeInterface, ASTNodeAwareInterface, DescriptionAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use ASTNodeTrait;\n\n    /**\n     * @var callable\n     */\n    protected $serializeCallback;\n\n    /**\n     * @var callable|null\n     */\n    protected $parseValueCallback;\n\n    /**\n     * @var callable|null\n     */\n    protected $parseLiteralCallback;\n\n    /**\n     * ScalarType constructor.\n     *\n     * @param string                        $name\n     * @param null|string                   $description\n     * @param callable                      $serializeCallback\n     * @param callable|null                 $parseValueCallback\n     * @param callable|null                 $parseLiteralCallback\n     * @param ScalarTypeDefinitionNode|null $astNode\n     * @throws InvariantException\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        callable $serializeCallback,\n        ?callable $parseValueCallback,\n        ?callable $parseLiteralCallback,\n        ?ScalarTypeDefinitionNode $astNode\n    ) {\n        $this->name                 = $name;\n        $this->description          = $description;\n        $this->serializeCallback    = $serializeCallback;\n        $this->parseValueCallback   = $parseValueCallback;\n        $this->parseLiteralCallback = $parseLiteralCallback;\n        $this->astNode              = $astNode;\n    }\n\n    /**\n     * @param mixed $value\n     * @return mixed\n     */\n    public function serialize($value)\n    {\n        return \\call_user_func($this->serializeCallback, $value);\n    }\n\n    /**\n     * @param mixed $value\n     * @return mixed|null\n     */\n    public function parseValue($value)\n    {\n        return null !== $this->parseValueCallback\n            ? \\call_user_func($this->parseValueCallback, $value)\n            : null;\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @param array|null    $variables\n     * @return mixed|null\n     */\n    public function parseLiteral(NodeInterface $node, ?array $variables = null)\n    {\n        return null !== $this->parseLiteralCallback\n            ? \\call_user_func($this->parseLiteralCallback, $node, $variables)\n            : null;\n    }\n\n    /**\n     * @param mixed $value\n     * @return bool\n     */\n    public function isValidValue($value): bool\n    {\n        return null !== $this->parseValue($value);\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return bool\n     */\n    public function isValidLiteral(NodeInterface $node): bool\n    {\n        return null !== $this->parseLiteral($node);\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/SerializableTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\n/**\n * Tagging interface for serializable types (Enum and Scalar).\n */\ninterface SerializableTypeInterface extends TypeInterface\n{\n    /**\n     * @param mixed $value\n     * @return mixed\n     */\n    public function serialize($value);\n\n    /**\n     * @param mixed $value\n     * @return mixed|null\n     */\n    public function parseValue($value);\n\n    /**\n     * @param NodeInterface $node\n     * @return mixed|null\n     */\n    public function parseLiteral(NodeInterface $node);\n}\n"
  },
  {
    "path": "src/Type/Definition/SpecifiedDirectiveEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nclass SpecifiedDirectiveEnum\n{\n    public const INCLUDE    = 'include';\n    public const SKIP       = 'skip';\n    public const DEPRECATED = 'deprecated';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return \\array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/TypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Schema\\DefinitionInterface;\n\n/**\n * Tagging interface for GraphQL types.\n */\ninterface TypeInterface extends DefinitionInterface\n{\n}\n"
  },
  {
    "path": "src/Type/Definition/TypeNameEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nclass TypeNameEnum\n{\n    public const INT       = 'Int';\n    public const FLOAT     = 'Float';\n    public const STRING    = 'String';\n    public const BOOLEAN   = 'Boolean';\n    public const ID        = 'ID';\n    public const INTERFACE = 'Interface';\n    public const ENUM      = 'Enum';\n    public const UNION     = 'Union';\n    public const LIST      = 'List';\n    public const NULL      = 'Null';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return \\array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/TypeTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait TypeTrait\n{\n    /**\n     * @var TypeInterface|null\n     */\n    protected $type;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getType(): ?TypeInterface\n    {\n        return $this->type;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/UnionType.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\ASTNodeTrait;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse function Digia\\GraphQL\\Type\\resolveThunk;\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 *     $PetType = newUnionType([\n *       'name' => 'Pet',\n *       'types' => [$DogType, $CatType],\n *       'resolveType' => function ($value) {\n *         if ($value instanceof Dog) {\n *           return $DogType;\n *         }\n *         if ($value instanceof Cat) {\n *           return $CatType;\n *         }\n *       }\n *     ]);\n */\nclass UnionType implements AbstractTypeInterface, CompositeTypeInterface, OutputTypeInterface,\n    ASTNodeAwareInterface, DescriptionAwareInterface\n{\n    use NameTrait;\n    use DescriptionTrait;\n    use ResolveTypeTrait;\n    use ASTNodeTrait;\n\n    /**\n     * Types can be defined either as an array or as a thunk.\n     * Using thunks allows for cross-referencing of types.\n     *\n     * @var array|callable\n     */\n    protected $typesOrThunk;\n\n    /**\n     * A key-value map over type names and their corresponding type instances.\n     *\n     * @var TypeInterface[]\n     */\n    protected $typeMap;\n\n    /**\n     * UnionType constructor.\n     *\n     * @param string                       $name\n     * @param null|string                  $description\n     * @param array|callable               $typesOrThunk\n     * @param callable|null                $resolveTypeCallback\n     * @param UnionTypeDefinitionNode|null $astNode\n     */\n    public function __construct(\n        string $name,\n        ?string $description,\n        $typesOrThunk,\n        ?callable $resolveTypeCallback,\n        ?UnionTypeDefinitionNode $astNode\n    ) {\n        $this->name                = $name;\n        $this->description         = $description;\n        $this->typesOrThunk        = $typesOrThunk;\n        $this->resolveTypeCallback = $resolveTypeCallback;\n        $this->astNode             = $astNode;\n    }\n\n    /**\n     * @return NamedTypeInterface[]\n     * @throws InvariantException\n     */\n    public function getTypes(): array\n    {\n        // Types are built lazily to avoid concurrency issues.\n        if (!isset($this->typeMap)) {\n            $this->typeMap = $this->buildTypeMap($this->typesOrThunk);\n        }\n\n        return $this->typeMap;\n    }\n\n    /**\n     * @param array|callable $typesOrThunk\n     * @return array\n     * @throws InvariantException\n     */\n    protected function buildTypeMap($typesOrThunk): array\n    {\n        $typeMap = resolveThunk($typesOrThunk);\n\n        if (!\\is_array($typeMap)) {\n            throw new InvariantException(\\sprintf(\n                'Must provide array of types or a function which returns such an array for Union %s.',\n                $this->name\n            ));\n        }\n\n        return $typeMap;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/ValueTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\ntrait ValueTrait\n{\n    /**\n     * @var mixed|null\n     */\n    protected $value;\n\n    /**\n     * @return mixed|null\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "src/Type/Definition/WrappingTypeInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type\\Definition;\n\n/**\n * Tagging interface for wrapping types.\n */\ninterface WrappingTypeInterface extends TypeInterface\n{\n    /**\n     * @return TypeInterface\n     */\n    public function getOfType(): TypeInterface;\n}\n"
  },
  {
    "path": "src/Type/DirectivesProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\DirectiveLocationEnum;\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass DirectivesProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        GraphQL::INCLUDE_DIRECTIVE,\n        GraphQL::SKIP_DIRECTIVE,\n        GraphQL::DEPRECATED_DIRECTIVE,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container\n            ->share(GraphQL::INCLUDE_DIRECTIVE, function () {\n                return newDirective([\n                    'name'        => 'include',\n                    'description' =>\n                        'Directs the executor to include this field or fragment only when ' .\n                        'the `if` argument is true.',\n                    'locations'   => [\n                        DirectiveLocationEnum::FIELD,\n                        DirectiveLocationEnum::FRAGMENT_SPREAD,\n                        DirectiveLocationEnum::INLINE_FRAGMENT,\n                    ],\n                    'args'        => [\n                        'if' => [\n                            'type'        => newNonNull(booleanType()),\n                            'description' => 'Included when true.',\n                        ],\n                    ],\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::SKIP_DIRECTIVE, function () {\n                return newDirective([\n                    'name'        => 'skip',\n                    'description' =>\n                        'Directs the executor to skip this field or fragment when the `if` ' .\n                        'argument is true.',\n                    'locations'   => [\n                        DirectiveLocationEnum::FIELD,\n                        DirectiveLocationEnum::FRAGMENT_SPREAD,\n                        DirectiveLocationEnum::INLINE_FRAGMENT,\n                    ],\n                    'args'        => [\n                        'if' => [\n                            'type'        => newNonNull(booleanType()),\n                            'description' => 'Skipped when true.',\n                        ],\n                    ],\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::DEPRECATED_DIRECTIVE, function () {\n                return newDirective([\n                    'name'        => 'deprecated',\n                    'description' => 'Marks an element of a GraphQL schema as no longer supported.',\n                    'locations'   => [\n                        DirectiveLocationEnum::FIELD_DEFINITION,\n                        DirectiveLocationEnum::ENUM_VALUE,\n                    ],\n                    'args'        => [\n                        'reason' => [\n                            'type'         => stringType(),\n                            'description'  =>\n                                'Explains why this element was deprecated, usually also including a suggestion ' .\n                                'for how to access supported similar data. Formatted using the Markdown syntax ' .\n                                '(as specified by [CommonMark](https://commonmark.org/).',\n                            'defaultValue' => DEFAULT_DEPRECATION_REASON,\n                        ],\n                    ]\n                ]);\n            });\n    }\n}\n"
  },
  {
    "path": "src/Type/IntrospectionProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\DirectiveLocationEnum;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\AbstractTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ArgumentsAwareInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass IntrospectionProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        // Introspection types\n        GraphQL::SCHEMA_INTROSPECTION,\n        GraphQL::DIRECTIVE_INTROSPECTION,\n        GraphQL::DIRECTIVE_LOCATION_INTROSPECTION,\n        GraphQL::TYPE_INTROSPECTION,\n        GraphQL::FIELD_INTROSPECTION,\n        GraphQL::INPUT_VALUE_INTROSPECTION,\n        GraphQL::ENUM_VALUE_INTROSPECTION,\n        GraphQL::TYPE_KIND_INTROSPECTION,\n        // Meta fields\n        GraphQL::SCHEMA_META_FIELD_DEFINITION,\n        GraphQL::TYPE_META_FIELD_DEFINITION,\n        GraphQL::TYPE_NAME_META_FIELD_DEFINITION,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->registerIntrospectionTypes();\n        $this->registerMetaFields();\n    }\n\n    /**\n     * Registers the introspection types with the container.\n     */\n    protected function registerIntrospectionTypes()\n    {\n        $this->container\n            ->share(GraphQL::SCHEMA_INTROSPECTION, function () {\n                return newObjectType([\n                    'name'            => GraphQL::SCHEMA_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'A GraphQL Schema defines the capabilities of a GraphQL server. It ' .\n                        'exposes all available types and directives on the server, as well as ' .\n                        'the entry points for query, mutation, and subscription operations.',\n                    'fields'          => function () {\n                        return [\n                            'types'            => [\n                                'description' => 'A list of all types supported by this server.',\n                                'type'        => newNonNull(newList(newNonNull(__Type()))),\n                                'resolve'     => function (Schema $schema): array {\n                                    return \\array_values($schema->getTypeMap());\n                                },\n                            ],\n                            'queryType'        => [\n                                'description' => 'The type that query operations will be rooted at.',\n                                'type'        => newNonNull(__Type()),\n                                'resolve'     => function (Schema $schema): ?TypeInterface {\n                                    return $schema->getQueryType();\n                                },\n                            ],\n                            'mutationType'     => [\n                                'description' =>\n                                    'If this server supports mutation, the type that ' .\n                                    'mutation operations will be rooted at.',\n                                'type'        => __Type(),\n                                'resolve'     => function (Schema $schema): ?TypeInterface {\n                                    return $schema->getMutationType();\n                                },\n                            ],\n                            'subscriptionType' => [\n                                'description' =>\n                                    'If this server support subscription, the type that ' .\n                                    'subscription operations will be rooted at.',\n                                'type'        => __Type(),\n                                'resolve'     => function (Schema $schema): ?TypeInterface {\n                                    return $schema->getSubscriptionType();\n                                },\n                            ],\n                            'directives'       => [\n                                'description' => 'A list of all directives supported by this server.',\n                                'type'        => newNonNull(newList(newNonNull(__Directive()))),\n                                'resolve'     => function (Schema $schema): array {\n                                    return $schema->getDirectives();\n                                },\n                            ],\n                        ];\n                    }\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::DIRECTIVE_INTROSPECTION, function () {\n                return newObjectType([\n                    'name'            => GraphQL::DIRECTIVE_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'A Directive provides a way to describe alternate runtime execution and ' .\n                        'type validation behavior in a GraphQL document.' .\n                        \"\\n\\nIn some cases, you need to provide options to alter GraphQL's \" .\n                        'execution behavior in ways field arguments will not suffice, such as ' .\n                        'conditionally including or skipping a field. Directives provide this by ' .\n                        'describing additional information to the executor.',\n                    'fields'          => function () {\n                        return [\n                            'name'        => ['type' => newNonNull(stringType())],\n                            'description' => ['type' => stringType()],\n                            'locations'   => [\n                                'type' => newNonNull(newList(newNonNull(__DirectiveLocation()))),\n                            ],\n                            'args'        => [\n                                'type'    => newNonNull(newList(newNonNull(__InputValue()))),\n                                'resolve' => function (Directive $directive): array {\n                                    return $directive->getArguments() ?: [];\n                                },\n                            ],\n                        ];\n                    }\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::DIRECTIVE_LOCATION_INTROSPECTION, function () {\n                return newEnumType([\n                    'name'            => GraphQL::DIRECTIVE_LOCATION_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'A Directive can be adjacent to many parts of the GraphQL language, a ' .\n                        '__DirectiveLocation describes one such possible adjacencies.',\n                    'values'          => [\n                        DirectiveLocationEnum::QUERY                  => [\n                            'description' => 'Location adjacent to a query operation.',\n                        ],\n                        DirectiveLocationEnum::MUTATION               => [\n                            'description' => 'Location adjacent to a mutation operation.',\n                        ],\n                        DirectiveLocationEnum::SUBSCRIPTION           => [\n                            'description' => 'Location adjacent to a subscription operation.',\n                        ],\n                        DirectiveLocationEnum::FIELD                  => [\n                            'description' => 'Location adjacent to a field.',\n                        ],\n                        DirectiveLocationEnum::FRAGMENT_DEFINITION    => [\n                            'description' => 'Location adjacent to a fragment definition.',\n                        ],\n                        DirectiveLocationEnum::FRAGMENT_SPREAD        => [\n                            'description' => 'Location adjacent to a fragment spread.',\n                        ],\n                        DirectiveLocationEnum::INLINE_FRAGMENT        => [\n                            'description' => 'Location adjacent to an inline fragment.',\n                        ],\n                        DirectiveLocationEnum::VARIABLE_DEFINITION => [\n                            'description' => 'Location adjacent to a variable definition.',\n                        ],\n                        DirectiveLocationEnum::SCHEMA                 => [\n                            'description' => 'Location adjacent to a schema definition.',\n                        ],\n                        DirectiveLocationEnum::SCALAR                 => [\n                            'description' => 'Location adjacent to a scalar definition.',\n                        ],\n                        DirectiveLocationEnum::OBJECT                 => [\n                            'description' => 'Location adjacent to an object type definition.',\n                        ],\n                        DirectiveLocationEnum::FIELD_DEFINITION       => [\n                            'description' => 'Location adjacent to a field definition.',\n                        ],\n                        DirectiveLocationEnum::ARGUMENT_DEFINITION    => [\n                            'description' => 'Location adjacent to an argument definition.',\n                        ],\n                        DirectiveLocationEnum::INTERFACE              => [\n                            'description' => 'Location adjacent to an interface definition.',\n                        ],\n                        DirectiveLocationEnum::UNION                  => [\n                            'description' => 'Location adjacent to a union definition.',\n                        ],\n                        DirectiveLocationEnum::ENUM                   => [\n                            'description' => 'Location adjacent to an enum definition.',\n                        ],\n                        DirectiveLocationEnum::ENUM_VALUE             => [\n                            'description' => 'Location adjacent to an enum value definition.',\n                        ],\n                        DirectiveLocationEnum::INPUT_OBJECT           => [\n                            'description' => 'Location adjacent to an input object type definition.',\n                        ],\n                        DirectiveLocationEnum::INPUT_FIELD_DEFINITION => [\n                            'description' => 'Location adjacent to an input object field definition.',\n                        ],\n                    ],\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::TYPE_INTROSPECTION, function () {\n                return newObjectType([\n                    'name'            => GraphQL::TYPE_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'The fundamental unit of any GraphQL Schema is the type. There are many kinds of ' .\n                        \"types in GraphQL as represented by the `__TypeKind` enum.\\n\\n\" .\n                        'Depending on the kind of a type, certain fields describe information about that ' .\n                        'type. Scalar types provide no information beyond a name and description, while ' .\n                        'Enum types provide their values. Object and Interface types provide the fields ' .\n                        'they describe. Abstract types, Union and Interface, provide the Object types ' .\n                        'possible at runtime. List and NonNull types compose other types.',\n                    'fields'          => function () {\n                        return [\n                            'kind'          => [\n                                'type'    => newNonNull(__TypeKind()),\n                                'resolve' => function (TypeInterface $type) {\n                                    if ($type instanceof ScalarType) {\n                                        return TypeKindEnum::SCALAR;\n                                    }\n                                    if ($type instanceof ObjectType) {\n                                        return TypeKindEnum::OBJECT;\n                                    }\n                                    if ($type instanceof InterfaceType) {\n                                        return TypeKindEnum::INTERFACE;\n                                    }\n                                    if ($type instanceof UnionType) {\n                                        return TypeKindEnum::UNION;\n                                    }\n                                    if ($type instanceof EnumType) {\n                                        return TypeKindEnum::ENUM;\n                                    }\n                                    if ($type instanceof InputObjectType) {\n                                        return TypeKindEnum::INPUT_OBJECT;\n                                    }\n                                    if ($type instanceof ListType) {\n                                        return TypeKindEnum::LIST;\n                                    }\n                                    if ($type instanceof NonNullType) {\n                                        return TypeKindEnum::NON_NULL;\n                                    }\n\n                                    throw new InvalidTypeException(\\sprintf('Unknown kind of type: %s', (string)$type));\n                                },\n                            ],\n                            'name'          => ['type' => stringType()],\n                            'description'   => ['type' => stringType()],\n                            'fields'        => [\n                                'type'    => newList(newNonNull(__Field())),\n                                'args'    => [\n                                    'includeDeprecated' => ['type' => booleanType(), 'defaultValue' => false],\n                                ],\n                                'resolve' => function (TypeInterface $type, array $args):\n                                ?array {\n                                    ['includeDeprecated' => $includeDeprecated] = $args;\n\n                                    if ($type instanceof ObjectType || $type instanceof InterfaceType) {\n                                        $fields = \\array_values($type->getFields());\n\n                                        if (!$includeDeprecated) {\n                                            $fields = \\array_filter($fields, function (Field $field) {\n                                                return !$field->isDeprecated();\n                                            });\n                                        }\n\n                                        return $fields;\n                                    }\n\n                                    return null;\n                                },\n                            ],\n                            'interfaces'    => [\n                                'type'    => newList(newNonNull(__Type())),\n                                'resolve' => function (TypeInterface $type): ?array {\n                                    return $type instanceof ObjectType ? $type->getInterfaces() : null;\n                                },\n                            ],\n                            'possibleTypes' => [\n                                'type'    => newList(newNonNull(__Type())),\n                                'resolve' => function (\n                                    TypeInterface $type,\n                                    array $args,\n                                    array $context,\n                                    ResolveInfo $info\n                                ):\n                                ?array {\n                                    /** @var Schema $schema */\n                                    $schema = $info->getSchema();\n                                    /** @noinspection PhpParamsInspection */\n                                    return $type instanceof AbstractTypeInterface ? $schema->getPossibleTypes($type) : null;\n                                },\n                            ],\n                            'enumValues'    => [\n                                'type'    => newList(newNonNull(__EnumValue())),\n                                'args'    => [\n                                    'includeDeprecated' => ['type' => booleanType(), 'defaultValue' => false],\n                                ],\n                                'resolve' => function (TypeInterface $type, array $args): ?array {\n                                    ['includeDeprecated' => $includeDeprecated] = $args;\n\n                                    if ($type instanceof EnumType) {\n                                        $values = \\array_values($type->getValues());\n\n                                        if (!$includeDeprecated) {\n                                            $values = \\array_filter($values, function (Field $field) {\n                                                return !$field->isDeprecated();\n                                            });\n                                        }\n\n                                        return $values;\n                                    }\n\n                                    return null;\n                                },\n                            ],\n                            'inputFields'   => [\n                                'type'    => newList(newNonNull(__InputValue())),\n                                'resolve' => function (TypeInterface $type): ?array {\n                                    return $type instanceof InputObjectType ? $type->getFields() : null;\n                                },\n                            ],\n                            'ofType'        => ['type' => __Type()],\n                        ];\n                    }\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::FIELD_INTROSPECTION, function () {\n                return newObjectType([\n                    'name'            => GraphQL::FIELD_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'Object and Interface types are described by a list of Fields, each of ' .\n                        'which has a name, potentially a list of arguments, and a return type.',\n                    'fields'          => function () {\n                        return [\n                            'name'              => ['type' => newNonNull(stringType())],\n                            'description'       => ['type' => stringType()],\n                            'args'              => [\n                                'type'    => newNonNull(newList(newNonNull(__InputValue()))),\n                                'resolve' => function (ArgumentsAwareInterface $directive): array {\n                                    return $directive->getArguments() ?? [];\n                                },\n                            ],\n                            'type'              => ['type' => newNonNull(__Type())],\n                            'isDeprecated'      => ['type' => newNonNull(booleanType())],\n                            'deprecationReason' => ['type' => stringType()],\n                        ];\n                    }\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::INPUT_VALUE_INTROSPECTION, function () {\n                return newObjectType([\n                    'name'            => GraphQL::INPUT_VALUE_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'Arguments provided to Fields or Directives and the input fields of an ' .\n                        'InputObject are represented as Input Values which describe their type ' .\n                        'and optionally a default value.',\n                    'fields'          => function () {\n                        return [\n                            'name'         => ['type' => newNonNull(stringType())],\n                            'description'  => ['type' => stringType()],\n                            'type'         => ['type' => newNonNull(__Type())],\n                            'defaultValue' => [\n                                'type'        => stringType(),\n                                'description' =>\n                                    'A GraphQL-formatted string representing the default value for this ' .\n                                    'input value.',\n                                'resolve'     => function (/*$inputValue*/) {\n                                    // TODO: Implement this when we have support for printing AST.\n                                    return null;\n                                }\n                            ],\n                        ];\n                    }\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::ENUM_VALUE_INTROSPECTION, function () {\n                return newObjectType([\n                    'name'            => GraphQL::ENUM_VALUE_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     =>\n                        'One possible value for a given Enum. Enum values are unique values, not ' .\n                        'a placeholder for a string or numeric value. However an Enum value is ' .\n                        'returned in a JSON response as a string.',\n                    'fields'          => function () {\n                        return [\n                            'name'              => ['type' => newNonNull(stringType())],\n                            'description'       => ['type' => stringType()],\n                            'isDeprecated'      => ['type' => newNonNull(booleanType())],\n                            'deprecationReason' => ['type' => stringType()],\n                        ];\n                    }\n                ]);\n            });\n\n        $this->container\n            ->share(GraphQL::TYPE_KIND_INTROSPECTION, function () {\n                return newEnumType([\n                    'name'            => GraphQL::TYPE_KIND_INTROSPECTION,\n                    'isIntrospection' => true,\n                    'description'     => 'An enum describing what kind of type a given `__Type` is.',\n                    'values'          => [\n                        TypeKindEnum::SCALAR       => [\n                            'description' => 'Indicates this type is a scalar.',\n                        ],\n                        TypeKindEnum::OBJECT       => [\n                            'description' => 'Indicates this type is an object. `fields` and `interfaces` are valid fields.',\n                        ],\n                        TypeKindEnum::INTERFACE    => [\n                            'description' => 'Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.',\n                        ],\n                        TypeKindEnum::UNION        => [\n                            'description' => 'Indicates this type is a union. `possibleTypes` is a valid field.',\n                        ],\n                        TypeKindEnum::ENUM         => [\n                            'description' => 'Indicates this type is an enum. `enumValues` is a valid field.',\n                        ],\n                        TypeKindEnum::INPUT_OBJECT => [\n                            'description' => 'Indicates this type is an input object. `inputFields` is a valid field.',\n                        ],\n                        TypeKindEnum::LIST         => [\n                            'description' => 'Indicates this type is a list. `ofType` is a valid field.',\n                        ],\n                        TypeKindEnum::NON_NULL     => [\n                            'description' => 'Indicates this type is a non-null. `ofType` is a valid field.',\n                        ],\n                    ],\n                ]);\n            });\n    }\n\n    /**\n     * Registers the introspection meta fields with the container.\n     */\n    protected function registerMetaFields()\n    {\n        $this->container\n            ->share(GraphQL::SCHEMA_META_FIELD_DEFINITION, function ($__Schema) {\n                return newField([\n                    'name'        => '__schema',\n                    'description' => 'Access the current type schema of this server.',\n                    'type'        => newNonNull($__Schema),\n                    'resolve'     => function ($source, $args, $context, ResolveInfo $info): Schema {\n                        return $info->getSchema();\n                    },\n                ]);\n            })\n            ->addArgument(GraphQL::SCHEMA_INTROSPECTION);\n\n        $this->container\n            ->share(GraphQL::TYPE_META_FIELD_DEFINITION, function ($__Type) {\n                return newField([\n                    'name'        => '__type',\n                    'description' => 'Request the type information of a single type.',\n                    'type'        => $__Type,\n                    'args'        => ['name' => ['type' => newNonNull(stringType())]],\n                    'resolve'     => function ($source, $args, $context, ResolveInfo $info): ?TypeInterface {\n                        ['name' => $name] = $args;\n                        return $info->getSchema()->getType($name);\n                    },\n                ]);\n            })\n            ->addArgument(GraphQL::TYPE_INTROSPECTION);\n\n        $this->container\n            ->share(GraphQL::TYPE_NAME_META_FIELD_DEFINITION, function () {\n                return newField([\n                    'name'        => '__typename',\n                    'description' => 'The name of the current Object type at runtime.',\n                    'type'        => newNonNull(stringType()),\n                    'resolve'     => function ($source, $args, $context, ResolveInfo $info): string {\n                        return $info->getParentType()->getName();\n                    },\n                ]);\n            });\n    }\n}\n"
  },
  {
    "path": "src/Type/ScalarTypesProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Type\\Coercer\\BooleanCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\FloatCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\IntCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\StringCoercer;\nuse Digia\\GraphQL\\Type\\Definition\\TypeNameEnum;\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass ScalarTypesProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        GraphQL::BOOLEAN,\n        GraphQL::FLOAT,\n        GraphQL::INT,\n        GraphQL::ID,\n        GraphQL::STRING,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container\n            ->share(GraphQL::BOOLEAN, function (BooleanCoercer $coercer) {\n                return newScalarType([\n                    'name'         => TypeNameEnum::BOOLEAN,\n                    'description'  => 'The `Boolean` scalar type represents `true` or `false`.',\n                    'serialize'    => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseValue'   => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseLiteral' => function (NodeInterface $node) {\n                        if ($node instanceof BooleanValueNode) {\n                            return $node->getValue();\n                        }\n                        return null;\n                    },\n                ]);\n            })\n            ->addArgument(BooleanCoercer::class);\n\n        $this->container\n            ->share(GraphQL::FLOAT, function (FloatCoercer $coercer) {\n                return newScalarType([\n                    'name'         => TypeNameEnum::FLOAT,\n                    'description'  =>\n                        'The `Float` scalar type represents signed double-precision fractional ' .\n                        'values as specified by ' .\n                        '[IEEE 754](https://en.wikipedia.org/wiki/IEEE_754).',\n                    'serialize'    => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseValue'   => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseLiteral' => function (NodeInterface $node) {\n                        if ($node instanceof FloatValueNode || $node instanceof IntValueNode) {\n                            return $node->getValue();\n                        }\n                        return null;\n                    },\n                ]);\n            })\n            ->addArgument(FloatCoercer::class);\n\n        $this->container\n            ->share(GraphQL::INT, function (IntCoercer $coercer) {\n                return newScalarType([\n                    'name'         => TypeNameEnum::INT,\n                    'description'  =>\n                        'The `Int` scalar type represents non-fractional signed whole numeric ' .\n                        'values. Int can represent values between -(2^31) and 2^31 - 1.',\n                    'serialize'    => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseValue'   => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseLiteral' => function (NodeInterface $node) {\n                        if ($node instanceof IntValueNode) {\n                            $value = (int)$node->getValue();\n                            if ((string)$node->getValue() === (string)$value &&\n                                $value <= PHP_INT_MAX && $value >= PHP_INT_MIN) {\n                                return $value;\n                            }\n                        }\n                        return null;\n                    },\n                ]);\n            })\n            ->addArgument(IntCoercer::class);\n\n        $this->container\n            ->share(GraphQL::ID, function (StringCoercer $coercer) {\n                return newScalarType([\n                    'name'         => TypeNameEnum::ID,\n                    'description'  =>\n                        'The `ID` scalar type represents a unique identifier, often used to ' .\n                        'refetch an object or as key for a cache. The ID type appears in a JSON ' .\n                        'response as a String; however, it is not intended to be human-readable. ' .\n                        'When expected as an input type, any string (such as `\"4\"`) or integer ' .\n                        '(such as `4`) input value will be accepted as an ID.',\n                    'serialize'    => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseValue'   => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseLiteral' => function (NodeInterface $node) {\n                        if ($node instanceof StringValueNode || $node instanceof IntValueNode) {\n                            return $node->getValue();\n                        }\n                        return null;\n                    },\n                ]);\n            })\n            ->addArgument(StringCoercer::class);\n\n        $this->container\n            ->share(GraphQL::STRING, function (StringCoercer $coercer) {\n                return newScalarType([\n                    'name'         => TypeNameEnum::STRING,\n                    'description'  =>\n                        'The `String` scalar type represents textual data, represented as UTF-8 ' .\n                        'character sequences. The String type is most often used by GraphQL to ' .\n                        'represent free-form human-readable text.',\n                    'serialize'    => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseValue'   => function ($value) use ($coercer) {\n                        return $coercer->coerce($value);\n                    },\n                    'parseLiteral' => function (NodeInterface $node) {\n                        if ($node instanceof StringValueNode) {\n                            return $node->getValue();\n                        }\n                        return null;\n                    },\n                ]);\n            })\n            ->addArgument(StringCoercer::class);\n    }\n}\n"
  },
  {
    "path": "src/Type/TypeKindEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nclass TypeKindEnum\n{\n\n    public const SCALAR       = 'SCALAR';\n    public const OBJECT       = 'OBJECT';\n    public const INTERFACE    = 'INTERFACE';\n    public const UNION        = 'UNION';\n    public const ENUM         = 'ENUM';\n    public const INPUT_OBJECT = 'INPUT_OBJECT';\n    public const LIST         = 'LIST';\n    public const NON_NULL     = 'NON_NULL';\n\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return array_values((new \\ReflectionClass(__CLASS__))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Type/definition.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\EnumValue;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\InputField;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InputTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\OutputTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse Digia\\GraphQL\\Type\\Definition\\WrappingTypeInterface;\nuse function Digia\\GraphQL\\Util\\invariant;\nuse function Digia\\GraphQL\\Util\\toString;\n\n/**\n * @param mixed $maybeThunk\n * @return mixed\n */\nfunction resolveThunk($maybeThunk)\n{\n    return \\is_callable($maybeThunk) ? $maybeThunk() : $maybeThunk;\n}\n\n/**\n * @param mixed $value\n * @return bool\n */\nfunction isAssocArray($value): bool\n{\n    if (!\\is_array($value)) {\n        return false;\n    }\n    if (empty($value)) {\n        return true;\n    }\n    $keys = \\array_keys($value);\n    return $keys !== \\array_keys($keys);\n}\n\n/**\n * @param mixed $type\n * @throws InvariantException\n */\nfunction assertType($type)\n{\n    invariant(\n        $type instanceof TypeInterface,\n        \\sprintf('Expected %s to be a GraphQL type.', toString($type))\n    );\n}\n\n/**\n * Whether a type is an input type cannot be determined with `instanceof`\n * because lists and non-nulls can also be output types if the wrapped type is an output type.\n *\n * @param TypeInterface|null $type\n * @return bool\n */\nfunction isInputType(?TypeInterface $type): bool\n{\n    return null !== $type &&\n        ($type instanceof InputTypeInterface ||\n            ($type instanceof WrappingTypeInterface && isInputType($type->getOfType())));\n}\n\n/**\n * Whether a type is an output type cannot be determined with `instanceof`\n * because lists and non-nulls can also be output types if the wrapped type is an output type.\n *\n * @param TypeInterface|null $type\n * @return bool\n */\nfunction isOutputType(?TypeInterface $type): bool\n{\n    return null !== $type &&\n        ($type instanceof OutputTypeInterface ||\n            ($type instanceof WrappingTypeInterface && isOutputType($type->getOfType())));\n}\n\n/**\n * @param TypeInterface|null $type\n * @return TypeInterface|null\n */\nfunction getNullableType(?TypeInterface $type): ?TypeInterface\n{\n    if (null === $type) {\n        return null;\n    }\n\n    return $type instanceof NonNullType ? $type->getOfType() : $type;\n}\n\n/**\n * @param TypeInterface|null $type\n * @return TypeInterface|null\n */\nfunction getNamedType(?TypeInterface $type): ?TypeInterface\n{\n    if (!$type) {\n        return null;\n    }\n\n    $unwrappedType = $type;\n\n    while ($unwrappedType instanceof WrappingTypeInterface) {\n        $unwrappedType = $unwrappedType->getOfType();\n    }\n\n    return $unwrappedType;\n}\n\n/**\n * Returns a new Scalar type after ensuring that its state is valid.\n *\n * @param array $config\n * @return ScalarType\n * @throws InvariantException\n */\nfunction newScalarType(array $config = []): ScalarType\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    invariant(\n        isset($config['serialize']) && \\is_callable($config['serialize']),\n        \\sprintf(\n            '%s must provide \"serialize\" function. If this custom Scalar ' .\n            'is also used as an input type, ensure \"parseValue\" and \"parseLiteral\" ' .\n            'functions are also provided.',\n            $config['name']\n        )\n    );\n\n    if (isset($config['parseValue']) || isset($config['parseLiteral'])) {\n        invariant(\n            (isset($config['parseValue']) && \\is_callable($config['parseValue'])) &&\n            (isset($config['parseLiteral']) && \\is_callable($config['parseLiteral'])),\n            \\sprintf('%s must provide both \"parseValue\" and \"parseLiteral\" functions.', $config['name'])\n        );\n    }\n\n    return new ScalarType(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['serialize'],\n        $config['parseValue'] ?? null,\n        $config['parseLiteral'] ?? null,\n        $config['astNode'] ?? null\n    );\n}\n\n/**\n * Returns a new Enum type after ensuring that its state is valid.\n *\n * @param array $config\n * @return EnumType\n * @throws InvariantException\n */\nfunction newEnumType(array $config = []): EnumType\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    return new EnumType(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['values'] ?? [],\n        $config['astNode'] ?? null\n    );\n}\n\n/**\n * Returns a new Enum value after ensuring that its state is valid.\n *\n * @param array $config\n * @return EnumValue\n * @throws InvariantException\n */\nfunction newEnumValue(array $config = []): EnumValue\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    return new EnumValue(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['deprecationReason'] ?? null,\n        $config['astNode'] ?? null,\n        $config['value'] ?? null\n    );\n}\n\n/**\n * Returns a new Input Object type after ensuring that its state is valid.\n *\n * @param array $config\n * @return InputObjectType\n * @throws InvariantException\n */\nfunction newInputObjectType(array $config = []): InputObjectType\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    return new InputObjectType(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['fields'] ?? [],\n        $config['astNode'] ?? null\n    );\n}\n\n/**\n * Returns a new Input field after ensuring that its state is valid.\n *\n * @param array $config\n * @return InputField\n * @throws InvariantException\n */\nfunction newInputField(array $config = []): InputField\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    return new InputField(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['type'] ?? null,\n        $config['defaultValue'] ?? null,\n        $config['astNode'] ?? null\n    );\n}\n\n/**\n * Returns a new Interface type after ensuring that its state is valid.\n *\n * @param array $config\n * @return InterfaceType\n * @throws InvariantException\n */\nfunction newInterfaceType(array $config = []): InterfaceType\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    invariant(\n        !isset($config['resolveType']) || null === $config['resolveType'] || \\is_callable($config['resolveType']),\n        \\sprintf('%s must provide \"resolveType\" as a function.', $config['name'])\n    );\n\n    return new InterfaceType(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['fields'] ?? [],\n        $config['resolveType'] ?? null,\n        $config['astNode'] ?? null,\n        $config['extensionASTNodes'] ?? []\n    );\n}\n\n/**\n * Returns a new Object type after ensuring that its state is valid.\n *\n * @param array $config\n * @return ObjectType\n * @throws InvariantException\n */\nfunction newObjectType(array $config = []): ObjectType\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    if (isset($config['isTypeOf'])) {\n        invariant(\n            \\is_callable($config['isTypeOf']),\n            \\sprintf('%s must provide \"isTypeOf\" as a function.', $config['name'])\n        );\n    }\n\n    return new ObjectType(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['fields'] ?? [],\n        $config['interfaces'] ?? [],\n        $config['isTypeOf'] ?? null,\n        $config['astNode'] ?? null,\n        $config['extensionASTNodes'] ?? []\n    );\n}\n\n/**\n * Returns a new Field after ensuring that its state is valid.\n *\n * @param array $config\n * @return Field\n * @throws InvariantException\n */\nfunction newField(array $config = []): Field\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    return new Field(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['type'] ?? null,\n        $config['args'] ?? [],\n        $config['resolve'] ?? null,\n        $config['subscribe'] ?? null,\n        $config['deprecationReason'] ?? null,\n        $config['astNode'] ?? null,\n        $config['typeName'] ?? ''\n    );\n}\n\n/**\n * Returns a new Argument after ensuring that its state is valid.\n *\n * @param array $config\n * @return Argument\n * @throws InvariantException\n */\nfunction newArgument(array $config = []): Argument\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    return new Argument(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['type'] ?? null,\n        $config['defaultValue'] ?? null,\n        $config['astNode'] ?? null\n    );\n}\n\n/**\n * Returns a new Union type after ensuring that its state is valid.\n *\n * @param array $config\n * @return UnionType\n * @throws InvariantException\n */\nfunction newUnionType(array $config = []): UnionType\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    if (isset($config['resolveType'])) {\n        invariant(\n            \\is_callable($config['resolveType']),\n            \\sprintf('%s must provide \"resolveType\" as a function.', $config['name'])\n        );\n    }\n\n    return new UnionType(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['types'] ?? [],\n        $config['resolveType'] ?? null,\n        $config['astNode'] ?? null\n    );\n}\n\n/**\n * Returns a new Schema after ensuring that its state is valid.\n *\n * @param array $config\n * @return Schema\n * @throws InvariantException\n */\nfunction newSchema(array $config = []): Schema\n{\n    if (!isset($config['assumeValid']) || !$config['assumeValid']) {\n        if (isset($config['types'])) {\n            invariant(\n                \\is_array($config['types']),\n                \\sprintf('\"types\" must be Array if provided but got: %s.', toString($config['types']))\n            );\n        }\n\n        if (isset($config['directives'])) {\n            invariant(\n                \\is_array($config['directives']),\n                \\sprintf('\"directives\" must be Array if provided but got: %s.', toString($config['directives']))\n            );\n        }\n    }\n\n    return new Schema(\n        $config['query'] ?? null,\n        $config['mutation'] ?? null,\n        $config['subscription'] ?? null,\n        $config['types'] ?? [],\n        $config['directives'] ?? [],\n        $config['assumeValid'] ?? false,\n        $config['astNode'] ?? null,\n        $config['extensionASTNodes'] ?? []\n    );\n}\n\n/**\n * Returns a new Directive after ensuring that its state is valid.\n *\n * @param array $config\n * @return Directive\n * @throws InvariantException\n */\nfunction newDirective(array $config = []): Directive\n{\n    invariant(isset($config['name']), 'Must provide name.');\n\n    invariant(\n        isset($config['locations']) && \\is_array($config['locations']),\n        'Must provide locations for directive.'\n    );\n\n    return new Directive(\n        $config['name'],\n        $config['description'] ?? null,\n        $config['locations'],\n        $config['args'] ?? [],\n        $config['astNode'] ?? null,\n        $config['typeName'] ?? ''\n    );\n}\n\n/**\n * Returns a new List type after ensuring that its state is valid.\n *\n * @param mixed $ofType\n * @return ListType\n * @throws InvariantException\n */\nfunction newList($ofType): ListType\n{\n    assertType($ofType);\n\n    return new ListType($ofType);\n}\n\n/**\n * Returns a new Non-null type after ensuring that its state is valid.\n *\n * @param mixed $ofType\n * @return NonNullType\n * @throws InvariantException\n */\nfunction newNonNull($ofType): NonNullType\n{\n    if ($ofType instanceof NonNullType) {\n        throw new InvariantException(\\sprintf('Expected %s to be a GraphQL nullable type.', toString($ofType)));\n    }\n\n    return new NonNullType($ofType);\n}\n"
  },
  {
    "path": "src/Type/directives.php",
    "content": "<?php\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse function Digia\\GraphQL\\Util\\arraySome;\n\n/**\n * @return Directive\n */\nfunction IncludeDirective(): Directive\n{\n    return GraphQL::make(GraphQL::INCLUDE_DIRECTIVE);\n}\n\n/**\n * @return Directive\n */\nfunction SkipDirective(): Directive\n{\n    return GraphQL::make(GraphQL::SKIP_DIRECTIVE);\n}\n\nconst DEFAULT_DEPRECATION_REASON = 'No longer supported';\n\n/**\n * @return Directive\n */\nfunction DeprecatedDirective(): Directive\n{\n    return GraphQL::make(GraphQL::DEPRECATED_DIRECTIVE);\n}\n\n/**\n * @return array\n */\nfunction specifiedDirectives(): array\n{\n    return [\n        IncludeDirective(),\n        SkipDirective(),\n        DeprecatedDirective(),\n    ];\n}\n\n/**\n * @param Directive $directive\n * @return bool\n */\nfunction isSpecifiedDirective(Directive $directive): bool\n{\n    return arraySome(\n        specifiedDirectives(),\n        function (Directive $specifiedDirective) use ($directive) {\n            return $specifiedDirective->getName() === $directive->getName();\n        }\n    );\n}\n"
  },
  {
    "path": "src/Type/introspection.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse function Digia\\GraphQL\\Util\\arraySome;\n\n/**\n * @return ObjectType\n */\nfunction __Schema(): ObjectType\n{\n    return GraphQL::make(GraphQL::SCHEMA_INTROSPECTION);\n}\n\n/**\n * @return ObjectType\n */\nfunction __Directive(): ObjectType\n{\n    return GraphQL::make(GraphQL::DIRECTIVE_INTROSPECTION);\n\n}\n\n/**\n * @return EnumType\n */\nfunction __DirectiveLocation(): EnumType\n{\n    return GraphQL::make(GraphQL::DIRECTIVE_LOCATION_INTROSPECTION);\n\n}\n\n/**\n * @return ObjectType\n */\nfunction __Type(): ObjectType\n{\n    return GraphQL::make(GraphQL::TYPE_INTROSPECTION);\n}\n\n/**\n * @return ObjectType\n */\nfunction __Field(): ObjectType\n{\n    return GraphQL::make(GraphQL::FIELD_INTROSPECTION);\n}\n\n/**\n * @return ObjectType\n */\nfunction __InputValue(): ObjectType\n{\n    return GraphQL::make(GraphQL::INPUT_VALUE_INTROSPECTION);\n}\n\n/**\n * @return ObjectType\n */\nfunction __EnumValue(): ObjectType\n{\n    return GraphQL::make(GraphQL::ENUM_VALUE_INTROSPECTION);\n}\n\n/**\n * @return EnumType\n */\nfunction __TypeKind(): EnumType\n{\n    return GraphQL::make(GraphQL::TYPE_KIND_INTROSPECTION);\n}\n\n/**\n * @return Field\n */\nfunction SchemaMetaFieldDefinition(): Field\n{\n    return GraphQL::make(GraphQL::SCHEMA_META_FIELD_DEFINITION);\n}\n\n/**\n * @return Field\n */\nfunction TypeMetaFieldDefinition(): Field\n{\n    return GraphQL::make(GraphQL::TYPE_META_FIELD_DEFINITION);\n}\n\n/**\n * @return Field\n */\nfunction TypeNameMetaFieldDefinition(): Field\n{\n    return GraphQL::make(GraphQL::TYPE_NAME_META_FIELD_DEFINITION);\n}\n\n/**\n * @return array\n */\nfunction introspectionTypes(): array\n{\n    return [\n        __Schema(),\n        __Directive(),\n        __DirectiveLocation(),\n        __Type(),\n        __Field(),\n        __InputValue(),\n        __EnumValue(),\n        __TypeKind(),\n    ];\n}\n\n/**\n * @param NamedTypeInterface $type\n * @return bool\n */\nfunction isIntrospectionType(NamedTypeInterface $type): bool\n{\n    return arraySome(\n        introspectionTypes(),\n        function (NamedTypeInterface $introspectionType) use ($type) {\n            /** @noinspection PhpUndefinedMethodInspection */\n            return $type->getName() === $introspectionType->getName();\n        }\n    );\n}\n"
  },
  {
    "path": "src/Type/scalars.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Type;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse function Digia\\GraphQL\\Util\\arraySome;\n\n/**\n * @return ScalarType\n */\nfunction booleanType(): ScalarType\n{\n    return GraphQL::make(GraphQL::BOOLEAN);\n}\n\n/**\n * @return ScalarType\n */\nfunction floatType(): ScalarType\n{\n    return GraphQL::make(GraphQL::FLOAT);\n}\n\n/**\n * @return ScalarType\n */\nfunction intType(): ScalarType\n{\n    return GraphQL::make(GraphQL::INT);\n}\n\n/**\n * @return ScalarType\n */\nfunction idType(): ScalarType\n{\n    return GraphQL::make(GraphQL::ID);\n}\n\n/**\n * @return ScalarType\n */\nfunction stringType(): ScalarType\n{\n    return GraphQL::make(GraphQL::STRING);\n}\n\n/**\n * @return array\n */\nfunction specifiedScalarTypes(): array\n{\n    return [\n        stringType(),\n        intType(),\n        floatType(),\n        booleanType(),\n        idType(),\n    ];\n}\n\n/**\n * @param NamedTypeInterface $type\n * @return bool\n */\nfunction isSpecifiedScalarType(NamedTypeInterface $type): bool\n{\n    return arraySome(\n        specifiedScalarTypes(),\n        function (ScalarType $specifiedScalarType) use ($type) {\n            return $type->getName() === $specifiedScalarType->getName();\n        }\n    );\n}\n"
  },
  {
    "path": "src/Util/AbstractEnum.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nabstract class AbstractEnum\n{\n    /**\n     * @return array\n     * @throws \\ReflectionException\n     */\n    public static function values(): array\n    {\n        return \\array_values((new \\ReflectionClass(static::class))->getConstants());\n    }\n}\n"
  },
  {
    "path": "src/Util/ArrayToJsonTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\ntrait ArrayToJsonTrait\n{\n    /**\n     * @return array\n     */\n    abstract public function toArray(): array;\n\n    /**\n     * @return string\n     */\n    public function toJSON(): string\n    {\n        return \\json_encode($this->toArray(), JSON_UNESCAPED_UNICODE);\n    }\n}\n"
  },
  {
    "path": "src/Util/ConversionException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Error\\AbstractException;\n\nclass ConversionException extends AbstractException\n{\n}\n"
  },
  {
    "path": "src/Util/NameHelper.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass NameHelper\n{\n\n    /**\n     * Returns an Error if a name is invalid.\n     *\n     * @param string     $name\n     * @param mixed|null $node\n     * @return ValidationException\n     */\n    public static function isValidError(string $name, $node = null): ?ValidationException\n    {\n        if (\\strlen($name) > 1 && $name[0] === '_' && $name[1] === '_') {\n            return new ValidationException(\n                sprintf('Name \"%s\" must not begin with \"__\", which is reserved by GraphQL introspection.', $name),\n                $node instanceof NodeInterface ? [$node] : null\n            );\n        }\n\n        if (preg_match(\"/^[_a-zA-Z][_a-zA-Z0-9]*$/\", $name) === 0) {\n            return new ValidationException(\n                sprintf('Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"%s\" does not.', $name),\n                $node instanceof NodeInterface ? [$node] : null\n            );\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/Util/NodeComparator.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass NodeComparator\n{\n    /**\n     * @param NodeInterface $node\n     * @param NodeInterface $other\n     * @return bool\n     */\n    public static function compare(NodeInterface $node, NodeInterface $other): bool\n    {\n        return $node->toJSON() === $other->toJSON();\n    }\n}\n"
  },
  {
    "path": "src/Util/SerializationInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\ninterface SerializationInterface\n{\n\n    /**\n     * @return array\n     */\n    public function toArray(): array;\n\n    /**\n     * @return string\n     */\n    public function toJSON(): string;\n}\n"
  },
  {
    "path": "src/Util/TypeASTConverter.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NonNullTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\n\nclass TypeASTConverter\n{\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     * @param Schema            $schema\n     * @param TypeNodeInterface $typeNode\n     * @return TypeInterface|null\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    public static function convert(Schema $schema, TypeNodeInterface $typeNode): ?TypeInterface\n    {\n        $innerType = null;\n\n        if ($typeNode instanceof ListTypeNode) {\n            $innerType = self::convert($schema, $typeNode->getType());\n            return null !== $innerType ? newList($innerType) : null;\n        }\n\n        if ($typeNode instanceof NonNullTypeNode) {\n            $innerType = self::convert($schema, $typeNode->getType());\n            return null !== $innerType ? newNonNull($innerType) : null;\n        }\n\n        if ($typeNode instanceof NamedTypeNode) {\n            return $schema->getType($typeNode->getNameValue());\n        }\n\n        throw new ConversionException(sprintf('Unexpected type kind: %s', $typeNode->getKind()));\n    }\n}\n"
  },
  {
    "path": "src/Util/TypeHelper.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\AbstractTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\LeafTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\nclass TypeHelper\n{\n    /**\n     * Provided two types, return true if the types are equal (invariant).\n     *\n     * @param TypeInterface $typeA\n     * @param TypeInterface $typeB\n     * @return bool\n     */\n    public static function isEqualType(TypeInterface $typeA, TypeInterface $typeB): bool\n    {\n        // Equivalent types are equal.\n        if ($typeA === $typeB) {\n            return true;\n        }\n\n        // If either type is non-null, the other must also be non-null.\n        if ($typeA instanceof NonNullType && $typeB instanceof NonNullType) {\n            return self::isEqualType($typeA->getOfType(), $typeB->getOfType());\n        }\n\n        // If either type is a list, the other must also be a list.\n        if ($typeA instanceof ListType && $typeB instanceof ListType) {\n            return self::isEqualType($typeA->getOfType(), $typeB->getOfType());\n        }\n\n        // Otherwise the types are not equal.\n        return false;\n    }\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     * @param Schema        $schema\n     * @param TypeInterface $maybeSubtype\n     * @param TypeInterface $superType\n     * @return bool\n     *\n     * @throws InvariantException\n     */\n    public static function isTypeSubtypeOf(\n        Schema $schema,\n        TypeInterface $maybeSubtype,\n        TypeInterface $superType\n    ): bool {\n        // Equivalent type is a valid subtype.\n        if ($maybeSubtype === $superType) {\n            return true;\n        }\n\n        // If superType is non-null, maybeSubType must also be non-null.\n        if ($superType instanceof NonNullType) {\n            if ($maybeSubtype instanceof NonNullType) {\n                return self::isTypeSubtypeOf($schema, $maybeSubtype->getOfType(), $superType->getOfType());\n            }\n            return false;\n        }\n\n        if ($maybeSubtype instanceof NonNullType) {\n            // If superType is nullable, maybeSubType may be non-null or nullable.\n            return self::isTypeSubtypeOf($schema, $maybeSubtype->getOfType(), $superType);\n        }\n\n        // If superType type is a list, maybeSubType type must also be a list.\n        if ($superType instanceof ListType) {\n            if ($maybeSubtype instanceof ListType) {\n                return self::isTypeSubtypeOf($schema, $maybeSubtype->getOfType(), $superType->getOfType());\n            }\n            return false;\n        }\n\n        if ($maybeSubtype instanceof ListType) {\n            // If superType is not a list, maybeSubType must also be not a list.\n            return false;\n        }\n\n        // If superType type is an abstract type, maybeSubType type may be a currently\n        // possible object type.\n        if ($superType instanceof AbstractTypeInterface &&\n            $maybeSubtype instanceof ObjectType &&\n            $schema->isPossibleType($superType, $maybeSubtype)) {\n            return true;\n        }\n\n        // Otherwise, the child type is not a valid subtype of the parent type.\n        return false;\n    }\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     * @param Schema        $schema\n     * @param TypeInterface $typeA\n     * @param TypeInterface $typeB\n     * @return bool\n     *\n     * @throws InvariantException\n     */\n    public static function doTypesOverlap(Schema $schema, TypeInterface $typeA, TypeInterface $typeB): bool\n    {\n        // Equivalent types overlap\n        if ($typeA === $typeB) {\n            return true;\n        }\n\n        if ($typeA instanceof AbstractTypeInterface) {\n            if ($typeB instanceof AbstractTypeInterface) {\n                // If both types are abstract, then determine if there is any intersection\n                // between possible concrete types of each.\n                return arraySome($schema->getPossibleTypes($typeA),\n                    function (NamedTypeInterface $type) use ($schema, $typeB) {\n                        return $schema->isPossibleType($typeB, $type);\n                    });\n            }\n\n            // Determine if the latter type is a possible concrete type of the former.\n            /** @noinspection PhpParamsInspection */\n            return $schema->isPossibleType($typeA, $typeB);\n        }\n\n        if ($typeB instanceof AbstractTypeInterface) {\n            // Determine if the former type is a possible concrete type of the latter.\n            /** @noinspection PhpParamsInspection */\n            return $schema->isPossibleType($typeB, $typeA);\n        }\n\n        // Otherwise the types do not overlap.\n        return false;\n    }\n\n    /**\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     * @param TypeInterface $typeA\n     * @param TypeInterface $typeB\n     * @return bool\n     */\n    public static function compareTypes(TypeInterface $typeA, TypeInterface $typeB): bool\n    {\n        if ($typeA instanceof ListType) {\n            return $typeB instanceof ListType\n                ? self::compareTypes($typeA->getOfType(), $typeB->getOfType())\n                : true;\n        }\n        if ($typeB instanceof ListType) {\n            return true;\n        }\n        if ($typeA instanceof NonNullType) {\n            return $typeB instanceof NonNullType\n                ? self::compareTypes($typeA->getOfType(), $typeB->getOfType())\n                : true;\n        }\n        if ($typeB instanceof NonNullType) {\n            return true;\n        }\n        if ($typeA instanceof LeafTypeInterface || $typeB instanceof LeafTypeInterface) {\n            return $typeA !== $typeB;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Util/TypeInfo.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\CompositeTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\EnumValue;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\InputTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\OutputTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\Type\\SchemaMetaFieldDefinition;\nuse function Digia\\GraphQL\\Type\\TypeMetaFieldDefinition;\nuse function Digia\\GraphQL\\Type\\TypeNameMetaFieldDefinition;\n\nclass TypeInfo\n{\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @var TypeInterface[]\n     */\n    protected $typeStack = [];\n\n    /**\n     * @var CompositeTypeInterface[]\n     */\n    protected $parentTypeStack = [];\n\n    /**\n     * @var TypeInterface[]\n     */\n    protected $inputTypeStack = [];\n\n    /**\n     * @var Field[]\n     */\n    protected $fieldDefinitionStack = [];\n\n    /**\n     * @var array\n     */\n    protected $defaultValueStack = [];\n\n    /**\n     * @var Directive\n     */\n    protected $directive;\n\n    /**\n     * @var Argument\n     */\n    protected $argument;\n\n    /**\n     * @var EnumValue\n     */\n    protected $enumValue;\n\n    /**\n     * @var callable|null\n     */\n    protected $getFieldDefinitionFunction;\n\n    /**\n     * TypeInfo constructor.\n     * @param Schema             $schema\n     * @param callable|null      $getFieldDefinitionFunction\n     * @param TypeInterface|null $initialType\n     */\n    public function __construct(\n        Schema $schema,\n        ?callable $getFieldDefinitionFunction = null,\n        ?TypeInterface $initialType = null\n    ) {\n        $this->schema                     = $schema;\n        $this->getFieldDefinitionFunction = $getFieldDefinitionFunction ?? function (\n                Schema $schema,\n                TypeInterface $parentType,\n                FieldNode $fieldNode\n            ) {\n                return getFieldDefinition($schema, $parentType, $fieldNode);\n            };\n\n        if ($initialType instanceof InputTypeInterface) {\n            $this->inputTypeStack[] = $initialType;\n        } elseif ($initialType instanceof CompositeTypeInterface) {\n            $this->parentTypeStack[] = $initialType;\n        } elseif ($initialType instanceof OutputTypeInterface) {\n            $this->typeStack[] = $initialType;\n        }\n    }\n\n    /**\n     * @param Schema        $schema\n     * @param TypeInterface $parentType\n     * @param FieldNode     $fieldNode\n     * @return Field|null\n     */\n    public function resolveFieldDefinition(\n        Schema $schema,\n        TypeInterface $parentType,\n        FieldNode $fieldNode\n    ): ?Field {\n        return \\call_user_func($this->getFieldDefinitionFunction, $schema, $parentType, $fieldNode);\n    }\n\n    /**\n     * @param TypeInterface|null $type\n     */\n    public function pushType(?TypeInterface $type): void\n    {\n        $this->typeStack[] = $type;\n    }\n\n    /**\n     *\n     */\n    public function popType(): void\n    {\n        \\array_pop($this->typeStack);\n    }\n\n    /**\n     * @return TypeInterface|TypeInterface|null\n     */\n    public function getType(): ?TypeInterface\n    {\n        return $this->getFromStack($this->typeStack, 1);\n    }\n\n    /**\n     * @param CompositeTypeInterface|null $type\n     */\n    public function pushParentType(?CompositeTypeInterface $type): void\n    {\n        $this->parentTypeStack[] = $type;\n    }\n\n    /**\n     *\n     */\n    public function popParentType(): void\n    {\n        \\array_pop($this->parentTypeStack);\n    }\n\n    /**\n     * @return CompositeTypeInterface|null\n     */\n    public function getParentType(): ?CompositeTypeInterface\n    {\n        return $this->getFromStack($this->parentTypeStack, 1);\n    }\n\n    /**\n     * @param TypeInterface|null $type\n     */\n    public function pushInputType(?TypeInterface $type): void\n    {\n        $this->inputTypeStack[] = $type;\n    }\n\n    /**\n     * \n     */\n    public function popInputType(): void\n    {\n        \\array_pop($this->inputTypeStack);\n    }\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getInputType(): ?TypeInterface\n    {\n        return $this->getFromStack($this->inputTypeStack, 1);\n    }\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getParentInputType(): ?TypeInterface\n    {\n        return $this->getFromStack($this->inputTypeStack, 2);\n    }\n\n    /**\n     * @param Field|null $fieldDefinition\n     */\n    public function pushFieldDefinition(?Field $fieldDefinition): void\n    {\n        $this->fieldDefinitionStack[] = $fieldDefinition;\n    }\n\n    /**\n     * \n     */\n    public function popFieldDefinition(): void\n    {\n        \\array_pop($this->fieldDefinitionStack);\n    }\n\n    /**\n     * @return Field|null\n     */\n    public function getFieldDefinition(): ?Field\n    {\n        return $this->getFromStack($this->fieldDefinitionStack, 1);\n    }\n\n    /**\n     * @return Schema\n     */\n    public function getSchema(): Schema\n    {\n        return $this->schema;\n    }\n\n    /**\n     * @param mixed|null $defaultValue\n     */\n    public function pushDefaultValue($defaultValue): void\n    {\n        $this->defaultValueStack[] = $defaultValue;\n    }\n\n    /**\n     *\n     */\n    public function popDefaultValue(): void\n    {\n        \\array_pop($this->defaultValueStack);\n    }\n\n    /**\n     * @return mixed|null\n     */\n    public function getDefaultValue()\n    {\n        return $this->getFromStack($this->defaultValueStack, 1);\n    }\n\n    /**\n     * @return Directive|null\n     */\n    public function getDirective(): ?Directive\n    {\n        return $this->directive;\n    }\n\n    /**\n     * @param Directive|null $directive\n     */\n    public function setDirective(?Directive $directive): void\n    {\n        $this->directive = $directive;\n    }\n\n    /**\n     * @return Argument|null\n     */\n    public function getArgument(): ?Argument\n    {\n        return $this->argument;\n    }\n\n    /**\n     * @param Argument|null $argument\n     */\n    public function setArgument(?Argument $argument): void\n    {\n        $this->argument = $argument;\n    }\n\n    /**\n     * @return EnumValue|null\n     */\n    public function getEnumValue(): ?EnumValue\n    {\n        return $this->enumValue;\n    }\n\n    /**\n     * @param EnumValue|null $enumValue\n     */\n    public function setEnumValue(?EnumValue $enumValue): void\n    {\n        $this->enumValue = $enumValue;\n    }\n\n    /**\n     * @param array $stack\n     * @param int   $depth\n     * @return mixed|null\n     */\n    protected function getFromStack(array $stack, int $depth)\n    {\n        $count = \\count($stack);\n\n        return $count >= $depth ? $stack[$count - $depth] : null;\n    }\n}\n\n/**\n * @param Schema        $schema\n * @param TypeInterface $parentType\n * @param FieldNode     $fieldNode\n * @return Field|null\n * @throws InvariantException\n */\nfunction getFieldDefinition(Schema $schema, TypeInterface $parentType, FieldNode $fieldNode): ?Field\n{\n    $name = $fieldNode->getNameValue();\n\n    $schemaDefinition = SchemaMetaFieldDefinition();\n    if ($name === $schemaDefinition->getName() && $schema->getQueryType() === $parentType) {\n        return $schemaDefinition;\n    }\n\n    $typeDefinition = TypeMetaFieldDefinition();\n    if ($name === $typeDefinition->getName() && $schema->getQueryType() === $parentType) {\n        return $typeDefinition;\n    }\n\n    $typeNameDefinition = TypeNameMetaFieldDefinition();\n    if ($name === $typeNameDefinition->getName() && $parentType instanceof CompositeTypeInterface) {\n        return $typeNameDefinition;\n    }\n\n    if ($parentType instanceof ObjectType || $parentType instanceof InterfaceType) {\n        $fields = $parentType->getFields();\n        if (isset($fields[$name])) {\n            return $fields[$name];\n        }\n    }\n\n    return null;\n}\n"
  },
  {
    "path": "src/Util/ValueASTConverter.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ValueNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\nclass ValueASTConverter\n{\n    /**\n     * Produces a PHP 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     * Throws a `ConversionException` when the value could not be validly converted 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     * @param NodeInterface $node\n     * @param TypeInterface $type\n     * @param array         $variables\n     * @return mixed|null\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    public static function convert(NodeInterface $node, TypeInterface $type, array $variables = [])\n    {\n        if ($type instanceof NonNullType) {\n            return self::convertNonNullType($node, $type, $variables);\n        }\n\n        if ($node instanceof NullValueNode) {\n            return null;\n        }\n\n        if ($node instanceof VariableNode) {\n            return self::convertVariable($node, $type, $variables);\n        }\n\n        if ($type instanceof ListType) {\n            return self::convertListType($node, $type, $variables);\n        }\n\n        if ($type instanceof InputObjectType) {\n            return self::convertInputObjectType($node, $type, $variables);\n        }\n\n        if ($type instanceof EnumType) {\n            return self::convertEnumType($node, $type);\n        }\n\n        if ($type instanceof ScalarType) {\n            return self::convertScalarType($node, $type, $variables);\n        }\n\n        throw new InvalidTypeException(\\sprintf('Unknown type: %s', (string)$type));\n    }\n\n    /**\n     * @param NodeInterface|ValueNodeInterface $node\n     * @param NonNullType                      $type\n     * @param array                            $variables\n     * @return mixed|null\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected static function convertNonNullType(NodeInterface $node, NonNullType $type, array $variables)\n    {\n        if ($node instanceof NullValueNode) {\n            throw new ConversionException('Cannot convert non-null values from null value node.');\n        }\n\n        return self::convert($node, $type->getOfType(), $variables);\n    }\n\n    /**\n     * @param VariableNode  $node\n     * @param TypeInterface $type\n     * @param array         $variables\n     * @return mixed\n     * @throws ConversionException\n     */\n    protected static function convertVariable(VariableNode $node, TypeInterface $type, array $variables)\n    {\n        $variableName = $node->getNameValue();\n\n        if (!isset($variables[$variableName])) {\n            throw new ConversionException(\n                \\sprintf('Cannot convert value for missing variable \"%s\".', $variableName)\n            );\n        }\n\n        // Note: we're not doing any checking that this variable is correct. We're\n        // assuming that this query has been validated and the variable usage here\n        // is of the correct type.\n        $variableValue = $variables[$variableName];\n\n        if (null === $variableValue && $type instanceof NonNullType) {\n            throw new ConversionException(\n                \\sprintf('Cannot convert invalid value \"%s\" for variable \"%s\".', $variableValue, $variableName)\n            );\n        }\n\n        return $variableValue;\n    }\n\n    /**\n     * @param NodeInterface|ValueNodeInterface $node\n     * @param ListType                         $type\n     * @param array                            $variables\n     * @return array|null\n     * @throws ConversionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected static function convertListType(NodeInterface $node, ListType $type, array $variables): ?array\n    {\n        $itemType = $type->getOfType();\n\n        if ($node instanceof ListValueNode) {\n            $values = [];\n\n            foreach ($node->getValues() as $value) {\n                if (self::isMissingVariable($value, $variables)) {\n                    if ($itemType instanceof NonNullType) {\n                        // If an array contains a missing variable, it is either converted to\n                        // null or if the item type is non-null, it considered invalid.\n                        throw new ConversionException('Cannot convert value for missing non-null list item.');\n                    }\n\n                    $values[] = null;\n                } else {\n                    $values[] = self::convert($value, $itemType, $variables);\n                }\n            }\n\n            return $values;\n        }\n\n        return [self::convert($node, $itemType, $variables)];\n    }\n\n    /**\n     * @param NodeInterface|ValueNodeInterface $node\n     * @param InputObjectType                  $type\n     * @param array                            $variables\n     * @return array|null\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected static function convertInputObjectType(\n        NodeInterface $node,\n        InputObjectType $type,\n        array $variables\n    ): ?array {\n        if (!$node instanceof ObjectValueNode) {\n            throw new ConversionException('Input object values can only be converted form object value nodes.');\n        }\n\n        $values = [];\n\n        /** @var ObjectFieldNode[] $fieldNodes */\n        $fieldNodes = keyMap($node->getFields(), function (ObjectFieldNode $value) {\n            return $value->getNameValue();\n        });\n\n        foreach ($type->getFields() as $field) {\n            $name      = $field->getName();\n            $fieldNode = $fieldNodes[$name] ?? null;\n\n            if (null === $fieldNode || self::isMissingVariable($fieldNode->getValue(), $variables)) {\n                if (null !== $field->getDefaultValue()) {\n                    $values[$name] = $field->getDefaultValue();\n                } elseif ($field->getType() instanceof NonNullType) {\n                    throw new ConversionException('Cannot convert input object value for missing non-null field.');\n                }\n                continue;\n            }\n\n            $fieldValue = self::convert($fieldNode->getValue(), $field->getType(), $variables);\n\n            $values[$name] = $fieldValue;\n        }\n\n        return $values;\n    }\n\n    /**\n     * @param NodeInterface|ValueNodeInterface $node\n     * @param EnumType                         $type\n     * @return mixed|null\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected static function convertEnumType(NodeInterface $node, EnumType $type)\n    {\n        if (!$node instanceof EnumValueNode) {\n            throw new ConversionException('Enum values can only be converted from enum value nodes.');\n        }\n\n        $name = $node->getValue();\n\n        $enumValue = $type->getValue($name);\n\n        if (null === $enumValue) {\n            throw new ConversionException(\\sprintf('Cannot convert enum value for missing value \"%s\".', $name));\n        }\n\n        return $enumValue->getValue();\n    }\n\n    /**\n     * @param NodeInterface|ValueNodeInterface $node\n     * @param ScalarType                       $type\n     * @param array                            $variables\n     * @return mixed|null\n     * @throws ConversionException\n     */\n    protected static function convertScalarType(NodeInterface $node, ScalarType $type, array $variables)\n    {\n        // Scalars 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        try {\n            $result = $type->parseLiteral($node, $variables);\n        } catch (\\Exception $e) {\n            // This will be handled by the next if-statement.\n        }\n\n        if (!isset($result)) {\n            throw new ConversionException(\\sprintf('Failed to parse literal for scalar type \"%s\".', (string)$type));\n        }\n\n        return $result;\n    }\n\n    /**\n     * @param ValueNodeInterface $node\n     * @param array              $variables\n     * @return bool\n     */\n    protected static function isMissingVariable(ValueNodeInterface $node, array $variables): bool\n    {\n        return $node instanceof VariableNode && !isset($variables[$node->getNameValue()]);\n    }\n}\n"
  },
  {
    "path": "src/Util/ValueConverter.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\SyntaxErrorException;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ValueNodeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputField;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\SerializableTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\Type\\idType;\n\nclass ValueConverter\n{\n    /**\n     * Produces a GraphQL Value AST given a PHP value.\n     *\n     * A GraphQL type must be provided, which will be used to interpret different\n     * PHP 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     * @param mixed         $value\n     * @param TypeInterface $type\n     * @return ValueNodeInterface|null\n     * @throws InvariantException\n     * @throws SyntaxErrorException\n     * @throws ConversionException\n     */\n    public static function convert($value, TypeInterface $type): ?ValueNodeInterface\n    {\n        if ($type instanceof NonNullType) {\n            $node = self::convert($value, $type->getOfType());\n\n            return null !== $node && $node->getKind() === NodeKindEnum::NULL ? null : $node;\n        }\n\n        if (null === $value) {\n            return new NullValueNode(null);\n        }\n\n        // Convert PHP 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        if ($type instanceof ListType) {\n            return self::convertListType($value, $type);\n        }\n\n        // Populate the fields of the input object by creating ASTs from each value\n        // in the PHP object according to the fields in the input type.\n        if ($type instanceof InputObjectType) {\n            return self::convertInputObjectType($value, $type);\n        }\n\n        if ($type instanceof ScalarType || $type instanceof EnumType) {\n            return self::convertScalarOrEnum($value, $type);\n        }\n\n        throw new ConversionException(\\sprintf('Unknown type: %s.', (string)$type));\n    }\n\n    /**\n     * @param mixed    $value\n     * @param ListType $type\n     * @return ValueNodeInterface|null\n     * @throws InvariantException\n     * @throws SyntaxErrorException\n     * @throws ConversionException\n     */\n    protected static function convertListType($value, ListType $type): ?ValueNodeInterface\n    {\n        $itemType = $type->getOfType();\n\n        if (!\\is_iterable($value)) {\n            return self::convert($value, $itemType);\n        }\n\n        $nodes = [];\n\n        foreach ($value as $item) {\n            $itemNode = self::convert($item, $itemType);\n            if (null !== $itemNode) {\n                $nodes[] = $itemNode;\n            }\n        }\n\n        return new ListValueNode($nodes, null);\n    }\n\n    /**\n     * @param mixed           $value\n     * @param InputObjectType $type\n     * @return ObjectValueNode|null\n     * @throws InvariantException\n     * @throws SyntaxErrorException\n     * @throws ConversionException\n     */\n    protected static function convertInputObjectType($value, InputObjectType $type): ?ObjectValueNode\n    {\n        if (null === $value || !\\is_object($value)) {\n            return null;\n        }\n\n        /** @var InputField[] $fields */\n        $fields = \\array_values($type->getFields());\n\n        $nodes = [];\n\n        foreach ($fields as $field) {\n            $fieldName  = $field->getName();\n            $fieldValue = self::convert($value[$fieldName], $field->getType());\n\n            if (null !== $fieldValue) {\n                $nodes[] = new ObjectFieldNode(new NameNode($fieldName, null), $fieldValue, null);\n            }\n        }\n\n        return new ObjectValueNode($nodes, null);\n    }\n\n    /**\n     * @param mixed                     $value\n     * @param SerializableTypeInterface $type\n     * @return ValueNodeInterface|null\n     * @throws ConversionException\n     */\n    protected static function convertScalarOrEnum($value, SerializableTypeInterface $type): ?ValueNodeInterface\n    {\n        // Since value is an internally represented value, it must be serialized\n        // to an externally represented value before converting into an AST.\n        $serialized = $type->serialize($value);\n\n        if (null === $serialized) {\n            return null;\n        }\n\n        // Others serialize based on their corresponding JavaScript scalar types.\n        if (\\is_bool($serialized)) {\n            return new BooleanValueNode($serialized, null);\n        }\n\n        if (\\is_float($serialized)) {\n            return new FloatValueNode($serialized, null);\n        }\n\n        if (\\is_int($serialized)) {\n            return new IntValueNode($serialized, null);\n        }\n\n        if (\\is_string($serialized)) {\n            // Enum types use Enum literals.\n            if ($type instanceof EnumType) {\n                return new EnumValueNode($serialized, null);\n            }\n\n            // ID types can use Int literals.\n            if (idType() === $type && \\is_numeric($serialized)) {\n                return new IntValueNode($serialized, null);\n            }\n\n            return new StringValueNode($serialized, false, null);\n        }\n\n        throw new ConversionException(\\sprintf('Cannot convert value to AST: %s', $serialized));\n    }\n}\n"
  },
  {
    "path": "src/Util/ValueHelper.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse function Digia\\GraphQL\\printNode;\n\nclass ValueHelper\n{\n    /**\n     * @param ArgumentNode[] $argumentsA\n     * @param ArgumentNode[] $argumentsB\n     * @return bool\n     */\n    public static function compareArguments(array $argumentsA, array $argumentsB): bool\n    {\n        if (\\count($argumentsA) !== \\count($argumentsB)) {\n            return false;\n        }\n\n        return arrayEvery($argumentsA, function (ArgumentNode $argumentA) use ($argumentsB) {\n            $argumentB = find($argumentsB, function (ArgumentNode $argument) use ($argumentA) {\n                return $argument->getNameValue() === $argumentA->getNameValue();\n            });\n\n            if (null === $argumentB) {\n                return false;\n            }\n\n            return printNode($argumentA->getValue()) === printNode($argumentB->getValue());\n        });\n    }\n}\n"
  },
  {
    "path": "src/Util/utils.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Util;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse React\\Promise\\PromiseInterface;\nuse function Digia\\GraphQL\\printNode;\n\n/**\n * @param bool   $condition\n * @param string $message\n * @throws InvariantException\n */\nfunction invariant(bool $condition, string $message)\n{\n    if (!$condition) {\n        throw new InvariantException($message);\n    }\n}\n\n/**\n * Given `[A, B, C]` returns `'A, B or C'`.\n *\n * @param array $items\n * @return string\n */\nfunction orList(array $items): string\n{\n    static $MAX_LENGTH = 5;\n\n    $selected = \\array_slice($items, 0, $MAX_LENGTH);\n    $count    = \\count($selected);\n    $index    = 0;\n\n    return $count === 1\n        ? $selected[0]\n        : \\array_reduce($selected, function ($list, $item) use ($count, &$index) {\n            $list .= ($index > 0 && $index < ($count - 1) ? ', ' : '') . ($index === ($count - 1) ? ' or ' : '') .\n                $item;\n            $index++;\n            return $list;\n        }, '');\n}\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 *\n * @param string $input\n * @param array  $options\n * @return array\n */\nfunction suggestionList(string $input, array $options): array\n{\n    $optionsByDistance = [];\n    $oLength           = \\count($options);\n    $inputThreshold    = \\strlen($input) / 2;\n\n    /** @noinspection ForeachInvariantsInspection */\n    for ($i = 0; $i < $oLength; $i++) {\n        // Comparison must be case-insensitive.\n        $distance  = \\levenshtein(\\strtolower($input), \\strtolower($options[$i]));\n        $threshold = \\max($inputThreshold, \\strlen($options[$i]) / 2, 1);\n        if ($distance <= $threshold) {\n            $optionsByDistance[$options[$i]] = $distance;\n        }\n    }\n\n    $result = \\array_keys($optionsByDistance);\n\n    \\usort($result, function ($a, $b) use ($optionsByDistance) {\n        return $optionsByDistance[$a] - $optionsByDistance[$b];\n    });\n\n    return $result;\n}\n\n/**\n * Given `[A, B, C]` returns `'\"A\", \"B\" or \"C\"'`.\n *\n * @param array $items\n * @return string\n */\nfunction quotedOrList(array $items): string\n{\n    return orList(\\array_map(function ($item) {\n        return '\"' . $item . '\"';\n    }, $items));\n}\n\n\n/**\n * @param array    $array\n * @param callable $fn\n * @return bool\n */\nfunction arrayEvery(array $array, callable $fn): bool\n{\n    return \\array_reduce($array, function ($result, $value) use ($fn) {\n        return $result && $fn($value);\n    }, true);\n}\n\n/**\n * @param array    $array\n * @param callable $fn\n * @return mixed\n */\nfunction arraySome(array $array, callable $fn)\n{\n    return \\array_reduce($array, function ($result, $value) use ($fn) {\n        return $result || $fn($value);\n    });\n}\n\n/**\n * @param array    $array\n * @param callable $predicate\n * @return mixed|null\n */\nfunction find(array $array, callable $predicate)\n{\n    foreach ($array as $value) {\n        if ($predicate($value)) {\n            return $value;\n        }\n    }\n\n    return null;\n}\n\n/**\n * @param array    $array\n * @param callable $keyFn\n * @return array\n */\nfunction keyMap(array $array, callable $keyFn): array\n{\n    return \\array_reduce($array, function ($map, $item) use ($keyFn) {\n        $map[$keyFn($item)] = $item;\n        return $map;\n    }, []);\n}\n\n/**\n * @param array    $array\n * @param callable $keyFn\n * @param callable $valFn\n * @return array\n */\nfunction keyValueMap(array $array, callable $keyFn, callable $valFn): array\n{\n    return \\array_reduce($array, function ($map, $item) use ($keyFn, $valFn) {\n        $map[$keyFn($item)] = $valFn($item);\n        return $map;\n    }, []);\n}\n\n/**\n * @param array $map\n * @return PromiseInterface\n */\nfunction promiseForMap(array $map): PromiseInterface\n{\n    $keys             = \\array_keys($map);\n    $promisesOrValues = \\array_map(function ($name) use ($map) {\n        return $map[$name];\n    }, $keys);\n\n    return \\React\\Promise\\all($promisesOrValues)->then(function ($values) use ($keys) {\n        $i = 0;\n        return \\array_reduce($values, function ($resolvedObject, $value) use ($keys, &$i) {\n            $resolvedObject[$keys[$i++]] = $value;\n            return $resolvedObject;\n        }, []);\n    });\n}\n\n/**\n * @param array    $values\n * @param callable $fn\n * @param mixed    $initial\n * @return mixed\n */\nfunction promiseReduce(array $values, callable $fn, $initial = null)\n{\n    return \\array_reduce($values, function ($previous, $value) use ($fn) {\n        return $previous instanceof PromiseInterface\n            ? $previous->then(function ($resolvedValue) use ($fn, $value) {\n                return $fn($resolvedValue, $value);\n            })\n            : $fn($previous, $value);\n    }, $initial);\n}\n\n/**\n * @param mixed $value\n * @return string\n */\nfunction toString($value): string\n{\n    if ($value instanceof TypeInterface) {\n        return (string)$value;\n    }\n    if ($value instanceof NodeInterface) {\n        return printNode($value);\n    }\n    if (\\is_object($value)) {\n        return 'Object';\n    }\n    if (\\is_array($value)) {\n        return 'Array';\n    }\n    if (\\is_callable($value)) {\n        return 'Function';\n    }\n    if ($value === '') {\n        return '(empty string)';\n    }\n    if ($value === null) {\n        return 'null';\n    }\n    if ($value === true) {\n        return 'true';\n    }\n    if ($value === false) {\n        return 'false';\n    }\n    if (\\is_string($value)) {\n        return \"\\\"{$value}\\\"\";\n    }\n    if (\\is_scalar($value)) {\n        return (string)$value;\n    }\n    return \\gettype($value);\n}\n"
  },
  {
    "path": "src/Validation/Conflict/ComparisonContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Conflict;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\n\nclass ComparisonContext\n{\n    /**\n     * @var array\n     */\n    protected $fieldMap = [];\n\n    /**\n     * @var array\n     */\n    protected $fragmentNames = [];\n\n    /**\n     * @var Conflict[]\n     */\n    protected $conflicts = [];\n\n    /**\n     * @param FieldContext $field\n     * @return $this\n     */\n    public function registerField(FieldContext $field)\n    {\n        $responseName = $field->getNode()->getAliasOrNameValue();\n\n        if (!isset($this->fieldMap[$responseName])) {\n            $this->fieldMap[$responseName] = [];\n        }\n\n        $this->fieldMap[$responseName][] = $field;\n\n        return $this;\n    }\n\n    /**\n     * @param NodeInterface|FragmentSpreadNode|FragmentDefinitionNode $fragment\n     * @return $this\n     */\n    public function registerFragment(NodeInterface $fragment)\n    {\n        if ($fragment instanceof NameAwareInterface) {\n            $this->fragmentNames[] = $fragment->getNameValue();\n        }\n\n        return $this;\n    }\n\n    /**\n     * @param Conflict $conflict\n     * @return $this\n     */\n    public function reportConflict(Conflict $conflict)\n    {\n        $this->conflicts[] = $conflict;\n\n        return $this;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFieldMap(): array\n    {\n        return $this->fieldMap;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFragmentNames(): array\n    {\n        return $this->fragmentNames;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasConflicts(): bool\n    {\n        return !empty($this->conflicts);\n    }\n\n    /**\n     * @return Conflict[]\n     */\n    public function getConflicts(): array\n    {\n        return $this->conflicts;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Conflict/Conflict.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Conflict;\n\nclass Conflict\n{\n    /**\n     * @var string\n     */\n    protected $responseName;\n\n    /**\n     * @var mixed\n     */\n    protected $reason;\n\n    /**\n     * @var array\n     */\n    protected $fieldsA;\n\n    /**\n     * @var array\n     */\n    protected $fieldsB;\n\n    /**\n     * Conflict constructor.\n     * @param string $responseName\n     * @param mixed  $reason\n     * @param array  $fieldsA\n     * @param array  $fieldsB\n     */\n    public function __construct(string $responseName, $reason, array $fieldsA, array $fieldsB)\n    {\n        $this->responseName = $responseName;\n        $this->reason       = $reason;\n        $this->fieldsA      = $fieldsA;\n        $this->fieldsB      = $fieldsB;\n    }\n\n    /**\n     * @return string\n     */\n    public function getResponseName(): string\n    {\n        return $this->responseName;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getReason()\n    {\n        return $this->reason;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFieldsA(): array\n    {\n        return $this->fieldsA;\n    }\n\n    /**\n     * @return array\n     */\n    public function getFieldsB(): array\n    {\n        return $this->fieldsB;\n    }\n\n    /**\n     * @return array\n     */\n    public function getAllFields(): array\n    {\n        return \\array_merge($this->fieldsA, $this->fieldsB);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Conflict/ConflictFinder.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Conflict;\n\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Util\\TypeHelper;\nuse Digia\\GraphQL\\Util\\ValueHelper;\nuse Digia\\GraphQL\\Validation\\ValidationContextAwareTrait;\nuse function Digia\\GraphQL\\Type\\getNamedType;\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 * Class ConflictFinder\n * @package Digia\\GraphQL\\Validation\\Conflict\n */\nclass ConflictFinder\n{\n    use ValidationContextAwareTrait;\n\n    /**\n     * 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     * @var \\SplObjectStorage\n     */\n    protected $cachedFieldsAndFragmentNames;\n\n    /**\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     *\n     * @var PairSet\n     */\n    protected $comparedFragmentPairs;\n\n    /**\n     * ConflictFinder constructor.\n     */\n    public function __construct()\n    {\n        $this->cachedFieldsAndFragmentNames = new \\SplObjectStorage();\n        $this->comparedFragmentPairs        = new PairSet();\n    }\n\n    /**\n     * @param SelectionSetNode        $selectionSet\n     * @param NamedTypeInterface|null $parentType\n     * @return array|Conflict[]\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    public function findConflictsWithinSelectionSet(\n        SelectionSetNode $selectionSet,\n        ?NamedTypeInterface $parentType = null\n    ): array {\n        $context = $this->getFieldsAndFragmentNames($selectionSet, $parentType);\n\n        // (A) Find find all conflicts \"within\" the fields of this selection set.\n        // Note: this is the *only place* `collectConflictsWithin` is called.\n        $this->collectConflictsWithin($context);\n\n        $fieldMap      = $context->getFieldMap();\n        $fragmentNames = $context->getFragmentNames();\n\n        // (B) Then collect conflicts between these fields and those represented by\n        // each spread fragment name found.\n        if (!empty($fragmentNames)) {\n            $fragmentNamesCount = \\count($fragmentNames);\n            $comparedFragments  = [];\n\n            /** @noinspection ForeachInvariantsInspection */\n            for ($i = 0; $i < $fragmentNamesCount; $i++) {\n                $this->collectConflictsBetweenFieldsAndFragment(\n                    $context,\n                    $comparedFragments,\n                    $fieldMap,\n                    $fragmentNames[$i],\n                    false/* $areMutuallyExclusive */\n                );\n\n                // (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                for ($j = $i + 1; $j < $fragmentNamesCount; $j++) {\n                    $this->collectConflictsBetweenFragments(\n                        $context,\n                        $fragmentNames[$i],\n                        $fragmentNames[$j],\n                        false/* $areMutuallyExclusive */\n                    );\n                }\n            }\n        }\n\n        return $context->getConflicts();\n    }\n\n    /**\n     * Collect all conflicts found between a set of fields and a fragment reference\n     * including via spreading in any nested fragments.\n     *\n     * @param ComparisonContext $context\n     * @param array             $comparedFragments\n     * @param array             $fieldMap\n     * @param string            $fragmentName\n     * @param bool              $areMutuallyExclusive\n     * @throws ConversionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function collectConflictsBetweenFieldsAndFragment(\n        ComparisonContext $context,\n        array &$comparedFragments,\n        array $fieldMap,\n        string $fragmentName,\n        bool $areMutuallyExclusive\n    ): void {\n        // Memoize so a fragment is not compared for conflicts more than once.\n        if (isset($comparedFragments[$fragmentName])) {\n            return;\n        }\n\n        $comparedFragments[$fragmentName] = true;\n\n        $fragment = $this->getContext()->getFragment($fragmentName);\n\n        if (null === $fragment) {\n            return;\n        }\n\n        $contextB = $this->getReferencedFieldsAndFragmentNames($fragment);\n\n        $fieldMapB = $contextB->getFieldMap();\n\n        // Do not compare a fragment's fieldMap to itself.\n        if ($fieldMap == $fieldMapB) {\n            return;\n        }\n\n        // (D) First collect any conflicts between the provided collection of fields\n        // and the collection of fields represented by the given fragment.\n        $this->collectConflictsBetween(\n            $context,\n            $fieldMap,\n            $fieldMapB,\n            $areMutuallyExclusive\n        );\n\n        $fragmentNamesB = $contextB->getFragmentNames();\n\n        // (E) Then collect any conflicts between the provided collection of fields\n        // and any fragment names found in the given fragment.\n        if (!empty($fragmentNamesB)) {\n            $fragmentNamesBCount = \\count($fragmentNamesB);\n\n            /** @noinspection ForeachInvariantsInspection */\n            for ($i = 0; $i < $fragmentNamesBCount; $i++) {\n                $this->collectConflictsBetweenFieldsAndFragment(\n                    $context,\n                    $comparedFragments,\n                    $fieldMap,\n                    $fragmentNamesB[$i],\n                    $areMutuallyExclusive\n                );\n            }\n        }\n    }\n\n    /**\n     * Collect all conflicts found between two fragments, including via spreading in\n     * any nested fragments.\n     *\n     * @param ComparisonContext $context\n     * @param string            $fragmentNameA\n     * @param string            $fragmentNameB\n     * @param bool              $areMutuallyExclusive\n     * @throws ConversionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function collectConflictsBetweenFragments(\n        ComparisonContext $context,\n        string $fragmentNameA,\n        string $fragmentNameB,\n        bool $areMutuallyExclusive\n    ): void {\n        // No need to compare a fragment to itself.\n        if ($fragmentNameA === $fragmentNameB) {\n            return;\n        }\n\n        // Memoize so two fragments are not compared for conflicts more than once.\n        if ($this->comparedFragmentPairs->has($fragmentNameA, $fragmentNameB, $areMutuallyExclusive)) {\n            return;\n        }\n\n        $this->comparedFragmentPairs->add($fragmentNameA, $fragmentNameB, $areMutuallyExclusive);\n\n        $fragmentA = $this->getContext()->getFragment($fragmentNameA);\n        $fragmentB = $this->getContext()->getFragment($fragmentNameB);\n\n        if (null === $fragmentA || null === $fragmentB) {\n            return;\n        }\n\n        $contextA = $this->getReferencedFieldsAndFragmentNames($fragmentA);\n        $contextB = $this->getReferencedFieldsAndFragmentNames($fragmentB);\n\n        // (F) First, collect all conflicts between these two collections of fields\n        // (not including any nested fragments).\n        $this->collectConflictsBetween(\n            $context,\n            $contextA->getFieldMap(),\n            $contextB->getFieldMap(),\n            $areMutuallyExclusive\n        );\n\n        $fragmentNamesB = $contextB->getFragmentNames();\n\n        // (G) Then collect conflicts between the first fragment and any nested\n        // fragments spread in the second fragment.\n        if (!empty($fragmentNamesB)) {\n            $fragmentNamesBCount = \\count($fragmentNamesB);\n\n            /** @noinspection ForeachInvariantsInspection */\n            for ($j = 0; $j < $fragmentNamesBCount; $j++) {\n                $this->collectConflictsBetweenFragments(\n                    $context,\n                    $fragmentNameA,\n                    $fragmentNamesB[$j],\n                    $areMutuallyExclusive\n                );\n            }\n        }\n\n        $fragmentNamesA = $contextA->getFragmentNames();\n\n        // (G) Then collect conflicts between the second fragment and any nested\n        // fragments spread in the first fragment.\n        if (!empty($fragmentNamesA)) {\n            $fragmentNamesACount = \\count($fragmentNamesA);\n\n            /** @noinspection ForeachInvariantsInspection */\n            for ($i = 0; $i < $fragmentNamesACount; $i++) {\n                $this->collectConflictsBetweenFragments(\n                    $context,\n                    $fragmentNamesA[$i],\n                    $fragmentNameB,\n                    $areMutuallyExclusive\n                );\n            }\n        }\n    }\n\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     * @param NamedTypeInterface|null $parentTypeA\n     * @param SelectionSetNode        $selectionSetA\n     * @param NamedTypeInterface|null $parentTypeB\n     * @param SelectionSetNode        $selectionSetB\n     * @param bool                    $areMutuallyExclusive\n     * @return Conflict[]\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected function findConflictsBetweenSubSelectionSets(\n        ?NamedTypeInterface $parentTypeA,\n        SelectionSetNode $selectionSetA,\n        ?NamedTypeInterface $parentTypeB,\n        SelectionSetNode $selectionSetB,\n        bool $areMutuallyExclusive\n    ): array {\n        $context = new ComparisonContext();\n\n        $contextA = $this->getFieldsAndFragmentNames($selectionSetA, $parentTypeA);\n        $contextB = $this->getFieldsAndFragmentNames($selectionSetB, $parentTypeB);\n\n        $fieldMapA = $contextA->getFieldMap();\n        $fieldMapB = $contextB->getFieldMap();\n\n        $fragmentNamesA = $contextA->getFragmentNames();\n        $fragmentNamesB = $contextB->getFragmentNames();\n\n        $fragmentNamesACount = \\count($fragmentNamesA);\n        $fragmentNamesBCount = \\count($fragmentNamesB);\n\n        // (H) First, collect all conflicts between these two collections of field.\n        $this->collectConflictsBetween(\n            $context,\n            $fieldMapA,\n            $fieldMapB,\n            $areMutuallyExclusive\n        );\n\n        // (I) Then collect conflicts between the first collection of fields and\n        // those referenced by each fragment name associated with the second.\n        if (!empty($fragmentNamesB)) {\n            $comparedFragments = [];\n\n            /** @noinspection ForeachInvariantsInspection */\n            for ($j = 0; $j < $fragmentNamesBCount; $j++) {\n                $this->collectConflictsBetweenFieldsAndFragment(\n                    $context,\n                    $comparedFragments,\n                    $fieldMapA,\n                    $fragmentNamesB[$j],\n                    $areMutuallyExclusive\n                );\n            }\n        }\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        if (!empty($fragmentNamesA)) {\n            $comparedFragments = [];\n\n            /** @noinspection ForeachInvariantsInspection */\n            for ($i = 0; $i < $fragmentNamesACount; $i++) {\n                $this->collectConflictsBetweenFieldsAndFragment(\n                    $context,\n                    $comparedFragments,\n                    $fieldMapB,\n                    $fragmentNamesA[$i],\n                    $areMutuallyExclusive\n                );\n            }\n        }\n\n        /** @noinspection ForeachInvariantsInspection */\n        for ($i = 0; $i < $fragmentNamesACount; $i++) {\n            /** @noinspection ForeachInvariantsInspection */\n            for ($j = 0; $j < $fragmentNamesBCount; $j++) {\n                $this->collectConflictsBetweenFragments(\n                    $context,\n                    $fragmentNamesA[$i],\n                    $fragmentNamesB[$j],\n                    $areMutuallyExclusive\n                );\n            }\n        }\n\n        return $context->getConflicts();\n    }\n\n    /**\n     * Collect all Conflicts \"within\" one collection of fields.\n     *\n     * @param ComparisonContext $context\n     * @throws ConversionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function collectConflictsWithin(ComparisonContext $context): void\n    {\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        foreach ($context->getFieldMap() as $responseName => $fields) {\n            $fieldsCount = \\count($fields);\n\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 ($fieldsCount > 1) {\n                /** @noinspection ForeachInvariantsInspection */\n                for ($i = 0; $i < $fieldsCount; $i++) {\n                    for ($j = $i + 1; $j < $fieldsCount; $j++) {\n                        $conflict = $this->findConflict(\n                            $responseName,\n                            $fields[$i],\n                            $fields[$j],\n                            // within one collection is never mutually exclusive\n                            false/* $areMutuallyExclusive */\n                        );\n\n                        if (null !== $conflict) {\n                            $context->reportConflict($conflict);\n                        }\n                    }\n                }\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     * @param ComparisonContext $context\n     * @param array             $fieldMapA\n     * @param array             $fieldMapB\n     * @param bool              $parentFieldsAreMutuallyExclusive\n     * @throws ConversionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function collectConflictsBetween(\n        ComparisonContext $context,\n        array $fieldMapA,\n        array $fieldMapB,\n        bool $parentFieldsAreMutuallyExclusive\n    ): void {\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        foreach ($fieldMapA as $responseName => $fieldsA) {\n            $fieldsB = $fieldMapB[$responseName] ?? null;\n\n            if (null !== $fieldsB) {\n                $fieldsACount = \\count($fieldsA);\n                $fieldsBCount = \\count($fieldsB);\n                /** @noinspection ForeachInvariantsInspection */\n                for ($i = 0; $i < $fieldsACount; $i++) {\n                    /** @noinspection ForeachInvariantsInspection */\n                    for ($j = 0; $j < $fieldsBCount; $j++) {\n                        $conflict = $this->findConflict(\n                            $responseName,\n                            $fieldsA[$i],\n                            $fieldsB[$j],\n                            $parentFieldsAreMutuallyExclusive\n                        );\n\n                        if (null !== $conflict) {\n                            $context->reportConflict($conflict);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Determines if there is a conflict between two particular fields, including\n     * comparing their sub-fields.\n     *\n     * @param string       $responseName\n     * @param FieldContext $fieldA\n     * @param FieldContext $fieldB\n     * @param bool         $parentFieldsAreMutuallyExclusive\n     * @return Conflict|null\n     * @throws ConversionException\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     */\n    protected function findConflict(\n        string $responseName,\n        FieldContext $fieldA,\n        FieldContext $fieldB,\n        bool $parentFieldsAreMutuallyExclusive\n    ): ?Conflict {\n        $parentTypeA = $fieldA->getParentType();\n        $parentTypeB = $fieldB->getParentType();\n\n        // 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        $areMutuallyExclusive = $parentFieldsAreMutuallyExclusive\n            || ($parentTypeA !== $parentTypeB\n                && $parentTypeA instanceof ObjectType\n                && $parentTypeB instanceof ObjectType);\n\n        $nodeA = $fieldA->getNode();\n        $nodeB = $fieldB->getNode();\n\n        $definitionA = $fieldA->getDefinition();\n        $definitionB = $fieldB->getDefinition();\n\n        if (!$areMutuallyExclusive) {\n            // Two aliases must refer to the same field.\n            $nameA = $nodeA->getNameValue();\n            $nameB = $nodeB->getNameValue();\n\n            if ($nameA !== $nameB) {\n                return new Conflict(\n                    $responseName,\n                    sprintf('%s and %s are different fields', $nameA, $nameB),\n                    [$nodeA],\n                    [$nodeB]\n                );\n            }\n\n            // Two field calls must have the same arguments.\n            if (!ValueHelper::compareArguments($nodeA->getArguments(), $nodeB->getArguments())) {\n                return new Conflict(\n                    $responseName,\n                    'they have differing arguments',\n                    [$nodeA],\n                    [$nodeB]\n                );\n            }\n        }\n\n        // The return type for each field.\n        $typeA = null !== $definitionA ? $definitionA->getType() : null;\n        $typeB = null !== $definitionB ? $definitionB->getType() : null;\n\n        if (null !== $typeA && null !== $typeB && TypeHelper::compareTypes($typeA, $typeB)) {\n            return new Conflict(\n                $responseName,\n                sprintf('they return conflicting types %s and %s', (string)$typeA, (string)$typeB),\n                [$nodeA],\n                [$nodeB]\n            );\n        }\n\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        $selectionSetA = $nodeA->getSelectionSet();\n        $selectionSetB = $nodeB->getSelectionSet();\n\n        if (null !== $selectionSetA && null !== $selectionSetB) {\n            $conflicts = $this->findConflictsBetweenSubSelectionSets(\n                getNamedType($typeA),\n                $selectionSetA,\n                getNamedType($typeB),\n                $selectionSetB,\n                $areMutuallyExclusive\n            );\n\n            return $this->subfieldConflicts($conflicts, $responseName, $nodeA, $nodeB);\n        }\n\n        return null;\n    }\n\n    /**\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     * @param SelectionSetNode        $selectionSet\n     * @param NamedTypeInterface|null $parentType\n     * @return ComparisonContext\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected function getFieldsAndFragmentNames(\n        SelectionSetNode $selectionSet,\n        ?NamedTypeInterface $parentType\n    ): ComparisonContext {\n        if (!$this->cachedFieldsAndFragmentNames->offsetExists($selectionSet)) {\n            $cached = new ComparisonContext();\n\n            $this->collectFieldsAndFragmentNames($cached, $selectionSet, $parentType);\n\n            $this->cachedFieldsAndFragmentNames->offsetSet($selectionSet, $cached);\n        }\n\n        return $this->cachedFieldsAndFragmentNames->offsetGet($selectionSet);\n    }\n\n    /**\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     * @param FragmentDefinitionNode $fragment\n     * @return ComparisonContext\n     * @throws InvalidTypeException\n     * @throws ConversionException\n     * @throws InvariantException\n     */\n    protected function getReferencedFieldsAndFragmentNames(FragmentDefinitionNode $fragment): ComparisonContext\n    {\n        if ($this->cachedFieldsAndFragmentNames->offsetExists($fragment)) {\n            return $this->cachedFieldsAndFragmentNames->offsetGet($fragment);\n        }\n\n        /** @var NamedTypeInterface $fragmentType */\n        $fragmentType = TypeASTConverter::convert($this->getContext()->getSchema(), $fragment->getTypeCondition());\n\n        return $this->getFieldsAndFragmentNames($fragment->getSelectionSet(), $fragmentType);\n    }\n\n    /**\n     * @param ComparisonContext       $context\n     * @param SelectionSetNode        $selectionSet\n     * @param NamedTypeInterface|null $parentType\n     * @throws InvalidTypeException\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected function collectFieldsAndFragmentNames(\n        ComparisonContext $context,\n        SelectionSetNode $selectionSet,\n        ?NamedTypeInterface $parentType\n    ): void {\n        foreach ($selectionSet->getSelections() as $selection) {\n            if ($selection instanceof FieldNode) {\n                $definition = ($parentType instanceof ObjectType || $parentType instanceof InterfaceType)\n                    ? ($parentType->getFields()[$selection->getNameValue()] ?? null)\n                    : null;\n\n                $context->registerField(new FieldContext($parentType, $selection, $definition));\n            } elseif ($selection instanceof FragmentSpreadNode) {\n                $context->registerFragment($selection);\n            } elseif ($selection instanceof InlineFragmentNode) {\n                $typeCondition = $selection->getTypeCondition();\n\n                $inlineFragmentType = null !== $typeCondition\n                    ? TypeASTConverter::convert($this->getContext()->getSchema(), $typeCondition)\n                    : $parentType;\n\n                $this->collectFieldsAndFragmentNames($context, $selection->getSelectionSet(), $inlineFragmentType);\n            }\n        }\n    }\n\n    /**\n     * Given a series of Conflicts which occurred between two sub-fields, generate\n     * a single Conflict.\n     *\n     * @param array|Conflict[] $conflicts\n     * @param string           $responseName\n     * @param FieldNode        $nodeA\n     * @param FieldNode        $nodeB\n     * @return Conflict|null\n     */\n    protected function subfieldConflicts(\n        array $conflicts,\n        string $responseName,\n        FieldNode $nodeA,\n        FieldNode $nodeB\n    ): ?Conflict {\n        if (empty($conflicts)) {\n            return null;\n        }\n\n        return new Conflict(\n            $responseName,\n            array_map(function (Conflict $conflict) {\n                return [$conflict->getResponseName(), $conflict->getReason()];\n            }, $conflicts),\n            array_reduce($conflicts, function ($allFields, Conflict $conflict) {\n                return array_merge($allFields, $conflict->getFieldsA());\n            }, [$nodeA]),\n            array_reduce($conflicts, function ($allFields, Conflict $conflict) {\n                return array_merge($allFields, $conflict->getFieldsB());\n            }, [$nodeB])\n        );\n    }\n}\n"
  },
  {
    "path": "src/Validation/Conflict/FieldContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Conflict;\n\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Type\\Definition\\CompositeTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\n\nclass FieldContext\n{\n    /**\n     * @var NamedTypeInterface|null\n     */\n    protected $parentType;\n\n    /**\n     * @var FieldNode\n     */\n    protected $node;\n\n    /**\n     * @var Field|null\n     */\n    protected $definition;\n\n    /**\n     * FieldContext constructor.\n     * @param NamedTypeInterface|null $parentType\n     * @param FieldNode                   $node\n     * @param Field|null                  $definition\n     */\n    public function __construct(\n        ?NamedTypeInterface $parentType,\n        FieldNode $node,\n        ?Field $definition = null\n    ) {\n        $this->parentType = $parentType;\n        $this->node       = $node;\n        $this->definition = $definition;\n    }\n\n    /**\n     * @return NamedTypeInterface|null\n     */\n    public function getParentType(): ?NamedTypeInterface\n    {\n        return $this->parentType;\n    }\n\n    /**\n     * @return FieldNode\n     */\n    public function getNode(): FieldNode\n    {\n        return $this->node;\n    }\n\n    /**\n     * @return Field|null\n     */\n    public function getDefinition(): ?Field\n    {\n        return $this->definition;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Conflict/PairSet.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Conflict;\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 */\nclass PairSet\n{\n    /**\n     * @var array\n     */\n    protected $data = [];\n\n    /**\n     * @param string $a\n     * @param string $b\n     * @param bool   $areMutuallyExclusive\n     * @return bool\n     */\n    public function has(string $a, string $b, bool $areMutuallyExclusive): bool\n    {\n        $first  = $this->data[$a] ?? null;\n        $result = (null !== $first && isset($first[$b])) ? $first[$b] : null;\n\n        if (null === $result) {\n            return false;\n        }\n\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        if ($areMutuallyExclusive === false) {\n            return $result === false;\n        }\n\n        return true;\n    }\n\n    /**\n     * @param string $a\n     * @param string $b\n     * @param bool   $areMutuallyExclusive\n     */\n    public function add(string $a, string $b, bool $areMutuallyExclusive): void\n    {\n        $this->addToData($a, $b, $areMutuallyExclusive);\n        $this->addToData($b, $a, $areMutuallyExclusive);\n    }\n\n    /**\n     * @param string $a\n     * @param string $b\n     * @param bool   $areMutuallyExclusive\n     */\n    protected function addToData(string $a, string $b, bool $areMutuallyExclusive): void\n    {\n        $map = $this->data[$a] ?? [];\n\n        $map[$b] = $areMutuallyExclusive;\n\n        $this->data[$a] = $map;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/AbstractRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Visitor\\SpecificKindVisitor;\nuse Digia\\GraphQL\\Validation\\ValidationContextAwareTrait;\n\nabstract class AbstractRule extends SpecificKindVisitor implements RuleInterface\n{\n    use ValidationContextAwareTrait;\n}\n"
  },
  {
    "path": "src/Validation/Rule/ExecutableDefinitionsRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\ExecutableDefinitionNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NameAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\nonExecutableDefinitionMessage;\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 */\nclass ExecutableDefinitionsRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterDocument(DocumentNode $node): VisitorResult\n    {\n        foreach ($node->getDefinitions() as $definition) {\n            if (!$definition instanceof ExecutableDefinitionNodeInterface) {\n                $this->context->reportError(\n                    new ValidationException(\n                        nonExecutableDefinitionMessage($this->getDefinitionName($definition)),\n                        [$definition]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return null|string\n     */\n    protected function getDefinitionName(NodeInterface $node): ?string\n    {\n        if ($node instanceof SchemaDefinitionNode || $node instanceof SchemaExtensionNode) {\n            return 'schema';\n        }\n\n        return $node instanceof NameAwareInterface\n            ? $node->getNameValue()\n            : null;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/FieldOnCorrectTypeRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\AbstractTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\FieldsAwareInterface;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\OutputTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Util\\suggestionList;\nuse function Digia\\GraphQL\\Validation\\undefinedFieldMessage;\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 */\nclass FieldOnCorrectTypeRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterField(FieldNode $node): VisitorResult\n    {\n        $type = $this->context->getParentType();\n\n        if ($type instanceof OutputTypeInterface) {\n            $fieldDefinition = $this->context->getFieldDefinition();\n\n            if (null === $fieldDefinition) {\n                $schema              = $this->context->getSchema();\n                $fieldName           = $node->getNameValue();\n                $suggestedTypeNames  = $this->getSuggestedTypeNames($schema, $type, $fieldName);\n                $suggestedFieldNames = \\count($suggestedTypeNames) !== 0\n                    ? []\n                    : $this->getSuggestedFieldNames($type, $fieldName);\n\n                $this->context->reportError(\n                    new ValidationException(\n                        undefinedFieldMessage(\n                            $fieldName,\n                            (string)$type,\n                            $suggestedTypeNames,\n                            $suggestedFieldNames\n                        ),\n                        [$node]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * Go through all of the implementations of type, as well as the interfaces\n     * that they implement. If any of those types include the provided field,\n     * suggest them, sorted by how often the type is referenced,  starting\n     * with Interfaces.\n     *\n     * @param Schema        $schema\n     * @param TypeInterface $type\n     * @param string        $fieldName\n     * @return array\n     * @throws InvariantException\n     */\n    protected function getSuggestedTypeNames(Schema $schema, TypeInterface $type, string $fieldName): array\n    {\n        if (!$type instanceof AbstractTypeInterface) {\n            // Otherwise, must be an Object type, which does not have possible fields.\n            return [];\n        }\n\n        $suggestedObjectTypes = [];\n        $interfaceUsageCount  = [];\n\n        foreach ($schema->getPossibleTypes($type) as $possibleType) {\n            if (!$possibleType instanceof FieldsAwareInterface) {\n                continue;\n            }\n\n            $typeFields = $possibleType->getFields();\n\n            if (!isset($typeFields[$fieldName])) {\n                break;\n            }\n\n            if (!$possibleType instanceof NamedTypeInterface) {\n                continue;\n            }\n\n            $suggestedObjectTypes[] = $possibleType->getName();\n\n            if (!$possibleType instanceof ObjectType) {\n                continue;\n            }\n\n            foreach ($possibleType->getInterfaces() as $possibleInterface) {\n                $interfaceFields = $possibleInterface->getFields();\n\n                if (!isset($interfaceFields[$fieldName])) {\n                    break;\n                }\n\n                $interfaceName                       = $possibleInterface->getName();\n                $interfaceUsageCount[$interfaceName] = ($interfaceUsageCount[$interfaceName] ?? 0) + 1;\n            }\n        }\n\n        $suggestedInterfaceTypes = \\array_keys($interfaceUsageCount);\n\n        \\uasort($suggestedInterfaceTypes, function ($a, $b) use ($interfaceUsageCount) {\n            return $interfaceUsageCount[$b] - $interfaceUsageCount[$a];\n        });\n\n        return \\array_merge($suggestedInterfaceTypes, $suggestedObjectTypes);\n    }\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     * @param OutputTypeInterface $type\n     * @param string              $fieldName\n     * @return array\n     * @throws \\Exception\n     */\n    protected function getSuggestedFieldNames(OutputTypeInterface $type, string $fieldName): array\n    {\n        if (!($type instanceof ObjectType || $type instanceof InterfaceType)) {\n            // Otherwise, must be a Union type, which does not define fields.\n            return [];\n        }\n\n        $possibleFieldNames = \\array_keys($type->getFields());\n\n        return suggestionList($fieldName, $possibleFieldNames);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/FragmentsOnCompositeTypesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\CompositeTypeInterface;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\fragmentOnNonCompositeMessage;\nuse function Digia\\GraphQL\\Validation\\inlineFragmentOnNonCompositeMessage;\n\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 */\nclass FragmentsOnCompositeTypesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        $this->validateFragementNode($node, function (FragmentDefinitionNode $node) {\n            return fragmentOnNonCompositeMessage((string)$node, (string)$node->getTypeCondition());\n        });\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterInlineFragment(InlineFragmentNode $node): VisitorResult\n    {\n        $this->validateFragementNode($node, function (InlineFragmentNode $node) {\n            return inlineFragmentOnNonCompositeMessage((string)$node->getTypeCondition());\n        });\n\n        return new VisitorResult($node);\n    }\n\n\n    /**\n     * @param InlineFragmentNode|FragmentDefinitionNode $node\n     * @param callable                                  $errorMessageFunction\n     * @throws \\Exception\n     * @throws \\TypeError\n     */\n    protected function validateFragementNode($node, callable $errorMessageFunction)\n    {\n        $typeCondition = $node->getTypeCondition();\n\n        if (null !== $typeCondition) {\n            $type = TypeASTConverter::convert($this->context->getSchema(), $typeCondition);\n\n            if (null !== $type && !($type instanceof CompositeTypeInterface)) {\n                $this->context->reportError(\n                    new ValidationException($errorMessageFunction($node),\n                        [$typeCondition]\n                    )\n                );\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/KnownArgumentNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\printNode;\nuse function Digia\\GraphQL\\Util\\suggestionList;\nuse function Digia\\GraphQL\\Validation\\unknownArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\unknownDirectiveArgumentMessage;\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 */\nclass KnownArgumentNamesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterArgument(ArgumentNode $node): VisitorResult\n    {\n        $argumentDefinition = $this->context->getArgument();\n\n        if (null === $argumentDefinition) {\n            $argumentOf = $node->getAncestor();\n\n            if ($argumentOf instanceof FieldNode) {\n                return new VisitorResult($this->validateField($node));\n            }\n\n            if ($argumentOf instanceof DirectiveNode) {\n                return new VisitorResult($this->validateDirective($node));\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return NodeInterface|null\n     */\n    protected function validateField(NodeInterface $node): ?NodeInterface\n    {\n        $fieldDefinition = $this->context->getFieldDefinition();\n        $parentType      = $this->context->getParentType();\n\n        if (null !== $fieldDefinition && null !== $parentType) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $options = \\array_map(function (Argument $argument) {\n                return $argument->getName();\n            }, $fieldDefinition->getArguments());\n\n            $suggestions = suggestionList(printNode($node), $options);\n\n            $this->context->reportError(\n                new ValidationException(\n                    unknownArgumentMessage(\n                        (string)$node,\n                        (string)$fieldDefinition,\n                        (string)$parentType,\n                        $suggestions\n                    ),\n                    [$node]\n                )\n            );\n        }\n\n        return $node;\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return NodeInterface|null\n     */\n    protected function validateDirective(NodeInterface $node): ?NodeInterface\n    {\n        $directive = $this->context->getDirective();\n\n        if (null !== $directive) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $options = \\array_map(function (Argument $argument) {\n                return $argument->getName();\n            }, $directive->getArguments());\n\n            $suggestions = suggestionList((string)$node, $options);\n\n            $this->context->reportError(\n                new ValidationException(\n                    unknownDirectiveArgumentMessage((string)$node, (string)$directive, $suggestions),\n                    [$node]\n                )\n            );\n        }\n\n        return $node;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/KnownDirectivesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\DirectiveLocationEnum;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Util\\find;\nuse function Digia\\GraphQL\\Validation\\misplacedDirectiveMessage;\nuse function Digia\\GraphQL\\Validation\\unknownDirectiveMessage;\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 */\nclass KnownDirectivesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterDirective(DirectiveNode $node): VisitorResult\n    {\n        /** @var Directive $directiveDefinition */\n        $directiveDefinition = find(\n            $this->context->getSchema()->getDirectives(),\n            function (Directive $definition) use ($node) {\n                return $definition->getName() === $node->getNameValue();\n            }\n        );\n\n        if (null == $directiveDefinition) {\n            $this->context->reportError(\n                new ValidationException(unknownDirectiveMessage((string)$node), [$node])\n            );\n\n            return new VisitorResult($node);\n        }\n\n        $location = $this->getDirectiveLocationFromASTPath($node);\n\n        if (null !== $location && !\\in_array($location, $directiveDefinition->getLocations())) {\n            $this->context->reportError(\n                new ValidationException(misplacedDirectiveMessage((string)$node, $location), [$node])\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param NodeInterface $node\n     * @return string|null\n     */\n    protected function getDirectiveLocationFromASTPath(NodeInterface $node): ?string\n    {\n        $appliedTo = $node->getAncestor();\n\n        if ($appliedTo instanceof OperationDefinitionNode) {\n            switch ($appliedTo->getOperation()) {\n                case 'query':\n                    return DirectiveLocationEnum::QUERY;\n                case 'mutation':\n                    return DirectiveLocationEnum::MUTATION;\n                case 'subscription':\n                    return DirectiveLocationEnum::SUBSCRIPTION;\n                default:\n                    return null;\n            }\n        }\n        if ($appliedTo instanceof FieldNode) {\n            return DirectiveLocationEnum::FIELD;\n        }\n        if ($appliedTo instanceof FragmentSpreadNode) {\n            return DirectiveLocationEnum::FRAGMENT_SPREAD;\n        }\n        if ($appliedTo instanceof InlineFragmentNode) {\n            return DirectiveLocationEnum::INLINE_FRAGMENT;\n        }\n        if ($appliedTo instanceof FragmentDefinitionNode) {\n            return DirectiveLocationEnum::FRAGMENT_DEFINITION;\n        }\n        if ($appliedTo instanceof SchemaDefinitionNode || $appliedTo instanceof SchemaExtensionNode) {\n            return DirectiveLocationEnum::SCHEMA;\n        }\n        if ($appliedTo instanceof ScalarTypeDefinitionNode || $appliedTo instanceof ScalarTypeExtensionNode) {\n            return DirectiveLocationEnum::SCALAR;\n        }\n        if ($appliedTo instanceof ObjectTypeDefinitionNode || $appliedTo instanceof ObjectTypeExtensionNode) {\n            return DirectiveLocationEnum::OBJECT;\n        }\n        if ($appliedTo instanceof FieldDefinitionNode) {\n            return DirectiveLocationEnum::FIELD_DEFINITION;\n        }\n        if ($appliedTo instanceof InterfaceTypeDefinitionNode || $appliedTo instanceof InterfaceTypeExtensionNode) {\n            return DirectiveLocationEnum::INTERFACE;\n        }\n        if ($appliedTo instanceof UnionTypeDefinitionNode || $appliedTo instanceof UnionTypeExtensionNode) {\n            return DirectiveLocationEnum::UNION;\n        }\n        if ($appliedTo instanceof EnumTypeDefinitionNode || $appliedTo instanceof EnumTypeExtensionNode) {\n            return DirectiveLocationEnum::ENUM;\n        }\n        if ($appliedTo instanceof EnumValueDefinitionNode) {\n            return DirectiveLocationEnum::ENUM_VALUE;\n        }\n        if ($appliedTo instanceof InputObjectTypeDefinitionNode || $appliedTo instanceof InputObjectTypeExtensionNode) {\n            return DirectiveLocationEnum::INPUT_OBJECT;\n        }\n        if ($appliedTo instanceof InputValueDefinitionNode) {\n            $parentNode = $node->getAncestor(2);\n            return $parentNode instanceof InputObjectTypeDefinitionNode\n                ? DirectiveLocationEnum::INPUT_FIELD_DEFINITION\n                : DirectiveLocationEnum::ARGUMENT_DEFINITION;\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/KnownFragmentNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\unknownFragmentMessage;\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 */\nclass KnownFragmentNamesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    public function enterFragmentSpread(FragmentSpreadNode $node): VisitorResult\n    {\n        $fragmentName = $node->getNameValue();\n        $fragment     = $this->context->getFragment($fragmentName);\n\n        if (null === $fragment) {\n            $this->context->reportError(\n                new ValidationException(unknownFragmentMessage($fragmentName), [$node->getName()])\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/KnownTypeNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Util\\suggestionList;\nuse function Digia\\GraphQL\\Validation\\unknownTypeMessage;\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 */\nclass KnownTypeNamesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterNamedType(NamedTypeNode $node): VisitorResult\n    {\n        $schema   = $this->context->getSchema();\n        $typeName = $node->getNameValue();\n        $type     = $schema->getType($typeName);\n\n        if (null === $type) {\n            $this->context->reportError(\n                new ValidationException(\n                    unknownTypeMessage($typeName, suggestionList($typeName, \\array_keys($schema->getTypeMap()))),\n                    [$node]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    // TODO: when validating IDL, re-enable these. Experimental version does not add unreferenced types, resulting in false-positive errors. Squelched errors for now.\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterObjectTypeDefinition(ObjectTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterInterfaceTypeDefinition(InterfaceTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterUnionTypeDefinition(UnionTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterInputObjectTypeDefinition(InputObjectTypeDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/LoneAnonymousOperationRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\anonymousOperationNotAloneMessage;\n\n/**\n * Lone anonymous operation\n *\n * A GraphQL document is only valid when it contains an anonymous operation\n * (the query short-hand) that it contains only that one operation definition.\n */\nclass LoneAnonymousOperationRule extends AbstractRule\n{\n    /**\n     * @var int\n     */\n    protected $operationCount = 0;\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterDocument(DocumentNode $node): VisitorResult\n    {\n        $this->operationCount = \\count(\\array_filter($node->getDefinitions(), function ($definition) {\n            return $definition instanceof OperationDefinitionNode;\n        }));\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        if (null === $node->getName() && $this->operationCount > 1) {\n            $this->context->reportError(\n                new ValidationException(anonymousOperationNotAloneMessage(), [$node])\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/NoFragmentCyclesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\fragmentCycleMessage;\n\n/**\n * No fragment cycles\n *\n * The graph of fragment spreads must not form any cycles including spreading itself.\n * Otherwise an operation could infinitely spread or infinitely execute on cycles in the underlying data.\n */\nclass NoFragmentCyclesRule extends AbstractRule\n{\n    /**\n     * Tracks already visited fragments to maintain O(N) and to ensure that cycles\n     * are not redundantly reported.\n     *\n     * @var array\n     */\n    protected $visitedFragments = [];\n\n    /**\n     * Array of AST nodes used to produce meaningful errors.\n     *\n     * @var array\n     */\n    protected $spreadPath = [];\n\n    /**\n     * Position in the spread path.\n     *\n     * @var array\n     */\n    protected $spreadPathIndexByName = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null); // Operations cannot contain fragments.\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        if (!isset($this->visitedFragments[$node->getNameValue()])) {\n            $this->detectFragmentCycle($node);\n        }\n\n        return new VisitorResult(null);\n    }\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     * @param FragmentDefinitionNode $fragment\n     */\n    protected function detectFragmentCycle(FragmentDefinitionNode $fragment): void\n    {\n        $fragmentName = $fragment->getNameValue();\n\n        $this->visitedFragments[$fragmentName] = true;\n\n        $spreadNodes = $this->context->getFragmentSpreads($fragment->getSelectionSet());\n\n        if (empty($spreadNodes)) {\n            return;\n        }\n\n        $this->spreadPathIndexByName[$fragmentName] = \\count($this->spreadPath);\n\n        foreach ($spreadNodes as $spreadNode) {\n            $spreadName = $spreadNode->getNameValue();\n            $cycleIndex = $this->spreadPathIndexByName[$spreadName] ?? null;\n\n            if (null === $cycleIndex) {\n                $this->spreadPath[] = $spreadNode;\n\n                if (!isset($this->visitedFragments[$spreadName])) {\n                    $spreadFragment = $this->context->getFragment($spreadName);\n\n                    if (null !== $spreadFragment) {\n                        $this->detectFragmentCycle($spreadFragment);\n                    }\n                }\n\n                \\array_pop($this->spreadPath);\n            } else {\n                $cyclePath = \\array_slice($this->spreadPath, $cycleIndex);\n\n                $this->context->reportError(\n                    new ValidationException(\n                        fragmentCycleMessage($spreadName, \\array_map(function (FragmentSpreadNode $spread) {\n                            return $spread->getNameValue();\n                        }, $cyclePath)),\n                        \\array_merge($cyclePath, [$spreadNode])\n                    )\n                );\n            }\n        }\n\n        $this->spreadPathIndexByName[$fragmentName] = null;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/NoUndefinedVariablesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\undefinedVariableMessage;\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 */\nclass NoUndefinedVariablesRule extends AbstractRule\n{\n    /**\n     * @var array\n     */\n    protected $definedVariableNames;\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $this->definedVariableNames = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        $this->definedVariableNames[$node->getVariable()->getNameValue()] = true;\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function leaveOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $usages = $this->context->getRecursiveVariableUsages($node);\n\n        foreach ($usages as ['node' => $variableNode]) {\n            /** @var VariableNode $variableNode */\n            $variableName = $variableNode->getNameValue();\n\n            if (!isset($this->definedVariableNames[$variableName])) {\n                $operationName = $node->getName();\n                $this->context->reportError(\n                    new ValidationException(\n                        undefinedVariableMessage($variableName, $operationName ? $operationName->getValue() : null),\n                        [$variableNode, $node]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/NoUnusedFragmentsRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\unusedFragmentMessage;\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 */\nclass NoUnusedFragmentsRule extends AbstractRule\n{\n    /**\n     * @var OperationDefinitionNode[]\n     */\n    protected $operationDefinitions = [];\n\n    /**\n     * @var FragmentDefinitionNode[]\n     */\n    protected $fragmentDefinitions = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $this->operationDefinitions[] = $node;\n\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        $this->fragmentDefinitions[] = $node;\n\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function leaveDocument(DocumentNode $node): VisitorResult\n    {\n        $fragmentNamesUsed = [];\n\n        foreach ($this->operationDefinitions as $operationDefinition) {\n            foreach ($this->context->getRecursivelyReferencedFragments($operationDefinition) as $fragmentDefinition) {\n                $fragmentNamesUsed[$fragmentDefinition->getNameValue()] = true;\n            }\n        }\n\n        foreach ($this->fragmentDefinitions as $fragmentDefinition) {\n            $fragmentName = $fragmentDefinition->getNameValue();\n\n            if (!isset($fragmentNamesUsed[$fragmentName])) {\n                $this->context->reportError(\n                    new ValidationException(unusedFragmentMessage($fragmentName), [$fragmentDefinition])\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/NoUnusedVariablesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\unusedVariableMessage;\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 */\nclass NoUnusedVariablesRule extends AbstractRule\n{\n    /**\n     * @var VariableDefinitionNode[]\n     */\n    protected $variableDefinitions;\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $this->variableDefinitions = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        $this->variableDefinitions[] = $node;\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function leaveOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $variableNamesUsed = [];\n        $usages            = $this->context->getRecursiveVariableUsages($node);\n        $operationNameNode = $node->getName();\n        $operationName     = null !== $operationNameNode ? $operationNameNode->getValue() : null;\n\n        /** @var VariableNode $variableNode */\n        foreach ($usages as ['node' => $variableNode]) {\n            $variableNamesUsed[$variableNode->getNameValue()] = true;\n        }\n\n        foreach ($this->variableDefinitions as $variableDefinition) {\n            $variableName = $variableDefinition->getVariable()->getNameValue();\n\n            if (!isset($variableNamesUsed[$variableName])) {\n                $this->context->reportError(\n                    new ValidationException(\n                        unusedVariableMessage($variableName, $operationName),\n                        [$variableDefinition]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/OverlappingFieldsCanBeMergedRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\Conflict\\ConflictFinder;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\fieldsConflictMessage;\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 */\nclass OverlappingFieldsCanBeMergedRule extends AbstractRule\n{\n    /**\n     * @var ConflictFinder\n     */\n    protected $conflictFinder;\n\n    /**\n     * OverlappingFieldsCanBeMergedRule constructor.\n     */\n    public function __construct()\n    {\n        $this->conflictFinder = new ConflictFinder();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterSelectionSet(SelectionSetNode $node): VisitorResult\n    {\n        $this->conflictFinder->setContext($this->context);\n\n        $parentType = $this->context->getParentType();\n        $conflicts  = $this->conflictFinder->findConflictsWithinSelectionSet($node, $parentType);\n\n        foreach ($conflicts as $conflict) {\n            $this->context->reportError(\n                new ValidationException(\n                    fieldsConflictMessage($conflict->getResponseName(), $conflict->getReason()),\n                    $conflict->getAllFields()\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/PossibleFragmentSpreadsRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\CompositeTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Util\\TypeHelper;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\typeIncompatibleAnonymousSpreadMessage;\nuse function Digia\\GraphQL\\Validation\\typeIncompatibleSpreadMessage;\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 */\nclass PossibleFragmentSpreadsRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     *\n     * @throws InvariantException\n     */\n    protected function enterInlineFragment(InlineFragmentNode $node): VisitorResult\n    {\n        $fragmentType = $this->context->getType();\n        $parentType   = $this->context->getParentType();\n\n        if ($fragmentType instanceof CompositeTypeInterface &&\n            $parentType instanceof CompositeTypeInterface &&\n            !TypeHelper::doTypesOverlap($this->context->getSchema(), $fragmentType, $parentType)\n        ) {\n            $this->context->reportError(\n                new ValidationException(\n                    typeIncompatibleAnonymousSpreadMessage((string)$parentType, (string)$fragmentType),\n                    [$node]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected function enterFragmentSpread(FragmentSpreadNode $node): VisitorResult\n    {\n        $fragmentName = $node->getNameValue();\n        $fragmentType = $this->getFragmentType($fragmentName);\n        $parentType   = $this->context->getParentType();\n\n        if (null !== $fragmentType &&\n            null !== $parentType &&\n            !TypeHelper::doTypesOverlap($this->context->getSchema(), $fragmentType, $parentType)\n        ) {\n            $this->context->reportError(\n                new ValidationException(\n                    typeIncompatibleSpreadMessage($fragmentName, (string)$parentType, (string)$fragmentType),\n                    [$node]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @param string $name\n     * @return TypeInterface|null\n     * @throws InvariantException\n     * @throws ConversionException\n     */\n    protected function getFragmentType(string $name): ?TypeInterface\n    {\n        $fragment = $this->context->getFragment($name);\n\n        if (null === $fragment) {\n            return null;\n        }\n\n        $type = TypeASTConverter::convert($this->context->getSchema(), $fragment->getTypeCondition());\n\n        return $type instanceof CompositeTypeInterface ? $type : null;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/ProvidedRequiredArgumentsRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Util\\keyMap;\nuse function Digia\\GraphQL\\Validation\\missingDirectiveArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\missingFieldArgumentMessage;\n\n/**\n * Provided required arguments\n *\n * A field or directive is only valid if all required (non-null) field arguments\n * have been provided.\n */\nclass ProvidedRequiredArgumentsRule extends AbstractRule\n{\n    // Validate on leave to allow for deeper errors to appear first.\n\n    /**\n     * @inheritdoc\n     */\n    protected function leaveField(FieldNode $node): VisitorResult\n    {\n        $fieldDefinition = $this->context->getFieldDefinition();\n\n        if (null === $fieldDefinition) {\n            return new VisitorResult(null);\n        }\n\n        $argumentNodes   = $node->getArguments();\n        $argumentNodeMap = keyMap($argumentNodes, function (ArgumentNode $argument) {\n            return $argument->getNameValue();\n        });\n\n        foreach ($fieldDefinition->getArguments() as $argumentDefinition) {\n            $argumentNode = $argumentNodeMap[$argumentDefinition->getName()] ?? null;\n            $argumentType = $argumentDefinition->getType();\n            $defaultValue = $argumentDefinition->getDefaultValue();\n\n            if (\n                null === $argumentNode\n                && $argumentType instanceof NonNullType\n                && null === $defaultValue\n            ) {\n                $this->context->reportError(\n                    new ValidationException(\n                        missingFieldArgumentMessage(\n                            (string)$node,\n                            (string)$argumentDefinition,\n                            (string)$argumentType\n                        ),\n                        [$node]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function leaveDirective(DirectiveNode $node): VisitorResult\n    {\n        $directiveDefinition = $this->context->getDirective();\n\n        if (null === $directiveDefinition) {\n            return new VisitorResult(null);\n        }\n\n        $argumentNodes   = $node->getArguments();\n        $argumentNodeMap = keyMap($argumentNodes, function (ArgumentNode $argument) {\n            return $argument->getNameValue();\n        });\n\n        foreach ($directiveDefinition->getArguments() as $argumentDefinition) {\n            $argumentNode = $argumentNodeMap[$argumentDefinition->getName()] ?? null;\n            $argumentType = $argumentDefinition->getType();\n\n            if (null === $argumentNode && $argumentType instanceof NonNullType) {\n                $this->context->reportError(\n                    new ValidationException(\n                        missingDirectiveArgumentMessage(\n                            (string)$node,\n                            (string)$argumentDefinition,\n                            (string)$argumentType\n                        ),\n                        [$node]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/RuleInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\ValidationContextInterface;\n\ninterface RuleInterface\n{\n    /**\n     * @param ValidationContextInterface $context\n     * @return $this\n     */\n    public function setContext(ValidationContextInterface $context);\n}\n"
  },
  {
    "path": "src/Validation/Rule/ScalarLeafsRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\LeafTypeInterface;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Type\\getNamedType;\nuse function Digia\\GraphQL\\Validation\\noSubselectionAllowedMessage;\nuse function Digia\\GraphQL\\Validation\\requiresSubselectionMessage;\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 */\nclass ScalarLeafsRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterField(FieldNode $node): VisitorResult\n    {\n        $type         = $this->context->getType();\n        $selectionSet = $node->getSelectionSet();\n\n        if (null !== $type) {\n            if (getNamedType($type) instanceof LeafTypeInterface) {\n                if (null !== $selectionSet) {\n                    $this->context->reportError(\n                        new ValidationException(\n                            noSubselectionAllowedMessage((string)$node, (string)$type),\n                            [$selectionSet]\n                        )\n                    );\n                }\n            } elseif (null === $selectionSet) {\n                $this->context->reportError(\n                    new ValidationException(\n                        requiresSubselectionMessage((string)$node, (string)$type),\n                        [$node]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/SingleFieldSubscriptionsRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\singleFieldOnlyMessage;\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 */\nclass SingleFieldSubscriptionsRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        if ($node->getOperation() !== 'subscription') {\n            return new VisitorResult($node);\n        }\n\n        $selectionSet = $node->getSelectionSet();\n\n        if (null !== $selectionSet) {\n            $selections = $selectionSet->getSelections();\n            if (\\count($selections) !== 1) {\n                $this->context->reportError(\n                    new ValidationException(singleFieldOnlyMessage((string)$node), \\array_slice($selections, 1))\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/SupportedRules.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\GraphQL;\n\nclass SupportedRules\n{\n    /**\n     * @var array\n     */\n    private static $supportedRules = [\n        ExecutableDefinitionsRule::class,\n        FieldOnCorrectTypeRule::class,\n        FragmentsOnCompositeTypesRule::class,\n        KnownArgumentNamesRule::class,\n        KnownDirectivesRule::class,\n        KnownFragmentNamesRule::class,\n        KnownTypeNamesRule::class,\n        LoneAnonymousOperationRule::class,\n        NoFragmentCyclesRule::class,\n        NoUndefinedVariablesRule::class,\n        NoUnusedFragmentsRule::class,\n        NoUnusedVariablesRule::class,\n        OverlappingFieldsCanBeMergedRule::class,\n        PossibleFragmentSpreadsRule::class,\n        ProvidedRequiredArgumentsRule::class,\n        ScalarLeafsRule::class,\n        SingleFieldSubscriptionsRule::class,\n        UniqueArgumentNamesRule::class,\n        UniqueDirectivesPerLocationRule::class,\n        UniqueFragmentNamesRule::class,\n        UniqueVariableNamesRule::class,\n        ValuesOfCorrectTypeRule::class,\n        VariablesAreInputTypesRule::class,\n        VariablesDefaultValueAllowedRule::class,\n        VariablesInAllowedPositionRule::class,\n    ];\n\n    /**\n     * Rules maintain state so they should always new instances.\n     *\n     * @return array\n     */\n    public static function build(): array\n    {\n        $rules = [];\n\n        foreach (self::$supportedRules as $className) {\n            $rules[] = GraphQL::make($className);\n        }\n\n        return $rules;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/UniqueArgumentNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\duplicateArgumentMessage;\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 */\nclass UniqueArgumentNamesRule extends AbstractRule\n{\n    /**\n     * @var NameNode[]\n     */\n    protected $knownArgumentNames = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterField(FieldNode $node): VisitorResult\n    {\n        $this->knownArgumentNames = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterDirective(DirectiveNode $node): VisitorResult\n    {\n        $this->knownArgumentNames = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterArgument(ArgumentNode $node): VisitorResult\n    {\n        $argumentName = $node->getNameValue();\n\n        if (isset($this->knownArgumentNames[$argumentName])) {\n            $this->context->reportError(\n                new ValidationException(\n                    duplicateArgumentMessage($argumentName),\n                    [$this->knownArgumentNames[$argumentName], $node->getName()]\n                )\n            );\n        } else {\n            $this->knownArgumentNames[$argumentName] = $node->getName();\n        }\n\n        return new VisitorResult(null);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/UniqueDirectivesPerLocationRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\DirectivesAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\duplicateDirectiveMessage;\n\n/**\n * Unique directive names per location\n *\n * A GraphQL document is only valid if all directives at a given location\n * are uniquely named.\n */\nclass UniqueDirectivesPerLocationRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    public function enterNode(NodeInterface $node): VisitorResult\n    {\n        if ($node instanceof DirectivesAwareInterface) {\n            $directives      = $node->getDirectives();\n            $knownDirectives = [];\n\n            foreach ($directives as $directive) {\n                $directiveName = $directive->getNameValue();\n\n                if (isset($knownDirectives[$directiveName])) {\n                    $this->context->reportError(\n                        new ValidationException(\n                            duplicateDirectiveMessage($directiveName),\n                            [$knownDirectives[$directiveName], $directive]\n                        )\n                    );\n                } else {\n                    $knownDirectives[$directiveName] = $directive;\n                }\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/UniqueFragmentNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\duplicateFragmentMessage;\n\n/**\n * Unique fragment names\n *\n * A GraphQL document is only valid if all defined fragments have unique names.\n */\nclass UniqueFragmentNamesRule extends AbstractRule\n{\n    /**\n     * @var NameNode[]\n     */\n    protected $knownFragmentNames = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null); // Fragments cannot be defined inside operation definitions.\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        $fragmentName = $node->getNameValue();\n\n        if (isset($this->knownFragmentNames[$fragmentName])) {\n            $this->context->reportError(\n                new ValidationException(\n                    duplicateFragmentMessage($fragmentName),\n                    [$this->knownFragmentNames[$fragmentName], $node->getName()]\n                )\n            );\n        } else {\n            $this->knownFragmentNames[$fragmentName] = $node->getName();\n        }\n\n        return new VisitorResult(null);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/UniqueInputFieldNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\duplicateInputFieldMessage;\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 */\nclass UniqueInputFieldNamesRule extends AbstractRule\n{\n    /**\n     * @var array[]\n     */\n    protected $knownInputNamesStack = [];\n\n    /**\n     * @var NameNode[]\n     */\n    protected $knownInputNames = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterObjectValue(ObjectValueNode $node): VisitorResult\n    {\n        $this->knownInputNamesStack[] = $this->knownInputNames;\n        $this->knownInputNames        = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterObjectField(ObjectFieldNode $node): VisitorResult\n    {\n        $fieldName = $node->getNameValue();\n\n        if (isset($this->knownInputNames[$fieldName])) {\n            $this->context->reportError(\n                new ValidationException(\n                    duplicateInputFieldMessage($fieldName),\n                    [$this->knownInputNames[$fieldName], $node->getName()]\n                )\n            );\n        } else {\n            $this->knownInputNames[$fieldName] = $node->getName();\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function leaveObjectValue(ObjectValueNode $node): VisitorResult\n    {\n        $this->knownInputNames = \\array_pop($this->knownInputNamesStack);\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/UniqueOperationNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\duplicateOperationMessage;\n\n/**\n * Unique operation names\n *\n * A GraphQL document is only valid if all defined operations have unique names.\n */\nclass UniqueOperationNamesRule extends AbstractRule\n{\n    /**\n     * @var NameNode[]\n     */\n    protected $knownOperationNames = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $operationName = $node->getNameValue();\n\n        if (null !== $operationName) {\n            if (isset($this->knownOperationNames[$operationName])) {\n                $this->context->reportError(\n                    new ValidationException(\n                        duplicateOperationMessage($operationName),\n                        [$this->knownOperationNames[$operationName], $node->getName()]\n                    )\n                );\n            } else {\n                $this->knownOperationNames[$operationName] = $node->getName();\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/UniqueVariableNamesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\duplicateVariableMessage;\n\n/**\n * Unique variable names\n *\n * A GraphQL operation is only valid if all its variables are uniquely named.\n */\nclass UniqueVariableNamesRule extends AbstractRule\n{\n    /**\n     * @var NameNode[]\n     */\n    protected $knownVariableNames = [];\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $this->knownVariableNames = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        $variable     = $node->getVariable();\n        $variableName = $variable->getNameValue();\n\n        if (isset($this->knownVariableNames[$variableName])) {\n            $this->context->reportError(\n                new ValidationException(\n                    duplicateVariableMessage($variableName),\n                    [$this->knownVariableNames[$variableName], $variable->getName()]\n                )\n            );\n        } else {\n            $this->knownVariableNames[$variableName] = $variable->getName();\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/ValuesOfCorrectTypeRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ValueNodeInterface;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\EnumValue;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\NamedTypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\printNode;\nuse function Digia\\GraphQL\\Type\\getNamedType;\nuse function Digia\\GraphQL\\Type\\getNullableType;\nuse function Digia\\GraphQL\\Util\\keyMap;\nuse function Digia\\GraphQL\\Util\\orList;\nuse function Digia\\GraphQL\\Util\\suggestionList;\nuse function Digia\\GraphQL\\Validation\\badValueMessage;\nuse function Digia\\GraphQL\\Validation\\requiredFieldMessage;\nuse function Digia\\GraphQL\\Validation\\unknownFieldMessage;\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 */\nclass ValuesOfCorrectTypeRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterNullValue(NullValueNode $node): VisitorResult\n    {\n        $type = $this->context->getInputType();\n\n        if ($type instanceof NonNullType) {\n            $this->context->reportError(\n                new ValidationException(\n                    badValueMessage((string)$type, printNode($node)),\n                    [$node]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterListValue(ListValueNode $node): VisitorResult\n    {\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        $type = getNullableType($this->context->getParentInputType());\n\n        if (!($type instanceof ListType)) {\n            $this->isValidScalar($node);\n\n            return new VisitorResult(null);\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterObjectField(ObjectFieldNode $node): VisitorResult\n    {\n        $parentType = getNamedType($this->context->getParentInputType());\n        $fieldType  = $this->context->getInputType();\n\n        if (null === $fieldType && $parentType instanceof InputObjectType) {\n            $suggestions = suggestionList($node->getNameValue(), \\array_keys($parentType->getFields()));\n            $didYouMean  = !empty($suggestions) ? \\sprintf('Did you mean %s?', orList($suggestions)) : null;\n\n            $this->context->reportError(\n                new ValidationException(\n                    unknownFieldMessage($parentType->getName(), $node->getNameValue(), $didYouMean),\n                    [$node]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterObjectValue(ObjectValueNode $node): VisitorResult\n    {\n        $type = getNamedType($this->context->getInputType());\n\n        if (!($type instanceof InputObjectType)) {\n            $this->isValidScalar($node);\n\n            return new VisitorResult(null);\n        }\n\n        // Ensure every required field exists.\n        $inputFields  = $type->getFields();\n        $fieldNodeMap = keyMap($node->getFields(), function (ObjectFieldNode $field) {\n            return $field->getNameValue();\n        });\n\n        foreach ($inputFields as $fieldName => $field) {\n            $fieldType = $field->getType();\n            $fieldNode = $fieldNodeMap[$fieldName] ?? null;\n            $fieldDefaultValue = $field->getDefaultValue();\n\n            if (null === $fieldNode\n                && $fieldType instanceof NonNullType\n                && null === $fieldDefaultValue\n            ) {\n                $this->context->reportError(\n                    new ValidationException(\n                        requiredFieldMessage($type->getName(), $fieldName, (string)$fieldType),\n                        [$node]\n                    )\n                );\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterEnumValue(EnumValueNode $node): VisitorResult\n    {\n        $type = getNamedType($this->context->getInputType());\n\n        if (!($type instanceof EnumType)) {\n            $this->isValidScalar($node);\n        } elseif (!$type->getValue($node->getValue())) {\n            $didYouMean = $this->getEnumTypeSuggestion($type, $node);\n\n            $this->context->reportError(\n                new ValidationException(\n                    badValueMessage($type->getName(), printNode($node), $didYouMean),\n                    [$node]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterIntValue(IntValueNode $node): VisitorResult\n    {\n        $this->isValidScalar($node);\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterFloatValue(FloatValueNode $node): VisitorResult\n    {\n        $this->isValidScalar($node);\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterStringValue(StringValueNode $node): VisitorResult\n    {\n        $this->isValidScalar($node);\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterBooleanValue(BooleanValueNode $node): VisitorResult\n    {\n        $this->isValidScalar($node);\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * Any value literal may be a valid representation of a Scalar, depending on\n     * that scalar type.\n     *\n     * @param ValueNodeInterface $node\n     * @throws InvariantException\n     */\n    protected function isValidScalar(ValueNodeInterface $node): void\n    {\n        $locationType = $this->context->getInputType();\n\n        if (null === $locationType) {\n            return;\n        }\n\n        $type = getNamedType($locationType);\n\n        if (!($type instanceof ScalarType)) {\n            $didYouMean = $this->getEnumTypeSuggestion($type, $node) ?? null;\n\n            $this->context->reportError(\n                new ValidationException(\n                    badValueMessage((string)$locationType, printNode($node), $didYouMean),\n                    [$node]\n                )\n            );\n\n            return;\n        }\n\n        // Scalars determine if a literal value is valid via parseLiteral() which\n        // may throw or return an invalid value to indicate failure.\n        try {\n            $result = $type->parseLiteral($node, null/* $variables */);\n\n            if (null === $result) {\n                $this->context->reportError(\n                    new ValidationException(\n                        badValueMessage((string)$locationType, printNode($node)),\n                        [$node]\n                    )\n                );\n            }\n        } catch (\\Exception $ex) {\n            // Ensure a reference to the original error is maintained.\n            $this->context->reportError(\n                new ValidationException(\n                    badValueMessage((string)$locationType, printNode($node), $ex->getMessage()),\n                    [$node],\n                    null,\n                    null,\n                    null,\n                    null,\n                    $ex\n                )\n            );\n        }\n    }\n\n    /**\n     * @param NamedTypeInterface $type\n     * @param ValueNodeInterface $node\n     * @return null|string\n     * @throws InvariantException\n     */\n    protected function getEnumTypeSuggestion(NamedTypeInterface $type, ValueNodeInterface $node): ?string\n    {\n        if ($type instanceof EnumType) {\n            $suggestions = suggestionList(printNode($node), \\array_map(function (EnumValue $value) {\n                return $value->getName();\n            }, $type->getValues()));\n\n            return !empty($suggestions)\n                ? \\sprintf('Did you mean the enum value %s?', orList($suggestions))\n                : null;\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/VariablesAreInputTypesRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\printNode;\nuse function Digia\\GraphQL\\Type\\isInputType;\nuse function Digia\\GraphQL\\Validation\\nonInputTypeOnVariableMessage;\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 */\nclass VariablesAreInputTypesRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     *\n     * @throws ConversionException\n     * @throws InvariantException\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        $type = TypeASTConverter::convert($this->context->getSchema(), $node->getType());\n\n        if (!isInputType($type)) {\n            $variableName = $node->getVariable()->getNameValue();\n\n            $this->context->reportError(\n                new ValidationException(\n                    nonInputTypeOnVariableMessage($variableName, printNode($node->getType())),\n                    [$node->getType()]\n                )\n            );\n        }\n\n        return new VisitorResult($node);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/VariablesDefaultValueAllowedRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Validation\\variableDefaultValueNotAllowedMessage;\n\n/**\n * Variable's default value is allowed\n *\n * A GraphQL document is only valid if all variable default values are allowed\n * due to a variable not being required.\n */\nclass VariablesDefaultValueAllowedRule extends AbstractRule\n{\n    /**\n     * @inheritdoc\n     */\n    protected function enterSelectionSet(SelectionSetNode $node): VisitorResult\n    {\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterFragmentDefinition(FragmentDefinitionNode $node): VisitorResult\n    {\n        return new VisitorResult(null);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        $variable     = $node->getVariable();\n        $variableName = $variable->getNameValue();\n        $defaultValue = $node->getDefaultValue();\n        $type         = $this->context->getInputType();\n\n        if (null !== $defaultValue && $type instanceof NonNullType) {\n            $this->context->reportError(\n                new ValidationException(\n                    variableDefaultValueNotAllowedMessage($variableName, $type, (string)$type->getOfType()),\n                    [$defaultValue]\n                )\n            );\n        }\n\n        return new VisitorResult(null); // do not traverse further.\n    }\n}\n"
  },
  {
    "path": "src/Validation/Rule/VariablesInAllowedPositionRule.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Util\\TypeASTConverter;\nuse Digia\\GraphQL\\Util\\TypeHelper;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Validation\\badVariablePositionMessage;\n\n/**\n * Variables in allowed position\n *\n * Variables passed to field arguments conform to type.\n */\nclass VariablesInAllowedPositionRule extends AbstractRule\n{\n    /**\n     * @var VariableDefinitionNode[]|null\n     */\n    protected $variableDefinitionMap;\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $this->variableDefinitionMap = [];\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     *\n     * @throws InvariantException\n     * @throws \\Digia\\GraphQL\\Util\\ConversionException\n     */\n    protected function leaveOperationDefinition(OperationDefinitionNode $node): VisitorResult\n    {\n        $usages = $this->context->getRecursiveVariableUsages($node);\n\n        /**\n         * @var VariableNode  $variableNode\n         * @var TypeInterface $type\n         */\n        foreach ($usages as ['node' => $variableNode, 'type' => $type]) {\n            $variableName       = $variableNode->getNameValue();\n            $variableDefinition = $this->variableDefinitionMap[$variableName];\n\n            if (null !== $variableDefinition && null !== $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                $schema       = $this->context->getSchema();\n                $variableType = TypeASTConverter::convert($schema, $variableDefinition->getType());\n\n                if (null !== $variableType &&\n                    !TypeHelper::isTypeSubtypeOf(\n                        $schema,\n                        $this->getEffectiveType($variableType, $variableDefinition),\n                        $type\n                    )\n                ) {\n                    $this->context->reportError(\n                        new ValidationException(\n                            badVariablePositionMessage($variableName, (string)$variableType, (string)$type),\n                            [$variableDefinition, $variableNode]\n                        )\n                    );\n                }\n            }\n        }\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    protected function enterVariableDefinition(VariableDefinitionNode $node): VisitorResult\n    {\n        $this->variableDefinitionMap[$node->getVariable()->getNameValue()] = $node;\n\n        return new VisitorResult($node);\n    }\n\n    /**\n     * If a variable definition has a default value, it's effectively non-null.\n     *\n     * @param TypeInterface          $variableType\n     * @param VariableDefinitionNode $variableDefinition\n     * @return TypeInterface\n     *\n     * @throws InvariantException\n     */\n    protected function getEffectiveType(\n        TypeInterface $variableType,\n        VariableDefinitionNode $variableDefinition\n    ): TypeInterface {\n        return (!$variableDefinition->hasDefaultValue() || $variableType instanceof NonNullType)\n            ? $variableType\n            : newNonNull($variableType);\n    }\n}\n"
  },
  {
    "path": "src/Validation/RulesProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse Digia\\GraphQL\\Validation\\Rule\\ExecutableDefinitionsRule;\nuse Digia\\GraphQL\\Validation\\Rule\\FieldOnCorrectTypeRule;\nuse Digia\\GraphQL\\Validation\\Rule\\FragmentsOnCompositeTypesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\KnownArgumentNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\KnownDirectivesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\KnownFragmentNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\KnownTypeNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\LoneAnonymousOperationRule;\nuse Digia\\GraphQL\\Validation\\Rule\\NoFragmentCyclesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\NoUndefinedVariablesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\NoUnusedFragmentsRule;\nuse Digia\\GraphQL\\Validation\\Rule\\NoUnusedVariablesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\OverlappingFieldsCanBeMergedRule;\nuse Digia\\GraphQL\\Validation\\Rule\\PossibleFragmentSpreadsRule;\nuse Digia\\GraphQL\\Validation\\Rule\\ProvidedRequiredArgumentsRule;\nuse Digia\\GraphQL\\Validation\\Rule\\ScalarLeafsRule;\nuse Digia\\GraphQL\\Validation\\Rule\\SingleFieldSubscriptionsRule;\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueArgumentNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueDirectivesPerLocationRule;\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueFragmentNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueInputFieldNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueOperationNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueVariableNamesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\ValuesOfCorrectTypeRule;\nuse Digia\\GraphQL\\Validation\\Rule\\VariablesAreInputTypesRule;\nuse Digia\\GraphQL\\Validation\\Rule\\VariablesDefaultValueAllowedRule;\nuse Digia\\GraphQL\\Validation\\Rule\\VariablesInAllowedPositionRule;\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass RulesProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        ExecutableDefinitionsRule::class,\n        FieldOnCorrectTypeRule::class,\n        FragmentsOnCompositeTypesRule::class,\n        KnownArgumentNamesRule::class,\n        KnownDirectivesRule::class,\n        KnownFragmentNamesRule::class,\n        KnownTypeNamesRule::class,\n        LoneAnonymousOperationRule::class,\n        NoFragmentCyclesRule::class,\n        NoUndefinedVariablesRule::class,\n        NoUnusedFragmentsRule::class,\n        NoUnusedVariablesRule::class,\n        OverlappingFieldsCanBeMergedRule::class,\n        PossibleFragmentSpreadsRule::class,\n        ProvidedRequiredArgumentsRule::class,\n        ScalarLeafsRule::class,\n        SingleFieldSubscriptionsRule::class,\n        UniqueArgumentNamesRule::class,\n        UniqueDirectivesPerLocationRule::class,\n        UniqueFragmentNamesRule::class,\n        UniqueVariableNamesRule::class,\n        ValuesOfCorrectTypeRule::class,\n        VariablesAreInputTypesRule::class,\n        VariablesDefaultValueAllowedRule::class,\n        VariablesInAllowedPositionRule::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->add(ExecutableDefinitionsRule::class, ExecutableDefinitionsRule::class);\n        $this->container->add(FieldOnCorrectTypeRule::class, FieldOnCorrectTypeRule::class);\n        $this->container->add(FragmentsOnCompositeTypesRule::class, FragmentsOnCompositeTypesRule::class);\n        $this->container->add(KnownArgumentNamesRule::class, KnownArgumentNamesRule::class);\n        $this->container->add(KnownDirectivesRule::class, KnownDirectivesRule::class);\n        $this->container->add(KnownFragmentNamesRule::class, KnownFragmentNamesRule::class);\n        $this->container->add(KnownTypeNamesRule::class, KnownTypeNamesRule::class);\n        $this->container->add(LoneAnonymousOperationRule::class, LoneAnonymousOperationRule::class);\n        $this->container->add(NoFragmentCyclesRule::class, NoFragmentCyclesRule::class);\n        $this->container->add(NoUndefinedVariablesRule::class, NoUndefinedVariablesRule::class);\n        $this->container->add(NoUnusedFragmentsRule::class, NoUnusedFragmentsRule::class);\n        $this->container->add(NoUnusedVariablesRule::class, NoUnusedVariablesRule::class);\n        $this->container->add(OverlappingFieldsCanBeMergedRule::class, OverlappingFieldsCanBeMergedRule::class);\n        $this->container->add(PossibleFragmentSpreadsRule::class, PossibleFragmentSpreadsRule::class);\n        $this->container->add(ProvidedRequiredArgumentsRule::class, ProvidedRequiredArgumentsRule::class);\n        $this->container->add(ScalarLeafsRule::class, ScalarLeafsRule::class);\n        $this->container->add(SingleFieldSubscriptionsRule::class, SingleFieldSubscriptionsRule::class);\n        $this->container->add(UniqueArgumentNamesRule::class, UniqueArgumentNamesRule::class);\n        $this->container->add(UniqueDirectivesPerLocationRule::class, UniqueDirectivesPerLocationRule::class);\n        $this->container->add(UniqueFragmentNamesRule::class, UniqueFragmentNamesRule::class);\n        $this->container->add(UniqueInputFieldNamesRule::class, UniqueInputFieldNamesRule::class);\n        $this->container->add(UniqueOperationNamesRule::class, UniqueOperationNamesRule::class);\n        $this->container->add(UniqueVariableNamesRule::class, UniqueVariableNamesRule::class);\n        $this->container->add(ValuesOfCorrectTypeRule::class, ValuesOfCorrectTypeRule::class);\n        $this->container->add(VariablesAreInputTypesRule::class, VariablesAreInputTypesRule::class);\n        $this->container->add(VariablesDefaultValueAllowedRule::class, VariablesDefaultValueAllowedRule::class);\n        $this->container->add(VariablesInAllowedPositionRule::class, VariablesInAllowedPositionRule::class);\n    }\n}\n"
  },
  {
    "path": "src/Validation/ValidationContext.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Language\\Visitor\\TypeInfoVisitor;\nuse Digia\\GraphQL\\Language\\Visitor\\Visitor;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorInfo;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Util\\TypeInfo;\n\nclass ValidationContext implements ValidationContextInterface\n{\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @var DocumentNode\n     */\n    protected $document;\n\n    /**\n     * @var TypeInfo\n     */\n    protected $typeInfo;\n\n    /**\n     * @var array|ValidationException[]\n     */\n    protected $errors = [];\n\n    /**\n     * @var array|FragmentDefinitionNode[]\n     */\n    protected $fragments = [];\n\n    /**\n     * @var array\n     */\n    protected $fragmentSpreads = [];\n\n    /**\n     * @var array\n     */\n    protected $variableUsages = [];\n\n    /**\n     * @var array\n     */\n    protected $recursiveVariableUsages = [];\n\n    /**\n     * @var array\n     */\n    protected $recursivelyReferencedFragment = [];\n\n    /**\n     * ValidationContext constructor.\n     * @param Schema       $schema\n     * @param DocumentNode $document\n     * @param TypeInfo     $typeInfo\n     */\n    public function __construct(Schema $schema, DocumentNode $document, TypeInfo $typeInfo)\n    {\n        $this->schema   = $schema;\n        $this->document = $document;\n        $this->typeInfo = $typeInfo;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function reportError(ValidationException $error): void\n    {\n        $this->errors[] = $error;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getErrors(): array\n    {\n        return $this->errors;\n    }\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getType(): ?TypeInterface\n    {\n        return $this->typeInfo->getType();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getParentType(): ?TypeInterface\n    {\n        return $this->typeInfo->getParentType();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getInputType(): ?TypeInterface\n    {\n        return $this->typeInfo->getInputType();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getParentInputType(): ?TypeInterface\n    {\n        return $this->typeInfo->getParentInputType();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getFieldDefinition(): ?Field\n    {\n        return $this->typeInfo->getFieldDefinition();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getSchema(): Schema\n    {\n        return $this->schema;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getArgument(): ?Argument\n    {\n        return $this->typeInfo->getArgument();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getDirective(): ?Directive\n    {\n        return $this->typeInfo->getDirective();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getFragment(string $name): ?FragmentDefinitionNode\n    {\n        if (empty($this->fragments)) {\n            $this->fragments = array_reduce($this->document->getDefinitions(), function ($fragments, $definition) {\n                if ($definition instanceof FragmentDefinitionNode) {\n                    $fragments[$definition->getNameValue()] = $definition;\n                }\n                return $fragments;\n            }, []);\n        }\n\n        return $this->fragments[$name] ?? null;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getFragmentSpreads(SelectionSetNode $selectionSet): array\n    {\n        $spreads = $this->fragmentSpreads[(string)$selectionSet] ?? null;\n\n        if (null === $spreads) {\n            $spreads = [];\n\n            $setsToVisit = [$selectionSet];\n\n            while (!empty($setsToVisit)) {\n                /** @var SelectionSetNode $set */\n                $set = array_pop($setsToVisit);\n\n                foreach ($set->getSelections() as $selection) {\n                    if ($selection instanceof FragmentSpreadNode) {\n                        $spreads[] = $selection;\n                    } elseif ($selection instanceof SelectionSetAwareInterface && $selection->hasSelectionSet()) {\n                        $setsToVisit[] = $selection->getSelectionSet();\n                    }\n                }\n            }\n\n            $this->fragmentSpreads[(string)$selectionSet] = $spreads;\n        }\n\n        return $spreads;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getRecursiveVariableUsages(OperationDefinitionNode $operation): array\n    {\n        $usages = $this->recursiveVariableUsages[(string)$operation] ?? null;\n\n        if (null === $usages) {\n            $usages    = $this->getVariableUsages($operation);\n            $fragments = $this->getRecursivelyReferencedFragments($operation);\n\n            foreach ($fragments as $fragment) {\n                // TODO: Figure out a more performance way to do this.\n                /** @noinspection SlowArrayOperationsInLoopInspection */\n                $usages = array_merge($usages, $this->getVariableUsages($fragment));\n            }\n\n            $this->recursiveVariableUsages[(string)$operation] = $usages;\n        }\n\n        return $usages;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getVariableUsages(NodeInterface $node): array\n    {\n        $usages = $this->variableUsages[(string)$node] ?? null;\n\n        if (null === $usages) {\n            $usages   = [];\n            $typeInfo = new TypeInfo($this->schema);\n\n            $enterCallback = function (NodeInterface $node) use (&$usages, $typeInfo): VisitorResult {\n                if ($node instanceof VariableDefinitionNode) {\n                    return new VisitorResult(null);\n                }\n\n                if ($node instanceof VariableNode) {\n                    $usages[] = [\n                        'node'         => $node,\n                        'type'         => $typeInfo->getInputType(),\n                        'defaultValue' => $typeInfo->getDefaultValue(),\n                    ];\n                }\n\n                return new VisitorResult($node);\n            };\n\n            $visitor = new TypeInfoVisitor($typeInfo, new Visitor($enterCallback));\n\n            $node->acceptVisitor(new VisitorInfo($visitor));\n\n            $this->variableUsages[(string)$node] = $usages;\n        }\n\n        return $usages;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getRecursivelyReferencedFragments(OperationDefinitionNode $operation): array\n    {\n        $fragments = $this->recursivelyReferencedFragment[(string)$operation] ?? null;\n\n        if (null === $fragments) {\n            $fragments      = [];\n            $collectedNames = [];\n            $nodesToVisit   = [$operation->getSelectionSet()];\n\n            while (!empty($nodesToVisit)) {\n                $node    = array_pop($nodesToVisit);\n                $spreads = $this->getFragmentSpreads($node);\n\n                foreach ($spreads as $spread) {\n                    $fragmentName = $spread->getNameValue();\n\n                    if (!isset($collectedNames[$fragmentName])) {\n                        $collectedNames[$fragmentName] = true;\n                        $fragment                      = $this->getFragment($fragmentName);\n\n                        if (null !== $fragment) {\n                            $fragments[]    = $fragment;\n                            $nodesToVisit[] = $fragment->getSelectionSet();\n                        }\n                    }\n                }\n            }\n\n            $this->recursivelyReferencedFragment[(string)$operation] = $fragments;\n        }\n\n        return $fragments;\n    }\n}\n"
  },
  {
    "path": "src/Validation/ValidationContextAwareTrait.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\ntrait ValidationContextAwareTrait\n{\n    /**\n     * @var ValidationContextInterface\n     */\n    protected $context;\n\n    /**\n     * @return ValidationContextInterface\n     */\n    public function getContext(): ValidationContextInterface\n    {\n        return $this->context;\n    }\n\n    /**\n     * @param ValidationContextInterface $context\n     * @return $this\n     */\n    public function setContext(ValidationContextInterface $context)\n    {\n        $this->context = $context;\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Validation/ValidationContextInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\Argument;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\n\ninterface ValidationContextInterface\n{\n    /**\n     * @param ValidationException $error\n     */\n    public function reportError(ValidationException $error): void;\n\n    /**\n     * @return array|ValidationException[]\n     */\n    public function getErrors(): array;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getType(): ?TypeInterface;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getParentType(): ?TypeInterface;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getInputType(): ?TypeInterface;\n\n    /**\n     * @return TypeInterface|null\n     */\n    public function getParentInputType(): ?TypeInterface;\n\n    /**\n     * @return Field|null\n     */\n    public function getFieldDefinition(): ?Field;\n\n    /**\n     * @return Schema\n     */\n    public function getSchema(): Schema;\n\n    /**\n     * @return Argument|null\n     */\n    public function getArgument(): ?Argument;\n\n    /**\n     * @return Directive|null\n     */\n    public function getDirective(): ?Directive;\n\n    /**\n     * @param string $name\n     * @return FragmentDefinitionNode|null\n     */\n    public function getFragment(string $name): ?FragmentDefinitionNode;\n\n    /**\n     * @param SelectionSetNode $selectionSet\n     * @return array|FragmentSpreadNode[]\n     */\n    public function getFragmentSpreads(SelectionSetNode $selectionSet): array;\n\n    /**\n     * @param OperationDefinitionNode $operation\n     * @return array\n     */\n    public function getRecursiveVariableUsages(OperationDefinitionNode $operation): array;\n\n    /**\n     * @param NodeInterface $node\n     * @return array\n     */\n    public function getVariableUsages(NodeInterface $node): array;\n\n    /**\n     * @param OperationDefinitionNode $operation\n     * @return array|FragmentDefinitionNode[]\n     */\n    public function getRecursivelyReferencedFragments(OperationDefinitionNode $operation): array;\n}\n"
  },
  {
    "path": "src/Validation/ValidationException.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\n\nclass ValidationException extends GraphQLException implements ValidationExceptionInterface\n{\n}\n"
  },
  {
    "path": "src/Validation/ValidationExceptionInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\ninterface ValidationExceptionInterface\n{\n}\n"
  },
  {
    "path": "src/Validation/ValidationProvider.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse League\\Container\\ServiceProvider\\AbstractServiceProvider;\n\nclass ValidationProvider extends AbstractServiceProvider\n{\n    /**\n     * @var array\n     */\n    protected $provides = [\n        ValidatorInterface::class,\n    ];\n\n    /**\n     * @inheritdoc\n     */\n    public function register()\n    {\n        $this->container->share(ValidatorInterface::class, Validator::class);\n    }\n}\n"
  },
  {
    "path": "src/Validation/Validator.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Visitor\\ParallelVisitor;\nuse Digia\\GraphQL\\Language\\Visitor\\TypeInfoVisitor;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorInfo;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Util\\TypeInfo;\nuse Digia\\GraphQL\\Validation\\Rule\\RuleInterface;\nuse Digia\\GraphQL\\Validation\\Rule\\SupportedRules;\n\nclass Validator implements ValidatorInterface\n{\n    /**\n     * @inheritdoc\n     */\n    public function validate(\n        Schema $schema,\n        DocumentNode $document,\n        ?array $rules = null,\n        ?TypeInfo $typeInfo = null\n    ): array {\n        $typeInfo = $typeInfo ?? new TypeInfo($schema);\n        $rules    = $rules ?? SupportedRules::build();\n\n        $context = $this->createContext($schema, $document, $typeInfo);\n\n        $visitors = \\array_map(function (RuleInterface $rule) use ($context) {\n            return $rule->setContext($context);\n        }, $rules);\n\n        $visitor = new TypeInfoVisitor($typeInfo, new ParallelVisitor($visitors));\n\n        // Visit the whole document with each instance of all provided rules.\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $document->acceptVisitor(new VisitorInfo($visitor));\n\n        return $context->getErrors();\n    }\n\n    /**\n     * @param Schema       $schema\n     * @param DocumentNode $document\n     * @param TypeInfo     $typeInfo\n     * @return ValidationContextInterface\n     */\n    public function createContext(\n        Schema $schema,\n        DocumentNode $document,\n        TypeInfo $typeInfo\n    ): ValidationContextInterface {\n        return new ValidationContext($schema, $document, $typeInfo);\n    }\n}\n"
  },
  {
    "path": "src/Validation/ValidatorInterface.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Util\\TypeInfo;\n\ninterface ValidatorInterface\n{\n    /**\n     * @param Schema        $schema\n     * @param DocumentNode  $document\n     * @param array|null    $rules\n     * @param TypeInfo|null $typeInfo\n     * @return ValidationException[]\n     */\n    public function validate(\n        Schema $schema,\n        DocumentNode $document,\n        ?array $rules = null,\n        ?TypeInfo $typeInfo = null\n    ): array;\n\n    /**\n     * @param Schema       $schema\n     * @param DocumentNode $document\n     * @param TypeInfo     $typeInfo\n     * @return ValidationContextInterface\n     */\n    public function createContext(\n        Schema $schema,\n        DocumentNode $document,\n        TypeInfo $typeInfo\n    ): ValidationContextInterface;\n}\n"
  },
  {
    "path": "src/Validation/messages.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Validation;\n\nuse function Digia\\GraphQL\\Util\\quotedOrList;\n\n/**\n * @param string $definitionName\n * @return string\n */\nfunction nonExecutableDefinitionMessage(string $definitionName): string\n{\n    return sprintf('The %s definition is not executable.', $definitionName);\n}\n\n/**\n * @param string $fieldName\n * @param string $type\n * @param array  $suggestedTypeNames\n * @param array  $suggestedFieldNames\n * @return string\n */\nfunction undefinedFieldMessage(\n    string $fieldName,\n    string $type,\n    array $suggestedTypeNames,\n    array $suggestedFieldNames\n): string {\n    $message = sprintf('Cannot query field \"%s\" on type \"%s\".', $fieldName, $type);\n    if (!empty($suggestedTypeNames)) {\n        return $message . ' ' . sprintf(\n                'Did you mean to use an inline fragment on %s?',\n                quotedOrList($suggestedTypeNames)\n            );\n    }\n    if (!empty($suggestedFieldNames)) {\n        return $message . ' ' . sprintf('Did you mean %s?', quotedOrList($suggestedFieldNames));\n    }\n    return $message;\n}\n\n/**\n * @param string $typeName\n * @return string\n */\nfunction inlineFragmentOnNonCompositeMessage(string $typeName): string\n{\n    return sprintf('Fragment cannot condition on non composite type \"%s\".', $typeName);\n}\n\n/**\n * @param string $fragmentName\n * @param string $typeName\n * @return string\n */\nfunction fragmentOnNonCompositeMessage(string $fragmentName, string $typeName): string\n{\n    return sprintf('Fragment \"%s\" cannot condition on non composite type \"%s\".', $fragmentName, $typeName);\n}\n\n/**\n * @param string $argumentName\n * @param string $fieldName\n * @param string $typeName\n * @param array  $suggestedArguments\n * @return string\n */\nfunction unknownArgumentMessage(\n    string $argumentName,\n    string $fieldName,\n    string $typeName,\n    array $suggestedArguments\n): string {\n    $message = sprintf('Unknown argument \"%s\" on field \"%s\" of type \"%s\".', $argumentName, $fieldName, $typeName);\n    if (!empty($suggestedArguments)) {\n        return $message . ' ' . sprintf('Did you mean %s', quotedOrList($suggestedArguments));\n    }\n    return $message;\n}\n\n/**\n * @param string $argumentName\n * @param string $directiveName\n * @param array  $suggestedArguments\n * @return string\n */\nfunction unknownDirectiveArgumentMessage(string $argumentName, string $directiveName, array $suggestedArguments): string\n{\n    $message = sprintf('Unknown argument \"%s\" on directive \"@%s\".', $argumentName, $directiveName);\n    if (!empty($suggestedArguments)) {\n        return $message . ' ' . sprintf('Did you mean %s', quotedOrList($suggestedArguments));\n    }\n    return $message;\n}\n\n/**\n * @param string $directiveName\n * @return string\n */\nfunction unknownDirectiveMessage(string $directiveName): string\n{\n    return sprintf('Unknown directive \"%s\".', $directiveName);\n}\n\n/**\n * @param string $directiveName\n * @param string $location\n * @return string\n */\nfunction misplacedDirectiveMessage(string $directiveName, string $location): string\n{\n    return sprintf('Directive \"%s\" may not be used on %s.', $directiveName, $location);\n}\n\n/**\n * @param string $fragmentName\n * @return string\n */\nfunction unknownFragmentMessage(string $fragmentName): string\n{\n    return sprintf('Unknown fragment \"%s\".', $fragmentName);\n}\n\n/**\n * @param string $typeName\n * @param array  $suggestedTypes\n * @return string\n */\nfunction unknownTypeMessage(string $typeName, array $suggestedTypes): string\n{\n    $message = sprintf('Unknown type \"%s\".', $typeName);\n    if (!empty($suggestedTypes)) {\n        return $message . ' ' . sprintf('Did you mean %s?', quotedOrList($suggestedTypes));\n    }\n    return $message;\n}\n\n/**\n * @return string\n */\nfunction anonymousOperationNotAloneMessage(): string\n{\n    return 'This anonymous operation must be the only defined operation.';\n}\n\n/**\n * @param string $fragmentName\n * @param array  $spreadNames\n * @return string\n */\nfunction fragmentCycleMessage(string $fragmentName, array $spreadNames): string\n{\n    $via = !empty($spreadNames) ? ' via ' . implode(', ', $spreadNames) : '';\n    return sprintf('Cannot spread fragment \"%s\" within itself%s.', $fragmentName, $via);\n}\n\n/**\n * @param string      $variableName\n * @param null|string $operationName\n * @return string\n */\nfunction undefinedVariableMessage(string $variableName, ?string $operationName = null): string\n{\n    /** @noinspection IsEmptyFunctionUsageInspection */\n    return !empty($operationName)\n        ? sprintf('Variable \"$%s\" is not defined by operation \"%s\".', $variableName, $operationName)\n        : sprintf('Variable \"$%s\" is not defined.', $variableName);\n}\n\n/**\n * @param string $fragmentName\n * @return string\n */\nfunction unusedFragmentMessage(string $fragmentName): string\n{\n    return sprintf('Fragment \"%s\" is never used.', $fragmentName);\n}\n\n/**\n * @param string      $variableName\n * @param null|string $operationName\n * @return string\n */\nfunction unusedVariableMessage(string $variableName, ?string $operationName = null): string\n{\n    /** @noinspection IsEmptyFunctionUsageInspection */\n    return !empty($operationName)\n        ? sprintf('Variable \"$%s\" is never used in operation \"%s\".', $variableName, $operationName)\n        : sprintf('Variable \"$%s\" is never used.', $variableName);\n}\n\n/**\n * @param string $responseName\n * @param mixed  $reason\n * @return string\n */\nfunction fieldsConflictMessage(string $responseName, $reason): string\n{\n    return sprintf(\n        'Fields \"%s\" conflict because %s. Use different aliases on the fields to fetch both if this was intentional.',\n        $responseName,\n        conflictReasonMessage($reason)\n    );\n}\n\n/**\n * @param array|string $reason\n * @return string\n */\nfunction conflictReasonMessage($reason): string\n{\n    if (\\is_string($reason)) {\n        return $reason;\n    }\n\n    if (\\is_array($reason) && \\is_string($reason[0])) {\n        return conflictReasonMessage([$reason]);\n    }\n\n    return implode(' and ', array_map(function ($reason) {\n        [$responseName, $subreason] = $reason;\n        return sprintf('subfields \"%s\" conflict because %s', $responseName, conflictReasonMessage($subreason));\n    }, $reason));\n}\n\n/**\n * @param string $fragmentName\n * @param string $parentType\n * @param string $fragmentType\n * @return string\n */\nfunction typeIncompatibleSpreadMessage(\n    string $fragmentName,\n    string $parentType,\n    string $fragmentType\n): string {\n    return sprintf(\n        'Fragment \"%s\" cannot be spread here as objects of type \"%s\" can never be of type \"%s\".',\n        $fragmentName,\n        $parentType,\n        $fragmentType\n    );\n}\n\n/**\n * @param string $parentType\n * @param string $fragmentType\n * @return string\n */\nfunction typeIncompatibleAnonymousSpreadMessage(string $parentType, string $fragmentType): string\n{\n    return sprintf(\n        'Fragment cannot be spread here as objects of type \"%s\" can never be of type \"%s\".',\n        $parentType,\n        $fragmentType\n    );\n}\n\n/**\n * @param string $fieldName\n * @param string $argumentName\n * @param string $typeName\n * @return string\n */\nfunction missingFieldArgumentMessage(string $fieldName, string $argumentName, string $typeName): string\n{\n    return sprintf(\n        'Field \"%s\" argument \"%s\" of type \"%s\" is required but not provided.',\n        $fieldName,\n        $argumentName,\n        $typeName\n    );\n}\n\n/**\n * @param string $directiveName\n * @param string $argumentName\n * @param string $typeName\n * @return string\n */\nfunction missingDirectiveArgumentMessage(string $directiveName, string $argumentName, string $typeName): string\n{\n    return sprintf(\n        'Directive \"%s\" argument \"%s\" of type \"%s\" is required but not provided.',\n        $directiveName,\n        $argumentName,\n        $typeName\n    );\n}\n\n/**\n * @param string $fieldName\n * @param string $typeName\n * @return string\n */\nfunction noSubselectionAllowedMessage(string $fieldName, string $typeName): string\n{\n    return sprintf('Field \"%s\" must not have a selection since type \"%s\" has no subfields.', $fieldName, $typeName);\n}\n\n/**\n * @param string $fieldName\n * @param string $typeName\n * @return string\n */\nfunction requiresSubselectionMessage(string $fieldName, string $typeName): string\n{\n    return sprintf(\n        'Field \"%s\" of type \"%s\" must have a selection of subfields. Did you mean \"%s { ... }\"?',\n        $fieldName,\n        $typeName,\n        $fieldName\n    );\n}\n\n/**\n * @param null|string $name\n * @return string\n */\nfunction singleFieldOnlyMessage(?string $name): string\n{\n    $prefix = $name ? \"Subscription {$name}\" : 'Anonymous subscription';\n    return sprintf('%s must select only one top level field.', $prefix);\n}\n\n/**\n * @param string $argumentName\n * @return string\n */\nfunction duplicateArgumentMessage(string $argumentName): string\n{\n    return sprintf('There can be only one argument named \"%s\".', $argumentName);\n}\n\n/**\n * @param string $directiveName\n * @return string\n */\nfunction duplicateDirectiveMessage(string $directiveName): string\n{\n    return sprintf('The directive \"%s\" can only be used once at this location.', $directiveName);\n}\n\n/**\n * @param string $fragmentName\n * @return string\n */\nfunction duplicateFragmentMessage(string $fragmentName): string\n{\n    return sprintf('There can be only one fragment named \"%s\".', $fragmentName);\n}\n\n/**\n * @param string $fieldName\n * @return string\n */\nfunction duplicateInputFieldMessage(string $fieldName): string\n{\n    return sprintf('There can be only one input field named \"%s\".', $fieldName);\n}\n\n/**\n * @param string $operationName\n * @return string\n */\nfunction duplicateOperationMessage(string $operationName): string\n{\n    return sprintf('There can be only one operation named \"%s\".', $operationName);\n}\n\n/**\n * @param string $variableName\n * @return string\n */\nfunction duplicateVariableMessage(string $variableName): string\n{\n    return sprintf('There can be only one variable named \"%s\".', $variableName);\n}\n\n/**\n * @param string $variableName\n * @param string $typeName\n * @return string\n */\nfunction nonInputTypeOnVariableMessage(string $variableName, string $typeName): string\n{\n    return sprintf('Variable \"$%s\" cannot be non-input type \"%s\".', $variableName, $typeName);\n}\n\n/**\n * @param string $variableName\n * @param string $typeName\n * @param string $guessedTypeName\n * @return string\n */\nfunction variableDefaultValueNotAllowedMessage(string $variableName, string $typeName, string $guessedTypeName): string\n{\n    return sprintf(\n        'Variable \"$%s\" of type \"%s\" is required and will not use the default value. Perhaps you meant to use type \"%s\".',\n        $variableName,\n        $typeName,\n        $guessedTypeName\n    );\n}\n\n/**\n * @param string $variableName\n * @param string $typeName\n * @param string $expectedTypeName\n * @return string\n */\nfunction badVariablePositionMessage(string $variableName, string $typeName, string $expectedTypeName): string\n{\n    return sprintf(\n        'Variable \"$%s\" of type \"%s\" used in position expecting type \"%s\".',\n        $variableName,\n        $typeName,\n        $expectedTypeName\n    );\n}\n\n/**\n * @param string      $typeName\n * @param string      $valueName\n * @param null|string $message\n * @return string\n */\nfunction badValueMessage(string $typeName, string $valueName, ?string $message = null): string\n{\n    return sprintf('Expected type %s, found %s%s', $typeName, $valueName, null !== $message ? \"; $message\" : '.');\n}\n\n/**\n * @param string $typeName\n * @param string $fieldName\n * @param string $fieldTypeName\n * @return string\n */\nfunction requiredFieldMessage(string $typeName, string $fieldName, string $fieldTypeName): string\n{\n    return sprintf('Field %s.%s of required type %s was not provided.', $typeName, $fieldName, $fieldTypeName);\n}\n\n/**\n * @param string      $typeName\n * @param string      $fieldName\n * @param null|string $message\n * @return string\n */\nfunction unknownFieldMessage(string $typeName, string $fieldName, ?string $message = null): string\n{\n    return sprintf(\n        'Field %s is not defined by type %s%s',\n        $fieldName,\n        $typeName,\n        null !== $message ? \"; $message\" : '.'\n    );\n}\n"
  },
  {
    "path": "src/api.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Error\\Handler\\CallableMiddleware;\nuse Digia\\GraphQL\\Error\\Handler\\ErrorHandler;\nuse Digia\\GraphQL\\Error\\Handler\\ErrorHandlerInterface;\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\TypeNodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\ValueNodeInterface;\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Language\\StringSourceBuilder;\nuse Digia\\GraphQL\\Language\\SyntaxErrorException;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistryInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidationException;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse React\\Promise\\PromiseInterface;\n\n/**\n * @param string|Source                   $source\n * @param array|ResolverRegistryInterface $resolverRegistry\n * @param array                           $options\n * @return Schema\n * @throws InvariantException\n */\nfunction buildSchema($source, $resolverRegistry = [], array $options = []): Schema\n{\n    if (\\is_string($source)) {\n        $source = (new StringSourceBuilder($source))->build();\n    }\n\n    return GraphQL::buildSchema($source, $resolverRegistry, $options);\n}\n\n/**\n * @param Schema                          $schema\n * @param string|Source                   $source\n * @param array|ResolverRegistryInterface $resolverRegistry\n * @param array                           $options\n * @return Schema\n * @throws InvariantException\n */\nfunction extendSchema(Schema $schema, $source, $resolverRegistry = [], array $options = []): Schema\n{\n    if (\\is_string($source)) {\n        $source = (new StringSourceBuilder($source))->build();\n    }\n\n    return GraphQL::extendSchema($schema, $source, $resolverRegistry, $options);\n}\n\n/**\n * @param Schema $schema\n * @return SchemaValidationException[]\n */\nfunction validateSchema(Schema $schema): array\n{\n    return GraphQL::validateSchema($schema);\n}\n\n/**\n * @param string|Source $source\n * @param array         $options\n * @return DocumentNode\n * @throws InvariantException\n * @throws SyntaxErrorException\n */\nfunction parse($source, array $options = []): DocumentNode\n{\n    if (\\is_string($source)) {\n        $source = (new StringSourceBuilder($source))->build();\n    }\n\n    return GraphQL::parse($source, $options);\n}\n\n/**\n * @param string|Source $source\n * @param array         $options\n * @return ValueNodeInterface\n * @throws InvariantException\n * @throws SyntaxErrorException\n */\nfunction parseValue($source, array $options = []): ValueNodeInterface\n{\n    if (\\is_string($source)) {\n        $source = (new StringSourceBuilder($source))->build();\n    }\n\n    return GraphQL::parseValue($source, $options);\n}\n\n/**\n * @param string|Source $source\n * @param array         $options\n * @return TypeNodeInterface\n * @throws InvariantException\n * @throws SyntaxErrorException\n */\nfunction parseType($source, array $options = []): TypeNodeInterface\n{\n    if (\\is_string($source)) {\n        $source = (new StringSourceBuilder($source))->build();\n    }\n\n    return GraphQL::parseType($source, $options);\n}\n\n/**\n * @param Schema       $schema\n * @param DocumentNode $document\n * @return array|ValidationException[]\n */\nfunction validate(Schema $schema, DocumentNode $document): array\n{\n    return GraphQL::validate($schema, $document);\n}\n\n/**\n * @param Schema                     $schema\n * @param DocumentNode               $document\n * @param mixed|null                 $rootValue\n * @param mixed|null                 $contextValue\n * @param array                      $variableValues\n * @param mixed|null                 $operationName\n * @param callable|null              $fieldResolver\n * @param ErrorHandlerInterface|null $errorHandler\n * @return ExecutionResult\n */\nfunction execute(\n    Schema $schema,\n    DocumentNode $document,\n    $rootValue = null,\n    $contextValue = null,\n    array $variableValues = [],\n    $operationName = null,\n    callable $fieldResolver = null,\n    $errorHandler = null\n): ExecutionResult {\n    $resultPromise = GraphQL::execute(\n        $schema,\n        $document,\n        $rootValue,\n        $contextValue,\n        $variableValues,\n        $operationName,\n        $fieldResolver,\n        $errorHandler\n    );\n\n    $data = null;\n\n    $resultPromise->then(function (ExecutionResult $result) use (&$data) {\n        $data = $result;\n    });\n\n    if (null === $data) {\n        $data = new ExecutionResult(null, [\n            new GraphQLException('Looks like you are using Event Loop. Please use `executeAsync` method instead.')\n        ]);\n    }\n\n    return $data;\n}\n\n/**\n * @param Schema                     $schema\n * @param DocumentNode               $document\n * @param mixed|null                 $rootValue\n * @param mixed|null                 $contextValue\n * @param array                      $variableValues\n * @param mixed|null                 $operationName\n * @param callable|null              $fieldResolver\n * @param ErrorHandlerInterface|null $errorHandler\n * @return PromiseInterface\n */\nfunction executeAsync(\n    Schema $schema,\n    DocumentNode $document,\n    $rootValue = null,\n    $contextValue = null,\n    array $variableValues = [],\n    $operationName = null,\n    callable $fieldResolver = null,\n    $errorHandler = null\n): PromiseInterface {\n    return GraphQL::execute(\n        $schema,\n        $document,\n        $rootValue,\n        $contextValue,\n        $variableValues,\n        $operationName,\n        $fieldResolver,\n        $errorHandler\n    );\n}\n\n/**\n * @param NodeInterface $node\n * @return string\n */\nfunction printNode(NodeInterface $node): string\n{\n    return GraphQL::print($node);\n}\n\n/**\n * @param Schema                              $schema\n * @param string                              $source\n * @param mixed                               $rootValue\n * @param mixed                               $contextValue\n * @param array                               $variableValues\n * @param string|null                         $operationName\n * @param callable|null                       $fieldResolver\n * @param ErrorHandlerInterface|callable|null $errorHandler\n * @return array\n * @throws InvariantException\n * @throws SyntaxErrorException\n */\nfunction graphql(\n    Schema $schema,\n    string $source,\n    $rootValue = null,\n    $contextValue = null,\n    array $variableValues = [],\n    ?string $operationName = null,\n    ?callable $fieldResolver = null,\n    $errorHandler = null\n): array {\n    if (\\is_callable($errorHandler)) {\n        $errorHandler = new ErrorHandler([new CallableMiddleware($errorHandler)]);\n    }\n\n    $resultPromise = GraphQL::process(\n        $schema,\n        $source,\n        $rootValue,\n        $contextValue,\n        $variableValues,\n        $operationName,\n        $fieldResolver,\n        $errorHandler\n    );\n\n    $data = null;\n\n    $resultPromise->then(function (ExecutionResult $result) use (&$data) {\n        $data = $result;\n    });\n\n    if (null === $data) {\n        $data = new ExecutionResult(null, [\n            new GraphQLException('Looks like you are using Event Loop. Please use `graphqlAsync` method instead.')\n        ]);\n    }\n\n    return $data->toArray();\n}\n\n/**\n * @param Schema                              $schema\n * @param string                              $source\n * @param mixed                               $rootValue\n * @param mixed                               $contextValue\n * @param array                               $variableValues\n * @param string|null                         $operationName\n * @param callable|null                       $fieldResolver\n * @param ErrorHandlerInterface|callable|null $errorHandler\n * @return PromiseInterface\n * @throws InvariantException\n * @throws SyntaxErrorException\n */\nfunction graphqlAsync(\n    Schema $schema,\n    string $source,\n    $rootValue = null,\n    $contextValue = null,\n    array $variableValues = [],\n    ?string $operationName = null,\n    ?callable $fieldResolver = null,\n    $errorHandler = null\n): PromiseInterface {\n    if (\\is_callable($errorHandler)) {\n        $errorHandler = new ErrorHandler([new CallableMiddleware($errorHandler)]);\n    }\n\n    $resultPromise = GraphQL::process(\n        $schema,\n        $source,\n        $rootValue,\n        $contextValue,\n        $variableValues,\n        $operationName,\n        $fieldResolver,\n        $errorHandler\n    );\n\n    return $resultPromise->then(function (ExecutionResult $result) {\n        return $result->toArray();\n    });\n}\n"
  },
  {
    "path": "tests/Functional/Execution/AbstractPromiseTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\n\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\n\nclass AbstractPromiseTest extends TestCase\n{\n    // EXECUTE: HANDLES EXECUTION OF ABSTRACT TYPES\n\n    /**\n     * isTypeOf used to resolve runtime type for Interface\n     */\n    public function testIsTypeOfUsedToResolveFunctionForInterface()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetInterfaceType = newInterfaceType([\n            'name'   => 'Pet',\n            'fields' => [\n                'name' => ['type' => stringType()]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return \\React\\Promise\\resolve($obj instanceof Dog);\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return \\React\\Promise\\resolve($obj instanceof Cat);\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ],\n            ]),\n            'types' => [$DogType, $CatType],\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected, $result);\n    }\n\n    /**\n     * isTypeOf can be rejected\n     */\n    public function testIsTypeOfCanBeRejected()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetInterfaceType = newInterfaceType([\n            'name'   => 'Pet',\n            'fields' => [\n                'name' => ['type' => stringType()]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return \\React\\Promise\\reject(new ExecutionException('We are testing this error'));\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return \\React\\Promise\\resolve($obj instanceof Cat);\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ],\n            ]),\n            'types' => [$DogType, $CatType],\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = [\n            'data'   => [\n                'pets' => [\n                    null,\n                    null\n                ]\n            ],\n            'errors' => [\n                [\n                    'message'   => 'We are testing this error',\n                    'locations' => null,\n                    'path'      => ['pets', 0]\n                ],\n                [\n                    'message'   => 'We are testing this error',\n                    'locations' => null,\n                    'path'      => ['pets', 1]\n                ]\n            ]\n        ];\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n\n    /**\n     * isTypeOf used to resolve runtime type for Union\n     */\n    public function testIsTypeOfUsedToResolveRuntimeTypeForUnion()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'     => 'Dog',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return \\React\\Promise\\resolve($obj instanceof Dog);\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'     => 'Cat',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return \\React\\Promise\\resolve($obj instanceof Cat);\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetUnionType = newUnionType([\n            'name'        => 'Pet',\n            'types'       => [$DogType, $CatType],\n            'resolveType' => function ($result, $context, $info) use ($DogType, $CatType) {\n                if ($result instanceof Dog) {\n                    return $DogType;\n                }\n\n                if ($result instanceof Cat) {\n                    return $CatType;\n                }\n                return null;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetUnionType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected, $result);\n    }\n\n    /**\n     * resolveType on Interface yields useful error\n     */\n    public function testResolveTypeOnInterfaceYieldsUsefulError()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetInterfaceType = newInterfaceType([\n            'name'        => 'Pet',\n            'resolveType' => function ($obj) use (&$DogType, &$CatType, &$HumanType) {\n                return \\React\\Promise\\resolve(\n                    $obj instanceof Dog\n                        ? $DogType\n                        : ($obj instanceof Cat\n                        ? $CatType\n                        : ($obj instanceof Human ? $HumanType : null)));\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $HumanType = newObjectType([\n            'name'   => 'Human',\n            'fields' => [\n                'name' => ['type' => stringType()]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return \\React\\Promise\\resolve([\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false),\n                                new Human('John')\n                            ]);\n                        }\n                    ]\n                ]\n            ]),\n            'types' => [$DogType, $CatType]\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = [\n            'data'   => [\n                'pets' => [\n                    [\n                        'name'  => 'Odie',\n                        'woofs' => true,\n                    ],\n                    [\n                        'name'  => 'Garfield',\n                        'meows' => false,\n                    ],\n                    null\n                ]\n            ],\n            'errors' => [\n                [\n                    'message'   => 'Runtime Object type \"Human\" is not a possible type for \"Pet\".',\n                    'locations' => null,\n                    'path'      => ['pets', 2]\n                ],\n            ]\n        ];\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n\n    /**\n     * resolveType on Union yields useful error\n     */\n    public function testResolveTypeOnUnionYieldsUsefulError()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'     => 'Dog',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'     => 'Cat',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $HumanType = newObjectType([\n            'name'     => 'Human',\n            'fields'   => [\n                'name' => ['type' => stringType()]\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Human;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetUnionType = newUnionType([\n            'name'        => 'Pet',\n            'types'       => [$DogType, $CatType],\n            'resolveType' => function ($result, $context, $info) use ($DogType, $CatType, $HumanType) {\n                if ($result instanceof Dog) {\n                    return $DogType;\n                }\n\n                if ($result instanceof Cat) {\n                    return $CatType;\n                }\n\n                if ($result instanceof Human) {\n                    return $HumanType;\n                }\n\n                return null;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetUnionType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return \\React\\Promise\\resolve([\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false),\n                                new Human('John')\n                            ]);\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = [\n            'data'   => [\n                'pets' => [\n                    [\n                        'name'  => 'Odie',\n                        'woofs' => true,\n                    ],\n                    [\n                        'name'  => 'Garfield',\n                        'meows' => false,\n                    ],\n                    null\n                ]\n            ],\n            'errors' => [\n                [\n                    'message'   => 'Runtime Object type \"Human\" is not a possible type for \"Pet\".',\n                    'locations' => null,\n                    'path'      => ['pets', 2]\n                ],\n            ]\n        ];\n\n        $this->assertArraySubset($expected, $result->toArray());\n    }\n\n    /**\n     * resolveType allows resolving with type name\n     */\n    public function testResolveTypeAllowsResolvingWithTypeName()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetInterfaceType = newInterfaceType([\n            'name'        => 'Pet',\n            'resolveType' => function ($obj) {\n                return \\React\\Promise\\resolve(\n                    $obj instanceof Dog\n                        ? 'Dog'\n                        : ($obj instanceof Cat ? 'Cat' : null)\n                );\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n            'types' => [$DogType, $CatType]\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected, $result);\n    }\n\n    /**\n     * resolveType can be caught\n     */\n    public function testResolveTypeCanBeCaught()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetInterfaceType = newInterfaceType([\n            'name'        => 'Pet',\n            'resolveType' => function ($obj) {\n                return \\React\\Promise\\reject(new ExecutionException('We are testing this error'));\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n            'types' => [$DogType, $CatType]\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source));\n\n        $expected = [\n            'data'   => [\n                'pets' => [\n                    null,\n                    null\n                ]\n            ],\n            'errors' => [\n                [\n                    'message'   => 'We are testing this error',\n                    'locations' => null,\n                    'path'      => ['pets', 0]\n                ],\n                [\n                    'message'   => 'We are testing this error',\n                    'locations' => null,\n                    'path'      => ['pets', 1]\n                ]\n            ]\n        ];\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/AbstractTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\n\nclass AbstractTest extends TestCase\n{\n    // EXECUTE: HANDLES EXECUTION OF ABSTRACT TYPES\n\n    /**\n     * isTypeOf used to resolve runtime type for Interface\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIsTypeOfUsedToResolveFunctionForInterface()\n    {\n        $PetInterfaceType = newInterfaceType([\n            'name'   => 'Pet',\n            'fields' => [\n                'name' => ['type' => stringType()]\n            ]\n        ]);\n\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ],\n            ]),\n            'types' => [$DogType, $CatType],\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @var ExecutionResult $executionResult */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected, $result);\n    }\n\n    /**\n     * isTypeOf used to resolve runtime type for Union\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIsTypeOfUsedToResolveRuntimeTypeForUnion()\n    {\n        $DogType = newObjectType([\n            'name'     => 'Dog',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        $CatType = newObjectType([\n            'name'     => 'Cat',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        $PetUnionType = newUnionType([\n            'name'        => 'Pet',\n            'types'       => [$DogType, $CatType],\n            'resolveType' => function ($result, $context, $info) use ($DogType, $CatType) {\n                if ($result instanceof Dog) {\n                    return $DogType;\n                }\n\n                if ($result instanceof Cat) {\n                    return $CatType;\n                }\n\n                return null;\n            }\n        ]);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetUnionType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @var ExecutionResult $executionResult */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected->getData(), $result->getData());\n    }\n\n    /**\n     * resolveType on Interface yields useful error\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testResolveTypeOnInterfaceYieldsUsefulError()\n    {\n        $PetInterfaceType = newInterfaceType([\n            'name'        => 'Pet',\n            'resolveType' => function ($result, $context, $info) use (&$DogType, &$CatType, &$HumanType) {\n                if ($result instanceof Dog) {\n                    return $DogType;\n                }\n\n                if ($result instanceof Cat) {\n                    return $CatType;\n                }\n\n                if ($result instanceof Human) {\n                    return $HumanType;\n                }\n                return null;\n            }\n        ]);\n\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        $HumanType = newObjectType([\n            'name'     => 'Human',\n            'fields'   => [\n                'name' => ['type' => stringType()]\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Human;\n            }\n        ]);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false),\n                                new Human('John')\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n            'types' => [$DogType, $CatType]\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @var ExecutionResult $executionResult */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ],\n                null\n            ]\n        ], [\n            new ExecutionException(\n                'Runtime Object type \"Human\" is not a possible type for \"Pet\".',\n                null,\n                null,\n                null,\n                ['pets', 2]\n            ),\n        ]);\n\n        $this->assertArraySubset($expected->toArray(), $result->toArray());\n    }\n\n    /**\n     * resolveType on Union yields useful error\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testResolveTypeOnUnionYieldsUseFulError()\n    {\n        $DogType = newObjectType([\n            'name'     => 'Dog',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        $CatType = newObjectType([\n            'name'     => 'Cat',\n            'fields'   => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        $HumanType = newObjectType([\n            'name'     => 'Human',\n            'fields'   => [\n                'name' => ['type' => stringType()]\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Human;\n            }\n        ]);\n\n        $PetUnionType = newUnionType([\n            'name'        => 'Pet',\n            'types'       => [$DogType, $CatType],\n            'resolveType' => function ($result, $context, $info) use ($DogType, $CatType, $HumanType) {\n                if ($result instanceof Dog) {\n                    return $DogType;\n                }\n\n                if ($result instanceof Cat) {\n                    return $CatType;\n                }\n\n                if ($result instanceof Human) {\n                    return $HumanType;\n                }\n\n                return null;\n            }\n        ]);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetUnionType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false),\n                                new Human('John')\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @var ExecutionResult $executionResult */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ],\n                null\n            ]\n        ], [\n            new ExecutionException(\n                'Runtime Object type \"Human\" is not a possible type for \"Pet\".',\n                null,\n                null,\n                null,\n                ['pets', 2]\n            ),\n        ]);\n\n        $this->assertArraySubset($expected->toArray(), $result->toArray());\n    }\n\n    /**\n     * resolveType allows resolving with type name\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testResolveTypeAllowsResolvingWithTypeName()\n    {\n        $PetInterfaceType = newInterfaceType([\n            'name'        => 'Pet',\n            'resolveType' => function ($result, $context, $info) {\n                if ($result instanceof Dog) {\n                    return 'Dog';\n                }\n\n                if ($result instanceof Cat) {\n                    return 'Cat';\n                }\n\n                return null;\n            }\n        ]);\n\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$PetInterfaceType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'pets' => [\n                        'type'    => newList($PetInterfaceType),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return [\n                                new Dog('Odie', true),\n                                new Cat('Garfield', false)\n                            ];\n                        }\n                    ]\n                ]\n            ]),\n            'types' => [$DogType, $CatType]\n        ]);\n\n        $source = '{\n          pets {\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        /** @var ExecutionResult $executionResult */\n        $result = execute($schema, parse($source));\n\n        $expected = new ExecutionResult([\n            'pets' => [\n                [\n                    'name'  => 'Odie',\n                    'woofs' => true,\n                ],\n                [\n                    'name'  => 'Garfield',\n                    'meows' => false,\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected, $result);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/DeferredResolverTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse React\\Promise\\Promise;\nuse function Digia\\GraphQL\\graphql;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass DirectorBuffer\n{\n    protected static $directorsIds = [];\n\n    protected static $authors = [];\n\n    public static function add(int $id)\n    {\n        self::$directorsIds[] = $id;\n    }\n\n    public static function get(int $id)\n    {\n        return self::$authors[$id];\n    }\n\n    public static function loadBuffered(): void\n    {\n        self::$authors = [\n            42 => [\n                'name' => 'George Lucas',\n            ],\n            43 => [\n                'name' => 'Irvin Kershner'\n            ]\n        ];\n    }\n}\n\nclass DeferredResolverTest extends ResolveTest\n{\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testUsingFieldDeferredResolver()\n    {\n        $movies = [\n            [\n                'title'      => 'Episode IV – A New Hope',\n                'directorId' => 42\n            ],\n            [\n                'title'      => 'Episode V – The Empire Strikes Back',\n                'directorId' => 43\n            ]\n        ];\n\n        $directorType = newObjectType([\n            'name'        => 'Director',\n            'description' => 'Director of the movie',\n            'fields'      => [\n                'name' => [\n                    'type' => stringType(),\n                ]\n            ]\n        ]);\n\n        $movieType = newObjectType([\n            'name'        => 'Movie',\n            'description' => 'A movie',\n            'fields'      => [\n                'title'    => ['type' => stringType()],\n                'director' => [\n                    'type'    => $directorType,\n                    'resolve' => function ($movie, $args) {\n                        DirectorBuffer::add($movie['directorId']);\n\n                        return new Promise(function (callable $resolve, callable $reject) use ($movie) {\n                            DirectorBuffer::loadBuffered();\n                            $resolve(DirectorBuffer::get($movie['directorId']));\n                        });\n                    }\n                ]\n            ]\n        ]);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'        => 'Query',\n                'description' => '',\n                'fields'      => [\n                    'movies' => [\n                        'type'    => newList($movieType),\n                        'resolve' => function ($source, $args) use ($movies) {\n                            return $movies;\n                        }\n                    ]\n                ]\n            ])\n        ]);\n\n        $query = '\n            {\n                movies {\n                    title\n                    director {\n                        name\n                    }\n                }\n            }\n        ';\n\n        $result = graphql($schema, $query, $movies);\n\n        $this->assertEquals([\n            'data' => [\n                'movies' => [\n                    [\n                        'title'    => 'Episode IV – A New Hope',\n                        'director' => [\n                            'name' => 'George Lucas'\n                        ]\n                    ],\n                    [\n                        'title'    => 'Episode V – The Empire Strikes Back',\n                        'director' => [\n                            'name' => 'Irvin Kershner'\n                        ]\n                    ]\n                ]\n            ]\n        ], $result);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/DirectivesTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass DirectivesTest extends TestCase\n{\n    /**\n     * @var Schema\n     */\n    private $schema;\n\n    /**\n     * @var array\n     */\n    private $data = [\n        'a' => 'a',\n        'b' => 'b'\n    ];\n\n    public function setUp()\n    {\n        parent::setUp();\n\n        $this->schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'TestType',\n                'fields' => [\n                    'a' => ['type' => stringType()],\n                    'b' => ['type' => stringType()]\n                ]\n            ])\n        ]);\n    }\n\n    // WORKS WITHOUT DIRECTIVES\n\n    /**\n     * works without directives\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testWorksWithDirective()\n    {\n        $result = execute($this->schema, parse('{ a, b }'), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * if true includes scalar\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfTrueReturnScalar()\n    {\n        $result = execute($this->schema, parse('{ a, b @include(if: true) }'), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * if false omits on scalar\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfFalseOmitScalar()\n    {\n        $result = execute($this->schema, parse('{ a, b @include(if: false) }'), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    /**\n     * unless false includes scalar\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessFalseIncludesScalar()\n    {\n        $result = execute($this->schema, parse('{ a, b @skip(if: false) }'), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless true omits scalar\n     * \n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessTrueOmitScalar()\n    {\n        $result = execute($this->schema, parse('{ a, b @skip(if: true) }'), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    // WORKS ON FRAGMENT SPREADS\n\n    /**\n     * if false omits fragment spread\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfFalseOmitsFragmentSpread()\n    {\n        $source = 'query {\n          a\n          ...Frag @include(if: false)\n        }\n        fragment Frag on TestType {\n          b\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n\n    /**\n     * if true includes fragment spread\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfTrueIncludesFragmentSpread()\n    {\n        $source = 'query {\n          a\n          ...Frag @include(if: true)\n        }\n        fragment Frag on TestType {\n          b\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless false includes fragment spread\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessFalseIncludesFragmentSpread()\n    {\n        $source = 'query {\n          a\n          ...Frag @skip(if: false)\n        }\n        fragment Frag on TestType {\n          b\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless true omits fragment spread\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessTrueOmitsFragmentSpread()\n    {\n        $source = 'query {\n          a\n          ...Frag @skip(if: true)\n        }\n        fragment Frag on TestType {\n          b\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    // WORKS ON INLINE FRAGMENT\n\n    /**\n     * if false omits inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfFalseOmitsInlineFragment()\n    {\n        $source = 'query {\n          a\n          ... on TestType @include(if: false) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    /**\n     * if true includes inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfTrueIncludesInlineFragment()\n    {\n        $source = 'query {\n          a\n          ... on TestType @include(if: true) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless false includes inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessFalseIncludesInlineFragment()\n    {\n        $source = 'query {\n          a\n          ... on TestType @skip(if: false) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless true includes inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessTrueIncludesInlineFragments()\n    {\n        $source = 'query {\n          a\n          ... on TestType @skip(if: true) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    // WORKS ON ANONYMOUS INLINE FRAGMENT\n\n    /**\n     * if false omits anonymous inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfFalseOmitsAnonymousInlineFragment()\n    {\n        $source = 'query {\n          a\n          ... @include(if: false) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    /**\n     * if true includes anonymous inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIfTrueIncludeAnonymousInlineFragment()\n    {\n        $source = 'query {\n          a\n          ... @include(if: true) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless false includes anonymous inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessFalseIncludesAnonymousInlineFragment()\n    {\n        $source = 'query Q {\n          a\n          ... @skip(if: false) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * unless true includes anonymous inline fragment\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testUnlessTrueIncludeAnonymousInlineFragment()\n    {\n        $source = 'query {\n          a\n          ... @skip(if: true) {\n            b\n          }\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    // WORKS WITH SKIP AND INCLUDE DIRECTIVES\n\n    /**\n     * include and no skip\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIncludeAndNoSkip()\n    {\n        $source = '{\n          a\n          b @include(if: true) @skip(if: false)\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertEquals($this->data, $result->getData());\n    }\n\n    /**\n     * include and skip\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIncludeAndSkip()\n    {\n        $source = '{\n          a\n          b @include(if: true) @skip(if: true)\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n\n    /**\n     * no include or skip\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testNoIncludeOrSkip()\n    {\n        $source = '{\n          a\n          b @include(if: false) @skip(if: false)\n        }';\n\n        $result = execute($this->schema, parse($source), $this->data);\n\n        $this->assertSame(['a' => 'a'], $result->getData());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/ExecutionTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\graphql;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass ExecutionTest extends TestCase\n{\n    /**\n     * throws if no document is provided\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testNoDocumentIsProvided()\n    {\n        $this->expectException(\\TypeError::class);\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType()\n                    ]\n                ]\n            ])\n        ]);\n\n        graphql($schema, null);\n    }\n\n    /**\n     * throws if no schema is provided\n     *\n     * @throws \\Exception\n     */\n    public function testNoSchemaIsProvided()\n    {\n        $this->expectException(\\TypeError::class);\n\n        graphql(null, '{field}');\n    }\n\n    /**\n     * Test accepts an object with named properties as arguments\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testAcceptAnObjectWithNamedPropertiesAsArguments()\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Greeting',\n                'fields' => [\n                    'a' => [\n                        'type'    => stringType(),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return $source;\n                        }\n                    ]\n                ]\n            ])\n        ]);\n\n        $rootValue = 'rootValue';\n        $source    = 'query Example { a }';\n\n        /** @var ExecutionResult $executionResult */\n        $result = graphql($schema, $source, $rootValue);\n\n        $this->assertSame(['data' => ['a' => $rootValue]], $result);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testExecuteHelloQuery()\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Greeting',\n                'fields' => [\n                    'hello' => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'world';\n                        }\n                    ]\n                ]\n            ])\n        ]);\n\n        /** @var ExecutionResult $executionResult */\n        $executionResult = graphql($schema, 'query Greeting {hello}');\n\n        $this->assertSame(['data' => ['hello' => 'world']], $executionResult);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testExecuteArbitraryCode()\n    {\n        $deep = newObjectType([\n            'name'   => 'DeepDataType',\n            'fields' => function () use (&$dataType) {\n                return [\n                    'a'      => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Already Been Done';\n                        }\n                    ],\n                    'b'      => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Boring';\n                        }\n                    ],\n                    'c'      => [\n                        'type'    => newList(stringType()),\n                        'resolve' => function () {\n                            return ['Contrived', null, 'Confusing'];\n                        }\n                    ],\n                    'deeper' => [\n                        'type'    => newList($dataType),\n                        'resolve' => function () {\n                            return [\n                                [\n                                    'a' => 'Apple',\n                                    'b' => 'Banana',\n                                ],\n                                null\n                                ,\n                                [\n                                    'a' => 'Apple',\n                                    'b' => 'Banana',\n                                ]\n                            ];\n                        }\n                    ]\n                ];\n            }\n        ]);\n\n        $dataType = newObjectType([\n            'name'   => 'DataType',\n            'fields' => function () use (&$dataType, &$deep) {\n                return [\n                    'a'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Apple';\n                        }\n                    ],\n                    'b'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Banana';\n                        }\n                    ],\n                    'c'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Cookie';\n                        }\n                    ],\n                    'd'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Donut';\n                        }\n                    ],\n                    'e'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Egg';\n                        }\n                    ],\n                    'f'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Fish';\n                        }\n                    ],\n                    'pic'     => [\n                        'type'    => stringType(),\n                        'resolve' => function ($src, $args) {\n                            return 'Pic of size: ' . ($args['size'] ?? 50);\n                        },\n                        'args'    => [\n                            'size' => [\n                                'type' => intType(),\n                            ]\n                        ],\n                    ],\n                    'promise' => [\n                        'type'    => $dataType,\n                        'resolve' => function () {\n                            return [];\n                        }\n                    ],\n                    'deep'    => [\n                        'type'    => $deep,\n                        'resolve' => function () {\n                            return [];\n                        }\n                    ]\n                ];\n            }\n        ]);\n\n        $source = '\n          query Example($size: Int) {\n            a,\n            b,\n            x: c\n            ...c\n            f\n            ...on DataType {\n              pic(size: $size)\n              promise {\n                a\n              }\n            }\n            deep {\n              a\n              b\n              c\n              deeper {\n                a\n                b\n              }\n            }\n          }\n    \n          fragment c on DataType {\n            d\n            e\n          }\n        ';\n\n        $schema = newSchema(['query' => $dataType]);\n\n        /** @var ExecutionResult $executionResult */\n        $executionResult = execute($schema, parse($source), null, null, ['size' => 100]);\n\n        $expected = new ExecutionResult([\n            'a'       => 'Apple',\n            'b'       => 'Banana',\n            'x'       => 'Cookie',\n            'd'       => 'Donut',\n            'e'       => 'Egg',\n            'f'       => 'Fish',\n            'pic'     => 'Pic of size: 100',\n            'promise' => [\n                'a' => 'Apple'\n            ],\n            'deep'    => [\n                'a'      => 'Already Been Done',\n                'b'      => 'Boring',\n                'c'      => ['Contrived', null, 'Confusing'],\n                'deeper' => [\n                    ['a' => 'Apple', 'b' => 'Banana'],\n                    null,\n                    ['a' => 'Apple', 'b' => 'Banana'],\n                ]\n            ]\n        ], []);\n\n        $this->assertEquals($expected, $executionResult);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testExecuteQueryHelloWithArgs()\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Greeting',\n                'fields' => [\n                    'greeting' => [\n                        'type'    => stringType(),\n                        'resolve' => function ($source, $args, $context, $info) {\n                            return sprintf('Hello %s', $args['name']);\n                        },\n                        'args'    => [\n                            'name' => [\n                                'type' => stringType(),\n                            ]\n                        ]\n                    ]\n                ]\n            ])\n        ]);\n\n        $source         = 'query Hello($name: String) {greeting(name: $name)}';\n        $variableValues = ['name' => 'Han Solo'];\n\n        /** @var ExecutionResult $executionResult */\n        $executionResult = graphql($schema, $source, '', null, $variableValues);\n\n        $this->assertSame(['data' => ['greeting' => 'Hello Han Solo']], $executionResult);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testExecuteQueryWithMultipleFields()\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Human',\n                'fields' => [\n                    'id'         => [\n                        'type'    => intType(),\n                        'resolve' => function () {\n                            return 1000;\n                        }\n                    ],\n                    'type'       => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Human';\n                        }\n                    ],\n                    'friends'    => [\n                        'type'    => newList(stringType()),\n                        'resolve' => function () {\n                            return ['1002', '1003', '2000', '2001'];\n                        }\n                    ],\n                    'appearsIn'  => [\n                        'type'    => newList(intType()),\n                        'resolve' => function () {\n                            return [4, 5, 6];\n                        }\n                    ],\n                    'homePlanet' => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Tatooine';\n                        }\n                    ],\n                ],\n            ]),\n        ]);\n\n        /** @var ExecutionResult $executionResult */\n        $executionResult = graphql($schema, 'query Human {id, type, friends, appearsIn, homePlanet}');\n\n        $this->assertSame([\n            'data' => [\n                'id'         => 1000,\n                'type'       => 'Human',\n                'friends'    => ['1002', '1003', '2000', '2001'],\n                'appearsIn'  => [4, 5, 6],\n                'homePlanet' => 'Tatooine'\n            ]\n        ], $executionResult);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testMergeParallelFragments()\n    {\n        $source = '\n        { a, ...FragOne, ...FragTwo }\n        fragment FragOne on Type {\n            b\n            deep { b, deeper: deep { b } }\n        }\n        fragment FragTwo on Type {\n            c\n            deep { c, deeper: deep { c } }\n        }\n        ';\n\n        $type = newObjectType([\n            'name'   => 'Type',\n            'fields' => function () use (&$type) {\n                return [\n                    'a'    => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Apple';\n                        }\n                    ],\n                    'b'    => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Banana';\n                        }\n                    ],\n                    'c'    => [\n                        'type'    => stringType(),\n                        'resolve' => function () {\n                            return 'Cherry';\n                        }\n                    ],\n                    'deep' => [\n                        'type'    => $type,\n                        'resolve' => function () {\n                            return [];\n                        }\n                    ]\n                ];\n            }\n        ]);\n\n        $schema = newSchema(['query' => $type]);\n\n        /** @var ExecutionResult $executionResult */\n        $executionResult = graphql($schema, $source);\n\n        $this->assertSame([\n            'data' => [\n                'a'    => 'Apple',\n                'b'    => 'Banana',\n                'deep' => [\n                    'b'      => 'Banana',\n                    'deeper' => [\n                        'b' => 'Banana',\n                        'c' => 'Cherry'\n                    ],\n                    'c'      => 'Cherry',\n                ],\n                'c'    => 'Cherry'\n            ]\n        ], $executionResult);\n    }\n\n    /**\n     * provides info about current execution state\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testProvidesInfoAboutCurrentExecutionState()\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Test',\n                'fields' => [\n                    'test' => [\n                        'type'    => stringType(),\n                        'resolve' => function ($source, $args, $context, $_info) use (&$info) {\n                            $info = $_info;\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        $rootValue = [\n            'rootValue' => 'val'\n        ];\n\n        $ast = parse('query ($var: String) { result: test }');\n        execute($schema, $ast, $rootValue, null, ['var' => 123]);\n\n        /** @var ResolveInfo $info */\n        $this->assertSame('test', $info->getFieldName());\n        $this->assertSame(1, count($info->getFieldNodes()));\n        $this->assertEquals(\n            $ast->getDefinitions()[0]->getSelectionSet()->getSelections()[0],\n            $info->getFieldNodes()[0]\n        );\n        $this->assertSame(stringType(), $info->getReturnType());\n        $this->assertEquals($schema->getQueryType(), $info->getParentType());\n        $this->assertSame([\"result\"], $info->getPath()); // { prev: undefined, key: 'result' }\n        $this->assertEquals($schema, $info->getSchema());\n        $this->assertEquals($rootValue, $info->getRootValue());\n        $this->assertEquals($ast->getDefinitions()[0], $info->getOperation());\n        $this->assertEquals(['var' => 123], $info->getVariableValues());\n    }\n\n    /**\n     * Threads root value context correctly\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testThreadsRootValueContextCorrectly()\n    {\n        $resolvedRootValue = null;\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Test',\n                'fields' => [\n                    'a' => [\n                        'type'    => stringType(),\n                        'resolve' => function ($rootValue) use (&$resolvedRootValue) {\n                            $resolvedRootValue = $rootValue;\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        $data = ['contextThing' => 'thing'];\n\n        $ast = parse('query Example { a }');\n\n        execute($schema, $ast, $data);\n\n        $this->assertEquals('thing', $resolvedRootValue['contextThing']);\n    }\n\n    /**\n     * Correctly threads arguments\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testCorrectlyThreadsArguments()\n    {\n        $resolvedArgs = null;\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'b' => [\n                        'type'    => intType(),\n                        'args'    => [\n                            'numArg'    => ['type' => intType()],\n                            'stringArg' => ['type' => stringType()]\n                        ],\n                        'resolve' => function ($source, $args) use (&$resolvedArgs) {\n                            $resolvedArgs = $args;\n                        }\n                    ]\n                ]\n            ]),\n        ]);\n\n        execute($schema, parse('query Example { b(numArg: 123, stringArg: \"foo\") }'));\n\n        $this->assertEquals(['numArg' => 123, 'stringArg' => 'foo'], $resolvedArgs);\n    }\n\n    public function testNullsOutErrorsSubTrees()\n    {\n        $source = dedent('{\n          sync\n          syncError\n          syncRawError\n          syncReturnError\n          syncReturnErrorList\n          async\n          asyncReject\n          asyncRawReject\n          asyncEmptyReject\n          asyncError\n          asyncRawError\n          asyncReturnError\n        }');\n\n        $data = [\n            'sync'                => function () {\n                return 'sync';\n            },\n            'syncError'           => function () {\n                throw new \\Exception('Error getting syncError');\n            },\n            'syncRawError'        => function () {\n                throw new \\Exception('Error getting syncRawError');\n            },\n            'syncReturnError'     => function () {\n                return new \\Exception('Error getting syncReturnError');\n            },\n            'syncReturnErrorList' => function () {\n                return [\n                    'sync0',\n                    new \\Exception('Error getting syncReturnErrorList1'),\n                    'sync2',\n                    new \\Exception('Error getting syncReturnErrorList3'),\n                ];\n            },\n            'async'               => function () {\n                return \\React\\Promise\\resolve('async');\n            },\n            'asyncReject'         => function () {\n                return new \\React\\Promise\\Promise(function ($resolve, $reject) {\n                    $reject(new \\Exception('Error getting asyncReject'));\n                });\n            },\n            'asyncRawReject'      => function () {\n                return \\React\\Promise\\reject('Error getting asyncRawReject');\n            },\n            'asyncEmptyReject'    => function () {\n                return \\React\\Promise\\reject(null);\n            },\n            'asyncError'          => function () {\n                return new \\React\\Promise\\Promise(function () {\n                    throw new \\Exception('Error getting asyncError');\n                });\n            },\n            'asyncRawError'       => function () {\n                return new \\React\\Promise\\Promise(function () {\n                    throw new \\Exception('Error getting asyncRawError');\n                });\n            },\n            'asyncReturnError'    => function () {\n                return \\React\\Promise\\resolve(new \\Exception('Error getting asyncReturnError'));\n            },\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'sync'                => ['type' => stringType()],\n                    'syncError'           => ['type' => stringType()],\n                    'syncRawError'        => ['type' => stringType()],\n                    'syncReturnError'     => ['type' => stringType()],\n                    'syncReturnErrorList' => ['type' => newList(stringType())],\n                    'async'               => ['type' => stringType()],\n                    'asyncReject'         => ['type' => stringType()],\n                    'asyncRawReject'      => ['type' => stringType()],\n                    'asyncEmptyReject'    => ['type' => stringType()],\n                    'asyncError'          => ['type' => stringType()],\n                    'asyncRawError'       => ['type' => stringType()],\n                    'asyncReturnError'    => ['type' => stringType()],\n                ]\n            ]),\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($source), $data);\n\n        $this->assertEquals([\n            'errors' => [\n                [\n                    'message'   => 'Error getting syncError',\n                    'locations' => [\n                        [\n                            'line'   => 3,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['syncError']\n                ],\n                [\n                    'message'   => 'Error getting syncRawError',\n                    'locations' => [\n                        [\n                            'line'   => 4,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['syncRawError']\n                ],\n                [\n                    'message'   => 'Error getting syncReturnError',\n                    'locations' => [\n                        [\n                            'line'   => 5,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['syncReturnError']\n                ],\n                [\n                    'message'   => 'Error getting syncReturnErrorList1',\n                    'locations' => [\n                        [\n                            'line'   => 6,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['syncReturnErrorList', 1]\n                ],\n                [\n                    'message'   => 'Error getting syncReturnErrorList3',\n                    'locations' => [\n                        [\n                            'line'   => 6,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['syncReturnErrorList', 3]\n                ],\n                [\n                    'message'   => 'Error getting asyncReject',\n                    'locations' => [\n                        [\n                            'line'   => 8,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['asyncReject']\n                ],\n                [\n                    'message'   => 'Error getting asyncRawReject',\n                    'locations' => [\n                        [\n                            'line'   => 9,\n                            'column' => 11,\n                        ]\n                    ],\n                    'path'      => ['asyncRawReject']\n                ],\n                [\n                    'message'   => '',\n                    'locations' => [\n                        [\n                            'line'   => 10,\n                            'column' => 11,\n                        ]\n                    ],\n                    'path'      => ['asyncEmptyReject']\n                ],\n                [\n                    'message'   => 'Error getting asyncError',\n                    'locations' => [\n                        [\n                            'line'   => 11,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['asyncError']\n                ],\n                [\n                    'message'   => 'Error getting asyncRawError',\n                    'locations' => [\n                        [\n                            'line'   => 12,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['asyncRawError']\n                ],\n                [\n                    'message'   => 'Error getting asyncReturnError',\n                    'locations' => [\n                        [\n                            'line'   => 13,\n                            'column' => 11\n                        ]\n                    ],\n                    'path'      => ['asyncReturnError']\n                ],\n            ],\n            'data'   => [\n                'sync'                => 'sync',\n                'syncError'           => null,\n                'syncRawError'        => null,\n                'syncReturnError'     => null,\n                'syncReturnErrorList' => ['sync0', null, 'sync2', null],\n                'async'               => 'async',\n                'asyncReject'         => null,\n                'asyncRawReject'      => null,\n                'asyncEmptyReject'    => null,\n                'asyncError'          => null,\n                'asyncRawError'       => null,\n                'asyncReturnError'    => null,\n            ],\n        ], $result->toArray());\n    }\n\n    public function testNullsErrorSubTreeForPromiseRejection()\n    {\n        $query = '\n          query {\n            foods {\n              name\n            }\n          }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'foods' => [\n                        'type'    => newList(newObjectType([\n                            'name'   => 'Food',\n                            'fields' => [\n                                'name' => [\n                                    'type' => stringType()\n                                ]\n                            ]\n                        ])),\n                        'resolve' => function () {\n                            return \\React\\Promise\\reject(new \\Exception('Dangit'));\n                        }\n                    ],\n                ]\n            ]),\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query));\n\n        $this->assertEquals([\n            'data'   => [\n                'foods' => null\n            ],\n            'errors' => [\n                [\n                    'message'   => 'Dangit',\n                    'locations' => [\n                        [\n                            'line'   => 3,\n                            'column' => 13\n                        ]\n                    ],\n                    'path'      => ['foods']\n                ]\n            ]\n        ], $result->toArray());\n    }\n\n    public function testFullResponsePathIsIncludedForNonNullableFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $A = newObjectType([\n            'name'   => 'A',\n            'fields' => function () use (&$A) {\n                return [\n                    'nullableA' => [\n                        'type'    => $A,\n                        'resolve' => function () {\n                            return [];\n                        },\n                    ],\n                    'nonNullA'  => [\n                        'type'    => newNonNull($A),\n                        'resolve' => function () {\n                            return [];\n                        },\n                    ],\n                    'throws'    => [\n                        'type'    => newNonNull(stringType()),\n                        'resolve' => function () {\n                            throw new \\Exception('Catch me if you can!');\n                        },\n                    ],\n                ];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'query',\n                'fields' => function () use (&$A) {\n                    return [\n                        'nullableA' => [\n                            'type'    => $A,\n                            'resolve' => function () {\n                                return [];\n                            },\n                        ],\n                    ];\n                },\n            ])\n        ]);\n\n        $query = dedent('\n          query {\n            nullableA {\n              aliasedA: nullableA {\n                nonNullA {\n                  anotherA: nonNullA {\n                    throws\n                  }\n                }\n              }\n            }\n          }\n        ');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query));\n\n        $this->assertSame([\n            'errors' => [\n                [\n                    'message'   => 'Catch me if you can!',\n                    'locations' => [\n                        [\n                            'line'   => 6,\n                            'column' => 1,\n                        ],\n                    ],\n                    'path'      => [\n                        'nullableA',\n                        'aliasedA',\n                        'nonNullA',\n                        'anotherA',\n                        'throws',\n                    ]\n                ]\n            ],\n            'data'   => [\n                'nullableA' => [\n                    'aliasedA' => null,\n                ],\n            ],\n        ], $result->toArray());\n    }\n\n    /**\n     * Uses the inline operation if no operation name is provided\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testUsesTheInlineOperationIfNoOperationIsProvided()\n    {\n        $rootValue = ['a' => 'b'];\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $result = execute($schema, parse('{ a }'), $rootValue);\n\n        $this->assertEquals([\n            'data' => [\n                'a' => 'b',\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Uses the named operation if operation name is provided\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testUsesTheNamedOperationIfOperationNameIsProvided()\n    {\n        $rootValue = ['a' => 'b'];\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query  = 'query Example { first: a } query OtherExample { second: a }';\n        $result = execute($schema, parse($query), $rootValue, null, [], 'OtherExample');\n\n        $this->assertEquals([\n            'data' => [\n                'second' => 'b',\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Provides error if no operation is provided\n     */\n    public function testProvidesErrorIfNoOperationIsProvided()\n    {\n        $rootValue = ['a' => 'b'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query  = 'fragment Example on Type { a }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue);\n\n        $this->assertEquals([\n            'data'   => null,\n            'errors' => [\n                [\n                    'message'   => 'Must provide an operation.',\n                    'locations' => null,\n                ]\n            ]\n        ], $result->toArray());\n    }\n\n\n    /**\n     * Errors if no op name is provided with multiple operations\n     */\n    public function testErrorsIfNoOpNameIsProvidedWithMultipleOperations()\n    {\n        $rootValue = ['a' => 'b'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query  = 'query Example { a } query OtherExample { a }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue);\n\n        $this->assertEquals([\n            'data'   => null,\n            'errors' => [\n                [\n                    'message'   => 'Must provide operation name if query contains multiple operations.',\n                    'locations' => null,\n                ]\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Errors if unknown operation name is provided\n     */\n    public function testErrorsIfUnknownOperationNameIsProvided()\n    {\n        $rootValue = ['a' => 'b'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query = 'query Example { a } query OtherExample { a }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue, [], [], 'UnknownExample');\n\n        $this->assertEquals([\n            'data'   => null,\n            'errors' => [\n                [\n                    'message'   => 'Unknown operation named \"UnknownExample\".',\n                    'locations' => null,\n                ]\n            ]\n        ], $result->toArray());\n    }\n\n\n    /**\n     * Uses the query schema for queries\n     */\n    public function testUsesTheQuerySchemaForQueries()\n    {\n        $rootValue = ['a' => 'b'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query'        => newObjectType([\n                'name'   => 'Q',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ]),\n            'mutation'     => newObjectType([\n                'name'   => 'M',\n                'fields' => [\n                    'c' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ]),\n            'subscription' => newObjectType([\n                'name'   => 'S',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query = 'query Q { a } mutation M { c } subscription S { a }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue, [], [], 'Q');\n\n        $this->assertEquals([\n            'data' => [\n                'a' => 'b',\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Uses the mutation schema for mutations\n     */\n    public function testUsesTheMutationSchemaForMutations()\n    {\n        $rootValue = ['a' => 'b', 'c' => 'd'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query'    => newObjectType([\n                'name'   => 'Q',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ],\n                ],\n            ]),\n            'mutation' => newObjectType([\n                'name'   => 'M',\n                'fields' => [\n                    'c' => [\n                        'type' => stringType(),\n                    ],\n                ],\n            ]),\n        ]);\n\n        $query  = 'query Q { a } mutation M { c } subscription S { a }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue, [], [], 'M');\n\n        $this->assertEquals([\n            'data' => [\n                'c' => 'd',\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Uses the subscription schema for subscriptions\n     */\n    public function testUsesTheSubscriptionSchemaForSubscriptions()\n    {\n        $rootValue = ['a' => 'b'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query'        => newObjectType([\n                'name'   => 'Q',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ]),\n            'subscription' => newObjectType([\n                'name'   => 'S',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query  = 'query Q { a } subscription S { a }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue, [], [], 'S');\n\n        $this->assertEquals([\n            'data' => [\n                'a' => 'b',\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Correct field ordering despite execution order\n     */\n    public function testCorrectFieldOrderingDespiteExecutionOrder()\n    {\n        $rootValue = [\n            'a' => function () {\n                return 'a';\n            },\n            'b' => function () {\n                return \\React\\Promise\\resolve('b');\n            },\n            'c' => function () {\n                return 'c';\n            },\n            'd' => function () {\n                return \\React\\Promise\\resolve('d');\n            },\n            'e' => function () {\n                return 'e';\n            },\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Q',\n                'fields' => [\n                    'a' => ['type' => stringType()],\n                    'b' => ['type' => stringType()],\n                    'c' => ['type' => stringType()],\n                    'd' => ['type' => stringType()],\n                    'e' => ['type' => stringType()],\n                ],\n            ]),\n        ]);\n\n        $query  = '{ a, b, c, d, e }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue);\n\n        $this->assertEquals([\n            'data' => [\n                'a' => 'a',\n                'b' => 'b',\n                'c' => 'c',\n                'd' => 'd',\n                'e' => 'e',\n            ],\n        ], $result->toArray());\n    }\n\n    /**\n     * Avoid recursions\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testAvoidRecursions()\n    {\n        $rootValue = ['a' => 'b'];\n\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Type',\n                'fields' => [\n                    'a' => [\n                        'type' => stringType(),\n                    ],\n                ],\n            ]),\n        ]);\n\n        $query  = '\n        query Q {\n          a\n          ...Frag\n          ...Frag\n        }\n    \n        fragment Frag on Type {\n          a\n          ...Frag\n        }\n        ';\n\n        $result = execute($schema, parse($query), $rootValue, [], [], 'Q');\n\n        $this->assertEquals([\n            'data' => [\n                'a' => 'b',\n            ],\n        ], $result->toArray());\n    }\n\n    /**\n     * Does not include illegal fields in output\n     */\n    public function testDoesNotIncludeIllegalFieldsInOutput()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query'    => newObjectType([\n                'name'   => 'Q',\n                'fields' => [\n                    'a' => ['type' => stringType()],\n                ],\n            ]),\n            'mutation' => newObjectType([\n                'name'   => 'M',\n                'fields' => [\n                    'c' => ['type' => stringType()],\n                ],\n            ]),\n        ]);\n\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $executionResult = execute($schema, parse('mutation M { thisIsIllegalDontIncludeMe }'));\n\n        $expected = new ExecutionResult([], []);\n\n        $this->assertEquals($expected, $executionResult);\n    }\n\n\n    /**\n     * Fails when an isTypeOf check is not met\n     */\n    public function testFailsWhenAnIsTypeOfCheckIsNotMet()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $specialType = newObjectType([\n            'name'     => 'specialType',\n            'fields'   => [\n                'value' => [\n                    'type' => stringType()\n                ]\n            ],\n            'isTypeOf' => function ($obj) {\n                return $obj instanceof Special;\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => function () use ($specialType) {\n                    return [\n                        'specials' => [\n                            'type'    => newList($specialType),\n                            'resolve' => function ($root) {\n                                return $root['specials'];\n                            }\n                        ]\n                    ];\n                }\n            ])\n        ]);\n\n        $rootValue = [\n            'specials' => [\n                new Special('foo'),\n                new NotSpecial('bar')\n            ]\n        ];\n\n        $query = '{ specials { value } }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), $rootValue);\n\n        $this->assertSame([\n            'errors' => [\n                [\n                    'message'   => 'Expected value of type \"specialType\" but got: Object.',\n                    'locations' => [\n                        [\n                            'line'   => 1,\n                            'column' => 3,\n                        ],\n                    ],\n                    'path'      => ['specials', 1],\n                ],\n            ],\n            'data'   => [\n                'specials' => [\n                    ['value' => 'foo'],\n                    null,\n                ],\n            ],\n        ], $result->toArray());\n    }\n\n    /**\n     * Executes ignoring invalid non-executable definitions\n     */\n    public function testExecutesIgnoringInvalidNonExecutableDefinitions()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'foo' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query = '{ foo } type Query { bar: String }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query));\n\n        $this->assertEquals([\n            'data' => [\n                'foo' => null,\n            ]\n        ], $result->toArray());\n    }\n\n    /**\n     * Uses a custom field resolver\n     */\n    public function testUsesACustomFieldResolver()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'foo' => [\n                        'type' => stringType(),\n                    ]\n                ]\n            ])\n        ]);\n\n        $query = '{ foo }';\n\n        $customResolver = function ($source, $args, $context, ResolveInfo $info) {\n            return $info->getFieldName();\n        };\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query), [], [], [], null, $customResolver);\n\n        $this->assertEquals([\n            'data' => [\n                'foo' => 'foo',\n            ]\n        ], $result->toArray());\n    }\n\n    public function testNonNullFieldQuery()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Greeting',\n                'fields' => [\n                    'hello' => [\n                        'type'    => newNonNull(stringType()),\n                        'resolve' => function () {\n                            return null;\n                        }\n                    ]\n                ]\n            ])\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $executionResult = graphql($schema, 'query Greeting {hello}');\n\n        $this->assertSame([\n            'errors' => [\n                [\n\n                    'message'   => 'Cannot return null for non-nullable field Greeting.hello.',\n                    'locations' => null,\n                    'path'      => ['hello'],\n                ]\n            ],\n            'data'   => null\n        ], $executionResult);\n    }\n}\n\nclass Special\n{\n    public $value;\n\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n}\n\nclass NotSpecial\n{\n    public $value;\n\n    public function __construct($value)\n    {\n        $this->value = $value;\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/ListTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass ListTest extends TestCase\n{\n    // EXECUTE: ACCEPTS ANY ITERABLE AS LIST VALUE\n\n    /**\n     * @param TypeInterface $testType\n     * @param mixed         $testData\n     * @param mixed         $expected\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function makeTest(TypeInterface $testType, $testData, $expected)\n    {\n        $dataType = newObjectType([\n            'name'   => 'DataType',\n            'fields' => function () use (&$dataType, $testType, $testData) {\n                return [\n                    'test' => [\n                        'type' => $testType\n                    ],\n                    'nest' => [\n                        'type'    => $dataType,\n                        'resolve' => function () use ($testData) {\n                            return [\n                                'test' => $testData\n                            ];\n                        }\n                    ]\n                ];\n            }\n        ]);\n\n        $source = '{ nest { test } }';\n\n        $schema = newSchema(['query' => $dataType]);\n\n\n        /** @var ExecutionResult $executionResult */\n        $result = execute($schema, parse($source));\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testAcceptAnArrayObjectAsListValue()\n    {\n        $this->makeTest(newList(stringType()),\n            new \\ArrayObject(['apple', 'banana', 'coconut']),\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => ['apple', 'banana', 'coconut']\n                    ]\n                ]\n            ]\n        );\n\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testAcceptsAGeneratorAsFunctionValue()\n    {\n        $this->makeTest(newList(stringType()),\n            function () {\n                yield 'one';\n                yield 2;\n                yield true;\n            },\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => ['one', '2', 'true']\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testDoesNotAcceptStringAsIterable()\n    {\n        $this->makeTest(newList(stringType()),\n            'Singluar',\n            [\n                'data'   => [\n                    'nest' => [\n                        'test' => null\n                    ]\n                ]\n                ,\n                'errors' => [\n                    [\n                        'message'   => 'Expected Array or Traversable, but did not find one for field DataType.test.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 10\n                            ]\n                        ],\n                        'path'      => ['nest', 'test']\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testArrayContainsValues()\n    {\n        $this->makeTest(newList(intType()),\n            [1, 2],\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => [1, 2]\n                    ]\n                ]\n            ]\n        );\n    }\n\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testArrayContainsNull()\n    {\n        $this->makeTest(newList(intType()),\n            [1, null, 2],\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => [1, null, 2]\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testArrayReturnsNull()\n    {\n        $this->makeTest(newList(intType()),\n            null,\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => null\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testPromiseContainsValues()\n    {\n        $this->makeTest(newList(intType()),\n            \\React\\Promise\\resolve([1, 2]),\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => [1, 2]\n                    ]\n                ]\n            ]\n        );\n    }\n\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testPromiseContainsNull()\n    {\n        $this->makeTest(newList(intType()),\n            \\React\\Promise\\resolve([1, null, 2]),\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => [1, null, 2]\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testPromiseReturnsNull()\n    {\n        $this->makeTest(newList(intType()),\n            \\React\\Promise\\resolve(null),\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => null\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testPromiseReject()\n    {\n        $this->makeTest(newList(intType()),\n            \\React\\Promise\\reject(new \\Exception('Bad')),\n            [\n                'data'   => [\n                    'nest' => [\n                        'test' => null\n                    ]\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Bad',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 10\n                            ]\n                        ],\n                        'path'      => ['nest', 'test']\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testArrayPromiseContainsValues()\n    {\n        $this->makeTest(newList(intType()),\n            [\n                \\React\\Promise\\resolve(1),\n                \\React\\Promise\\resolve(2)\n            ],\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => [1, 2]\n                    ]\n                ]\n            ]\n        );\n    }\n\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testArrayPromiseContainsNull()\n    {\n        $this->makeTest(newList(intType()),\n            [\n                \\React\\Promise\\resolve(1),\n                \\React\\Promise\\resolve(null),\n                \\React\\Promise\\resolve(2)\n            ],\n            [\n                'data' => [\n                    'nest' => [\n                        'test' => [1, null, 2]\n                    ]\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testArrayPromiseContainsReject()\n    {\n        $this->makeTest(newList(intType()),\n            [\n                \\React\\Promise\\resolve(1),\n                \\React\\Promise\\reject(new \\Exception('Bad')),\n                \\React\\Promise\\resolve(2)\n            ],\n            [\n                'data'   => [\n                    'nest' => [\n                        'test' => [1, null, 2]\n                    ]\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Bad',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 10\n                            ]\n                        ],\n                        'path'      => ['nest', 'test', 1]\n                    ]\n                ]\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/MutationTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse React\\Promise\\Promise;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass MutationTest extends TestCase\n{\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testSimpleMutation()\n    {\n        $schema = newSchema([\n            'mutation' =>\n                newObjectType([\n                    'name'   => 'M',\n                    'fields' => [\n                        'greeting' => [\n                            'type'    => stringType(),\n                            'resolve' => function ($source, $args, $context, $info) {\n                                return sprintf('Hello %s.', $args['name']);\n                            },\n                            'args'    => [\n                                'name' => [\n                                    'type' => stringType()\n                                ]\n                            ]\n                        ]\n                    ]\n                ])\n        ]);\n\n        $source = '\n        mutation M($name: String) {\n            greeting(name:$name)\n        }';\n\n        $executionResult = execute($schema, parse($source), '', null, ['name' => 'Han Solo']);\n\n        $expected = new ExecutionResult([\n            'greeting' => 'Hello Han Solo.'\n        ], []);\n\n        $this->assertEquals($expected, $executionResult);\n    }\n\n    // EXECUTE: HANDLES MUTATION EXECUTION ORDERING\n\n    /**\n     * Evaluates mutations serially\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testEvaluatesMutationsSerially()\n    {\n        $source = 'mutation M {\n          first: immediatelyChangeTheNumber(newNumber: 1) {\n            theNumber\n          },\n          second: promiseToChangeTheNumber(newNumber: 2) {\n            theNumber\n          },\n          third: immediatelyChangeTheNumber(newNumber: 3) {\n            theNumber\n          }\n          fourth: promiseToChangeTheNumber(newNumber: 4) {\n            theNumber\n          },\n          fifth: immediatelyChangeTheNumber(newNumber: 5) {\n            theNumber\n          }\n        }';\n\n        $result   = execute(rootSchema(), parse($source), new Root(6));\n        $expected = [\n            'data' => [\n                'first'  => [\n                    'theNumber' => 1\n                ],\n                'second' => [\n                    'theNumber' => 2\n                ],\n                'third'  => [\n                    'theNumber' => 3\n                ],\n                'fourth' => [\n                    'theNumber' => 4\n                ],\n                'fifth'  => [\n                    'theNumber' => 5\n                ]\n            ]\n        ];\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n\n    //evaluates mutations correctly in the presence of a failed mutation\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testEvaluatesMutationsCorrectlyInThePresenceOfAvailedMutation()\n    {\n        $source = 'mutation M {\n          first: immediatelyChangeTheNumber(newNumber: 1) {\n            theNumber\n          },\n          second: promiseToChangeTheNumber(newNumber: 2) {\n            theNumber\n          },\n          third: failToChangeTheNumber(newNumber: 3) {\n            theNumber\n          }\n          fourth: promiseToChangeTheNumber(newNumber: 4) {\n            theNumber\n          },\n          fifth: immediatelyChangeTheNumber(newNumber: 5) {\n            theNumber\n          }\n          sixth: promiseAndFailToChangeTheNumber(newNumber: 6) {\n            theNumber\n          }\n        }';\n\n        $result   = execute(rootSchema(), parse($source), new Root(6));\n        $expected = [\n            'data'   => [\n                'first'  => [\n                    'theNumber' => 1\n                ],\n                'second' => [\n                    'theNumber' => 2\n                ],\n                'third'  => null,\n                'fourth' => [\n                    'theNumber' => 4\n                ],\n                'fifth'  => [\n                    'theNumber' => 5\n                ],\n                'sixth'  => null\n            ],\n            'errors' => [\n                [\n                    'message'   => 'Cannot change the number',\n                    'locations' => null,\n                    'path'      => ['third']\n                ],\n                [\n                    'message'   => 'Cannot change the number',\n                    'locations' => null,\n                    'path'      => ['sixth']\n                ]\n            ]\n        ];\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n}\n\n\nclass NumberHolder\n{\n    /**\n     * @var int\n     */\n    public $theNumber;\n\n    /**\n     * NumberHolder constructor.\n     * @param int $originalNumber\n     */\n    public function __construct(int $originalNumber)\n    {\n        $this->theNumber = $originalNumber;\n    }\n}\n\nclass Root\n{\n    public $numberHolder;\n\n    /**\n     * Root constructor.\n     * @param int $originalNumber\n     */\n    public function __construct(int $originalNumber)\n    {\n        $this->numberHolder = new NumberHolder($originalNumber);\n    }\n\n    /**\n     * @param int $newNumber\n     * @return NumberHolder\n     */\n    public function immediatelyChangeTheNumber(int $newNumber)\n    {\n        $this->numberHolder->theNumber = $newNumber;\n        return $this->numberHolder;\n    }\n\n    /**\n     * @param int $newNumber\n     *\n     * @return Promise\n     */\n    public function promiseToChangeTheNumber(int $newNumber)\n    {\n        return new Promise(function (callable $resolve) use ($newNumber) {\n            return $resolve($this->immediatelyChangeTheNumber($newNumber));\n        });\n    }\n\n    /**\n     * @throws \\Exception\n     */\n    public function failToChangeTheNumber()\n    {\n        throw new ExecutionException('Cannot change the number');\n    }\n\n    /**\n     * @return Promise\n     */\n    public function promiseAndFailToChangeTheNumber()\n    {\n        return new Promise(function (callable $resolve, callable $reject) {\n            $reject(new ExecutionException(\"Cannot change the number\"));\n        });\n    }\n}\n\nfunction rootSchema(): Schema\n{\n    $numberHolderType = newObjectType([\n        'fields' => [\n            'theNumber' => ['type' => intType()],\n        ],\n        'name'   => 'NumberHolder',\n    ]);\n\n    $schema = newSchema([\n        'query'    => newObjectType([\n            'fields' => [\n                'numberHolder' => ['type' => $numberHolderType],\n            ],\n            'name'   => 'Query',\n        ]),\n        'mutation' => newObjectType([\n            'fields' => [\n                'immediatelyChangeTheNumber'      => [\n                    'type'    => $numberHolderType,\n                    'args'    => ['newNumber' => ['type' => intType()]],\n                    'resolve' => function (Root $obj, $args) {\n                        return $obj->immediatelyChangeTheNumber($args['newNumber']);\n                    }\n                ],\n                'promiseToChangeTheNumber'        => [\n                    'type'    => $numberHolderType,\n                    'args'    => ['newNumber' => ['type' => intType()]],\n                    'resolve' => function (Root $obj, $args) {\n                        return $obj->promiseToChangeTheNumber($args['newNumber']);\n                    }\n                ],\n                'failToChangeTheNumber'           => [\n                    'type'    => $numberHolderType,\n                    'args'    => ['newNumber' => ['type' => intType()]],\n                    'resolve' => function (Root $obj) {\n                        return $obj->failToChangeTheNumber();\n                    }\n                ],\n                'promiseAndFailToChangeTheNumber' => [\n                    'type'    => $numberHolderType,\n                    'args'    => ['newNumber' => ['type' => intType()]],\n                    'resolve' => function (Root $obj) {\n                        return $obj->promiseAndFailToChangeTheNumber();\n                    }\n                ]\n            ],\n            'name'   => 'Mutation',\n        ])\n    ]);\n\n    return $schema;\n}\n"
  },
  {
    "path": "tests/Functional/Execution/NonNullTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass NonNullTest extends TestCase\n{\n    private $schemaWithNonNullArg;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithNonNullArg = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'withNonNullArg' => [\n                        'type'    => stringType(),\n                        'args'    => [\n                            'cannotBeNull' => [\n                                'type' => newNonNull(stringType()),\n                            ],\n                        ],\n                        'resolve' => function ($_, $args): ?string {\n                            return isset($args['cannotBeNull']) && \\is_string($args['cannotBeNull'])\n                                ? \"Passed: {$args['cannotBeNull']}\"\n                                : null;\n                        }\n                    ],\n                ],\n            ])\n        ]);\n    }\n\n    // Handles non-null argument\n\n    public function testSucceedsWhenPassedNonNullLiteralValue()\n    {\n        $this->assertQueryResult(\n            'query {\n              withNonNullArg (cannotBeNull: \"literal value\")\n            }',\n            [\n                'data' => [\n                    'withNonNullArg' => 'Passed: literal value'\n                ]\n            ]\n        );\n    }\n\n    public function testSucceedsWhenPassedNonNullVariableValue()\n    {\n        $this->assertQueryResult(\n            'query ($testVar: String!) {\n              withNonNullArg (cannotBeNull: $testVar)\n            }',\n            [\n                'data' => [\n                    'withNonNullArg' => 'Passed: variable value'\n                ]\n            ],\n            ['testVar' => 'variable value']\n        );\n    }\n\n    public function testSucceedsWhenMissingVariableHasDefaultValue()\n    {\n        $this->assertQueryResult(\n            'query ($testVar: String = \"default value\") {\n              withNonNullArg (cannotBeNull: $testVar)\n            }',\n            [\n                'data' => [\n                    'withNonNullArg' => 'Passed: default value'\n                ]\n            ],\n            // Intentionally missing variable\n            []\n        );\n    }\n\n    public function testFieldErrorWhenMissingNonNullArg()\n    {\n        // Note: validation should identify this issue first (missing args rule)\n        // however execution should still protect against this.\n\n        $this->assertQueryResult(\n            'query {\n              withNonNullArg\n            }',\n            [\n                'data'   => [\n                    'withNonNullArg' => null,\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"cannotBeNull\" of required type \"String!\" was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 2,\n                                'column' => 15,\n                            ],\n                        ],\n                        'path'      => ['withNonNullArg'],\n                    ],\n                ],\n            ]\n        );\n    }\n\n    public function testFieldErrorWhenNonNullArgProvidedNull()\n    {\n        // Note: validation should identify this issue first (values of correct\n        // type rule) however execution should still protect against this.\n\n        $this->assertQueryResult(\n            'query {\n              withNonNullArg(cannotBeNull: null)\n            }',\n            [\n                'data'   => [\n                    'withNonNullArg' => null,\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"cannotBeNull\" of non-null type \"String!\" must not be null.',\n                        'locations' => [\n                            [\n                                'line'   => 2,\n                                'column' => 44,\n                            ],\n                        ],\n                        'path'      => ['withNonNullArg'],\n                    ],\n                ],\n            ]\n        );\n    }\n\n    public function testFieldErrorWhenNonNullArgNotProvidedVariableValue()\n    {\n        // Note: validation should identify this issue first (variables in allowed\n        // position rule) however execution should still protect against this.\n\n        $this->assertQueryResult(\n            'query ($testVar: String) {\n              withNonNullArg(cannotBeNull: $testVar)\n            }',\n            [\n                'data'   => [\n                    'withNonNullArg' => null,\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"cannotBeNull\" of required type \"String!\" was provided the variable '\n                            . '\"$testVar\" which was not provided a runtime value.',\n                        'locations' => [\n                            [\n                                'line'   => 2,\n                                'column' => 44,\n                            ],\n                        ],\n                        'path'      => ['withNonNullArg'],\n                    ],\n                ],\n            ],\n            // Intentionally missing variable\n            []\n        );\n    }\n\n    public function testFieldErrorWhenNonNullArgProvidedVariableWithExplicitNullValue()\n    {\n        $this->assertQueryResult(\n            'query ($testVar: String = \"default value\") {\n              withNonNullArg (cannotBeNull: $testVar)\n            }',\n            [\n                'data'   => [\n                    'withNonNullArg' => null,\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"cannotBeNull\" of non-null type \"String!\" must not be null.',\n                        'locations' => [\n                            [\n                                'line'   => 2,\n                                'column' => 45,\n                            ],\n                        ],\n                        'path'      => ['withNonNullArg'],\n                    ],\n                ],\n            ],\n            ['testVar' => null]\n        );\n    }\n\n    /**\n     * @param string $query\n     * @param array  $expected\n     * @param array  $variables\n     */\n    private function assertQueryResult(string $query, array $expected, array $variables = []): void\n    {\n        $this->assertQueryResultWithSchema($this->schemaWithNonNullArg, $query, $expected, null, null, $variables);\n    }\n}"
  },
  {
    "path": "tests/Functional/Execution/ResolveTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\graphql;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass ResolveTest extends TestCase\n{\n\n    protected function createTestSchema($testField)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'test' => $testField\n                ]\n            ])\n        ]);\n    }\n\n    // Execute: resolve function\n\n    /**\n     * Default function accesses properties\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testDefaultFunctionAccessProperties()\n    {\n        $schema = $this->createTestSchema(['type' => stringType()]);\n\n        $source = ['test' => 'testValue'];\n\n        $result = graphql($schema, '{ test }', $source);\n\n        $this->assertEquals([\n            'data' => [\n                'test' => 'testValue'\n            ]\n        ], $result);\n    }\n\n    /**\n     * Default function calls methods\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testDefaultFunctionCallsMethods()\n    {\n        $schema = $this->createTestSchema(['type' => stringType()]);\n\n        $source = [\n            'test' => function () {\n                return 'secretValue';\n            }\n        ];\n\n        $result = graphql($schema, '{ test }', $source);\n\n        $this->assertEquals([\n            'data' => [\n                'test' => 'secretValue'\n            ]\n        ], $result);\n    }\n\n    /**\n     * Default function passes args and context\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testDefaultFunctionPassesArgsAndContext()\n    {\n        $schema = $this->createTestSchema([\n            'type' => intType(),\n            'args' => ['addend1' => ['type' => intType()]],\n        ]);\n\n        $source = new class(700)\n        {\n            private $num;\n\n            public function __construct($num)\n            {\n                $this->num = $num;\n            }\n\n            public function test($source, $args, $context)\n            {\n                return $this->num + $args['addend1'] + $context['addend2'];\n            }\n        };\n\n        $result = graphql($schema, '{ test(addend1: 80) }', $source, ['addend2' => 9]);\n\n        $this->assertEquals([\n            'data' => [\n                'test' => 789\n            ]\n        ], $result);\n    }\n\n    /**\n     * Uses provided resolve function\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testUsesProvidedResolveFunction()\n    {\n        $schema = $this->createTestSchema([\n            'type'    => stringType(),\n            'args'    => [\n                'aStr' => ['type' => stringType()],\n                'aInt' => ['type' => intType()],\n            ],\n            'resolve' => function ($source, $args) {\n                return json_encode([$source, $args]);\n            }\n        ]);\n\n        $result = graphql($schema, '{ test }');\n\n        $this->assertEquals([\n            'data' => [\n                'test' => '[null,[]]'\n            ]\n        ], $result);\n\n        $this->assertEquals([\n            'data' => [\n                'test' => '[\"Source!\",[]]'\n            ]\n        ], graphql($schema, '{ test }', 'Source!'));\n\n\n        $this->assertEquals([\n            'data' => [\n                'test' => '[\"Source!\",{\"aStr\":\"String!\"}]'\n            ]\n        ], graphql($schema, '{ test(aStr:\"String!\") }', 'Source!'));\n\n\n        $this->assertEquals([\n            'data' => [\n                'test' => '[\"Source!\",{\"aStr\":\"String!\",\"aInt\":-123}]'\n            ]\n        ], graphql($schema, '{ test(aInt: -123, aStr: \"String!\") }', 'Source!'));\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/SchemaTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\idType;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\n\nclass SchemaTest extends TestCase\n{\n    // Execute: Handles execution with a complex schema\n\n    /**\n     * Executes using a schema\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvalidTypeException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testExecutesUsingASchema()\n    {\n        $BlogImage = newObjectType([\n            'name'   => 'Image',\n            'fields' => [\n                'url'    => ['type' => stringType()],\n                'height' => ['type' => intType()],\n                'width'  => ['type' => intType()],\n            ]\n        ]);\n\n        $BlogAuthor = newObjectType([\n            'name'   => 'Author',\n            'fields' => function () use (&$BlogArticle, &$BlogImage) {\n                return [\n                    'id'            => ['type' => stringType()],\n                    'name'          => ['type' => stringType()],\n                    'pic'           => [\n                        'type'    => $BlogImage,\n                        'args'    => [\n                            'width'  => ['type' => intType()],\n                            'height' => ['type' => intType()]\n                        ],\n                        'resolve' => function ($root, $args) {\n                            ['width' => $width, 'height' => $height] = $args;\n                            return $root['pic']($width, $height);\n                        }\n                    ],\n                    'recentArticle' => ['type' => $BlogArticle],\n\n                ];\n            }\n        ]);\n\n        $BlogArticle = newObjectType([\n            'name'   => 'Article',\n            'fields' => [\n                'id'          => ['type' => newNonNull(stringType())],\n                'isPublished' => ['type' => booleanType()],\n                'author'      => ['type' => $BlogAuthor],\n                'title'       => ['type' => stringType()],\n                'body'        => ['type' => stringType()],\n                'keywords'    => ['type' => newList(stringType())],\n            ]\n        ]);\n\n        $Query = newObjectType([\n            'name'   => 'Query',\n            'fields' => [\n                'article' => [\n                    'type'    => $BlogArticle,\n                    'args'    => [\n                        'id' => ['type' => idType()]\n                    ],\n                    'resolve' => function ($root, $args) use (&$article) {\n                        return $article($args['id']);\n                    }\n                ],\n                'feed'    => [\n                    'type'    => newList($BlogArticle),\n                    'resolve' => function ($root, $args) use (&$article) {\n                        return [\n                            $article(1),\n                            $article(2),\n                            $article(3),\n                            $article(4),\n                            $article(5),\n                            $article(6),\n                            $article(7),\n                            $article(8),\n                            $article(9),\n                            $article(10),\n                        ];\n                    }\n                ]\n            ]\n        ]);\n\n        $article = function ($id) use (&$johnSmith) {\n            return [\n                'id'          => $id,\n                'isPublished' => 'true',\n                'author'      => $johnSmith,\n                'title'       => 'My Article ' . $id,\n                'body'        => 'This is a post',\n                'hidden'      => 'This data is not exposed in the schema',\n                'keywords'    => ['foo', 'bar', 1, true, null],\n            ];\n        };\n\n        $getPic = function ($uid, $width, $height) {\n            return [\n                'url'    => \"cdn://${uid}\",\n                'width'  => $width,\n                'height' => $height,\n            ];\n        };\n\n        $johnSmith = function () use (&$article, &$getPic) {\n            return [\n                'id'            => 123,\n                'name'          => 'John Smith',\n                'pic'           => function ($width, $height) use (&$getPic) {\n                    return $getPic(123, $width, $height);\n                },\n                'recentArticle' => $article(1)\n            ];\n        };\n\n        $BlogSchema = newSchema([\n            'query' => $Query\n        ]);\n\n        $request = '\n          {\n            feed {\n              id,\n              title\n            },\n            article(id: \"1\") {\n              ...articleFields,\n              author {\n                id,\n                name,\n                pic(width: 640, height: 480) {\n                  url,\n                  width,\n                  height\n                },\n                recentArticle {\n                  ...articleFields,\n                  keywords\n                }\n              }\n            }\n          }\n    \n          fragment articleFields on Article {\n            id,\n            isPublished,\n            title,\n            body,\n            hidden,\n            notdefined\n          }\n        ';\n\n        $result = execute($BlogSchema, parse($request));\n\n        $this->assertEquals([\n            'data' => [\n                'feed'    => [\n                    [\n                        'id'    => '1',\n                        'title' => 'My Article 1',\n                    ],\n                    [\n                        'id'    => '2',\n                        'title' => 'My Article 2',\n                    ],\n                    [\n                        'id'    => '3',\n                        'title' => 'My Article 3',\n                    ],\n                    [\n                        'id'    => '4',\n                        'title' => 'My Article 4',\n                    ],\n                    [\n                        'id'    => '5',\n                        'title' => 'My Article 5',\n                    ],\n                    [\n                        'id'    => '6',\n                        'title' => 'My Article 6',\n                    ],\n                    [\n                        'id'    => '7',\n                        'title' => 'My Article 7',\n                    ],\n                    [\n                        'id'    => '8',\n                        'title' => 'My Article 8',\n                    ],\n                    [\n                        'id'    => '9',\n                        'title' => 'My Article 9',\n                    ],\n                    [\n                        'id'    => '10',\n                        'title' => 'My Article 10',\n                    ],\n                ],\n                'article' => [\n                    'id'          => '1',\n                    'isPublished' => true,\n                    'title'       => 'My Article 1',\n                    'body'        => 'This is a post',\n                    'author'      => [\n                        'id'            => '123',\n                        'name'          => 'John Smith',\n                        'pic'           => [\n                            'url'    => 'cdn://123',\n                            'width'  => 640,\n                            'height' => 480,\n                        ],\n                        'recentArticle' => [\n                            'id'          => '1',\n                            'isPublished' => true,\n                            'title'       => 'My Article 1',\n                            'body'        => 'This is a post',\n                            'keywords'    => ['foo', 'bar', '1', 'true', null],\n                        ],\n                    ]\n                ]\n            ]\n        ], $result->toArray());\n    }\n\n\n    public function testExecuteUsingASchemaWithCustomScalarType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $dateType = newScalarType([\n            'name'         => 'Date',\n            'serialize'    => function (\\DateTime $value) {\n                /** @noinspection PhpUndefinedMethodInspection */\n                return $value->format('d.m.Y');\n            },\n            'parseValue'   => function ($value) {\n                return new \\DateTime($value);\n            },\n            'parseLiteral' => function ($node) {\n                /** @noinspection PhpUndefinedMethodInspection */\n                return new \\DateTime($node->getValue(), new \\DateTimeZone('Europe/Helsinki'));\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestInputObject = newInputObjectType([\n            'name'   => 'TestInputObject',\n            'fields' => [\n                'c' => ['type' => newNonNull(stringType())],\n                'd' => ['type' => $dateType]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $blogArticle = newObjectType([\n            'name'   => 'Article',\n            'fields' => [\n                'id'        => ['type' => newNonNull(stringType())],\n                'title'     => ['type' => stringType()],\n                'body'      => ['type' => stringType()],\n                'createdAt' => ['type' => $dateType],\n            ]\n        ]);\n\n        $article = function ($id, $date) {\n            return [\n                'id'        => $id,\n                'title'     => 'My Article ' . $id,\n                'body'      => 'This is a post',\n                'createdAt' => $date,\n            ];\n        };\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestType = newObjectType([\n            'name'   => 'TestType',\n            'fields' => [\n                'articles' => [\n                    'type'    => newList($blogArticle),\n                    'args'    => [\n                        'input' => ['type' => $TestInputObject]\n                    ],\n                    'resolve' => function ($root, $args) use (&$article) {\n                        return [\n                            $article(1, new \\DateTime('2018-04-30')),\n                            $article(2, new \\DateTime('2018-05-01'))\n                        ];\n                    }\n                ]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => $TestType\n        ]);\n\n        $query = '{\n            articles(input: {c:\"foo\",d: \"2018-01-01\"}) {\n                id\n                title\n                createdAt\n            }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse($query));\n\n        $this->assertEquals([\n            'data' => [\n                'articles' => [\n                    [\n                        'id'        => '1',\n                        'title'     => 'My Article 1',\n                        'createdAt' => \"30.04.2018\"\n                    ],\n                    [\n                        'id'        => '2',\n                        'title'     => 'My Article 2',\n                        'createdAt' => \"01.05.2018\"\n                    ],\n                ]\n            ]\n        ], $result->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/UnionInterfaceTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\n\nclass UnionInterfaceTest extends TestCase\n{\n    private $schema;\n\n    private $garfield;\n\n    private $odie;\n\n    private $liz;\n\n    private $john;\n\n    public function setUp()\n    {\n        parent::setUp();\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $NamedType = newInterfaceType([\n            'name'   => 'Named',\n            'fields' => [\n                'name' => ['type' => stringType()]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $DogType = newObjectType([\n            'name'       => 'Dog',\n            'interfaces' => [$NamedType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'woofs' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Dog;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $CatType = newObjectType([\n            'name'       => 'Cat',\n            'interfaces' => [$NamedType],\n            'fields'     => [\n                'name'  => ['type' => stringType()],\n                'meows' => ['type' => booleanType()],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Cat;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PetType = newUnionType([\n            'name'        => 'Pet',\n            'types'       => [$DogType, $CatType],\n            'resolveType' => function ($result, $context, $info) use ($DogType, $CatType) {\n                if ($result instanceof Dog) {\n                    return $DogType;\n                }\n\n                if ($result instanceof Cat) {\n                    return $CatType;\n                }\n\n                return null;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PersonType = newObjectType([\n            'name'       => 'Person',\n            'interfaces' => [$NamedType],\n            'fields'     => [\n                'name'    => ['type' => stringType()],\n                'pets'    => ['type' => newList($PetType)],\n                'friends' => ['type' => newList($NamedType)],\n            ],\n            'isTypeOf'   => function ($obj) {\n                return $obj instanceof Person;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => $PersonType\n        ]);\n\n        $this->garfield = new Cat('Garfield', false);\n        $this->odie     = new Dog('Odie', true);\n        $this->liz      = new Person('Liz');\n        $this->john     = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]);\n\n\n        $this->schema = $schema;\n    }\n\n    //EXECUTE: UNION AND INTERSECTION TYPES\n\n    /**\n     * can introspect on union and intersection types\n     */\n    public function testCanIntrospectOnUnionAndIntersectionTypes()\n    {\n        $source = '\n        {\n          Named: __type(name: \"Named\") {\n            kind\n            name\n            fields { name }\n            interfaces { name }\n            possibleTypes { name }\n            enumValues { name }\n            inputFields { name }\n          }\n          \n          Pet: __type(name: \"Pet\") {\n            kind\n            name\n            fields { name }\n            interfaces { name }\n            possibleTypes { name }\n            enumValues { name }\n            inputFields { name }\n          }\n        }';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($this->schema, parse($source));\n\n        $this->assertSame([\n            'Named' => [\n                'kind'          => 'INTERFACE',\n                'name'          => 'Named',\n                'fields'        => [\n                    ['name' => 'name']\n                ],\n                'interfaces'    => null,\n                'possibleTypes' => [\n                    ['name' => 'Person'],\n                    ['name' => 'Dog'],\n                    ['name' => 'Cat']\n                ],\n                'enumValues'    => null,\n                'inputFields'   => null\n            ],\n            'Pet'   => [\n                'kind'          => 'UNION',\n                'name'          => 'Pet',\n                'fields'        => null,\n                'interfaces'    => null,\n                'possibleTypes' => [\n                    ['name' => 'Dog'],\n                    ['name' => 'Cat']\n                ],\n                'enumValues'    => null,\n                'inputFields'   => null\n            ]\n        ], $result->getData());\n    }\n\n    /**\n     * executes using union types\n     */\n    public function testExecutesUsingUnionTypes()\n    {\n        $source = '\n        {\n          __typename\n          name\n          pets {\n            __typename\n            name\n            woofs\n            meows\n          }\n        }';\n\n        $expected = [\n            '__typename' => 'Person',\n            'name'       => 'John',\n            'pets'       => [\n                ['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],\n                ['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],\n            ]\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($this->schema, parse($source), $this->john);\n\n        $this->assertEquals($expected, $result->getData());\n    }\n\n    /**\n     * executes union types with inline fragments\n     */\n    public function testExecutesUnionTypesWithInlineFragments()\n    {\n        $source = '\n        {\n          __typename\n          name\n          pets {\n            __typename\n            ... on Dog {\n              name\n              woofs\n            }\n            ... on Cat {\n              name\n              meows\n            }\n          }\n        }';\n\n        $expected = [\n            '__typename' => 'Person',\n            'name'       => 'John',\n            'pets'       => [\n                ['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],\n                ['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],\n            ]\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($this->schema, parse($source), $this->john);\n\n        $this->assertSame($expected, $result->getData());\n    }\n\n    /**\n     * executes using interface types\n     */\n    public function testExecutesUsingInterfaceTypes()\n    {\n        $source = '\n        {\n          __typename\n          name\n          friends {\n            __typename\n            name\n            woofs\n            meows\n          }\n        }';\n\n        $expected = [\n            '__typename' => 'Person',\n            'name'       => 'John',\n            'friends'    => [\n                ['__typename' => 'Person', 'name' => 'Liz'],\n                ['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],\n            ]\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($this->schema, parse($source), $this->john);\n\n        $this->assertSame($expected, $result->getData());\n    }\n\n    /**\n     * executes union types with inline fragments\n     */\n    public function testExecutesUnionTypesWithInlineFragmentsTwo()\n    {\n        $source = '\n        {\n          __typename\n          name\n          friends {\n            __typename\n            name\n            ... on Dog {\n              woofs\n            }\n            ... on Cat {\n              meows\n            }\n          }\n        }';\n\n        $expected = [\n            '__typename' => 'Person',\n            'name'       => 'John',\n            'friends'    => [\n                ['__typename' => 'Person', 'name' => 'Liz'],\n                ['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true],\n            ]\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($this->schema, parse($source), $this->john);\n\n        $this->assertSame($expected, $result->getData());\n    }\n\n    /**\n     * allows fragment conditions to be abstract types\n     */\n    public function testAllowsFragmentConditionsToBeAbstractTypes()\n    {\n        $source = '\n        {\n          __typename\n          name\n          pets { ...PetFields }\n          friends { ...FriendFields }\n        }\n  \n        fragment PetFields on Pet {\n          __typename\n          ... on Dog {\n            name\n            woofs\n          }\n          ... on Cat {\n            name\n            meows\n          }\n        }\n  \n        fragment FriendFields on Named {\n          __typename\n          name\n          ... on Dog {\n            woofs\n          }\n          ... on Cat {\n            meows\n          }\n        }';\n\n        $expected = [\n            '__typename' => 'Person',\n            'name'       => 'John',\n            'pets'       => [\n                ['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],\n                ['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]\n            ],\n            'friends'    => [\n                ['__typename' => 'Person', 'name' => 'Liz'],\n                ['__typename' => 'Dog', 'name' => 'Odie', 'woofs' => true]\n            ]\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($this->schema, parse($source), $this->john);\n\n        $this->assertSame($expected, $result->getData());\n    }\n\n    /**\n     * gets execution info in resolver\n     */\n    public function testGetsExecutionInfoInResolver()\n    {\n\n        $encounteredContext   = null;\n        $encounteredSchema    = null;\n        $encounteredRootValue = null;\n        $PersonType2          = null;\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $NamedType2 = newInterfaceType([\n            'name'        => 'Named',\n            'fields'      => [\n                'name' => ['type' => stringType()]\n            ],\n            'resolveType' => function ($obj, $context, ResolveInfo $info) use (\n                &$encounteredContext,\n                &$encounteredSchema,\n                &$encounteredRootValue,\n                &$PersonType2\n            ) {\n                $encounteredContext   = $context;\n                $encounteredSchema    = $info->getSchema();\n                $encounteredRootValue = $info->getRootValue();\n                return $PersonType2;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $PersonType2 = newObjectType([\n            'name'       => 'Person',\n            'interfaces' => [$NamedType2],\n            'fields'     => [\n                'name'    => ['type' => stringType()],\n                'friends' => ['type' => newList($NamedType2)],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema2 = newSchema([\n            'query' => $PersonType2\n        ]);\n\n        $john2 = new Person('John', [], [$this->liz]);\n\n        $context = ['authToken' => '123abc'];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema2, parse('{ name, friends { name } }'), $john2, $context);\n\n        $this->assertSame(\n            ['name' => 'John', 'friends' => [['name' => 'Liz']]],\n            $result->getData()\n        );\n\n        $this->assertSame($context, $encounteredContext);\n        $this->assertSame($schema2, $encounteredSchema);\n        $this->assertSame($john2, $encounteredRootValue);\n    }\n}\n\n"
  },
  {
    "path": "tests/Functional/Execution/ValuesResolverTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ValuesResolver;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentsAwareInterface;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass ValuesResolverTest extends TestCase\n{\n    /**\n     * @var ValuesResolver\n     */\n    private $valuesResolver;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        $this->valuesResolver = new ValuesResolver();\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvalidTypeException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Execution\\ExecutionException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     */\n    public function testCoerceArgumentValues()\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Greeting',\n                'fields' => [\n                    'greeting' => [\n                        'type' => stringType(),\n                        'args' => [\n                            'name' => [\n                                'type' => stringType(),\n                            ],\n                        ],\n                    ],\n                ],\n            ]),\n        ]);\n\n        $documentNode = parse('query Hello($name: String) { Greeting(name: $name) }');\n        $operation    = $documentNode->getDefinitions()[0];\n        $node         = $operation->getSelectionSet()->getSelections()[0];\n        $definition   = $schema->getQueryType()->getFields()['greeting'];\n\n        $context = new ExecutionContext(\n            $schema, [], null, null, ['name' => 'Han Solo'], null, $operation, []\n        );\n\n        $args = $this->valuesResolver->coerceArgumentValues($definition, $node, $context->getVariableValues());\n\n        $this->assertSame(['name' => 'Han Solo'], $args);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\GraphQLException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     * @throws \\Digia\\GraphQL\\Util\\ConversionException\n     */\n    public function testCoerceVariableValues(): void\n    {\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'nonNullBoolean',\n                'fields' => [\n                    'greeting' => [\n                        'type' => stringType(),\n                        'args' => [\n                            'shout' => [\n                                'type' => newNonNull(booleanType()),\n                            ],\n                        ],\n                    ],\n                ],\n            ]),\n        ]);\n\n        $documentNode = parse('\n            query ($shout: Boolean!) {\n                nonNullBoolean(shout: $shout)\n            }\n         ');\n\n        /** @var OperationDefinitionNode $operation */\n        $operation           = $documentNode->getDefinitions()[0];\n        $variableDefinitions = $operation->getVariableDefinitions();\n\n        // Try with true and false and null (null should give errors, the rest shouldn't)\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, ['shout' => true]);\n        $this->assertSame(['shout' => true], $coercedValue->getValue());\n        $this->assertFalse($coercedValue->hasErrors());\n\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, ['shout' => false]);\n        $this->assertSame(['shout' => false], $coercedValue->getValue());\n        $this->assertFalse($coercedValue->hasErrors());\n\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, ['shout' => null]);\n        $this->assertEquals([], $coercedValue->getValue());\n        $this->assertTrue($coercedValue->hasErrors());\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\GraphQLException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Language\\SyntaxErrorException\n     * @throws \\Digia\\GraphQL\\Util\\ConversionException\n     */\n    public function testCoerceValuesForInputObjectTypes(): void\n    {\n        // Test input object types\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'inputObjectField' => [\n                        'type' => booleanType(),\n                        'args' => [\n                            'inputObject' => [\n                                'type' => newInputObjectType([\n                                        'name'   => 'InputObject',\n                                        'fields' => [\n                                            'a' => ['type' => stringType()],\n                                            'b' => ['type' => newNonNull(stringType())]\n                                        ]\n                                    ]\n                                )\n                            ],\n                        ],\n                    ],\n                ],\n            ]),\n        ]);\n\n        $documentNode = parse('\n            query ($inputObject: InputObject!) {\n                inputObjectField(inputObject: $inputObject)\n            }\n         ');\n\n        /** @var OperationDefinitionNode $operation */\n        $operation           = $documentNode->getDefinitions()[0];\n        $variableDefinitions = $operation->getVariableDefinitions();\n\n        // Test with a missing non-null string\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, [\n            'inputObject' => [\n                'a' => 'some string'\n            ]\n        ]);\n\n        $this->assertTrue($coercedValue->hasErrors());\n        $this->assertEquals('Variable \"$inputObject\" got invalid value {\"a\":\"some string\"}; Field value.b of required type String! was not provided.',\n            $coercedValue->getErrors()[0]->getMessage());\n\n        // Test again with all variables, no errors expected\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, [\n            'inputObject' => [\n                'a' => 'some string',\n                'b' => 'some other required string',\n            ]\n        ]);\n\n        $this->assertFalse($coercedValue->hasErrors());\n\n        // Test with non-nullable boolean input fields\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'inputObjectField' => [\n                        'type' => booleanType(),\n                        'args' => [\n                            'inputObject' => [\n                                'type' => newInputObjectType([\n                                        'name'   => 'InputObject',\n                                        'fields' => [\n                                            'a' => ['type' => booleanType()],\n                                            'b' => ['type' => newNonNull(booleanType())]\n                                        ]\n                                    ]\n                                )\n                            ],\n                        ],\n                    ],\n                ],\n            ]),\n        ]);\n\n        $documentNode = parse('\n            query ($inputObject: InputObject!) {\n                inputObjectField(inputObject: $inputObject)\n            }\n         ');\n\n        /** @var OperationDefinitionNode $operation */\n        $operation           = $documentNode->getDefinitions()[0];\n        $variableDefinitions = $operation->getVariableDefinitions();\n\n        // Test with a missing non-null string\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, [\n            'inputObject' => [\n                'a' => true\n            ]\n        ]);\n\n        $this->assertTrue($coercedValue->hasErrors());\n        $this->assertEquals('Variable \"$inputObject\" got invalid value {\"a\":true}; Field value.b of required type Boolean! was not provided.',\n            $coercedValue->getErrors()[0]->getMessage());\n\n        // Test again with all fields present, all booleans true\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, [\n            'inputObject' => [\n                'a' => true,\n                'b' => true,\n            ]\n        ]);\n\n        $this->assertFalse($coercedValue->hasErrors());\n\n        // Test again with all fields present, all booleans false (this has been problematic before)\n        $coercedValue = $this->valuesResolver->coerceVariableValues($schema, $variableDefinitions, [\n            'inputObject' => [\n                'a' => false,\n                'b' => false,\n            ]\n        ]);\n\n        $this->assertFalse($coercedValue->hasErrors());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/VariablesTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Language\\Node\\ValueAwareInterface;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Test\\jsonEncode;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\n\n/**\n * Class VariablesTest\n * @package Digia\\GraphQL\\Test\\Functional\\Execution\n */\nclass VariablesTest extends TestCase\n{\n    private $schema;\n\n\n    /**\n     * @noinspection PhpDocMissingThrowsInspection\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestComplexScalar = newScalarType([\n            'name'         => 'ComplexScalar',\n            'serialize'    => function ($value) {\n                if ($value === 'DeserializedValue') {\n                    return 'SerializedValue';\n                }\n                return null;\n            },\n            'parseValue'   => function ($value) {\n                if ($value === 'SerializedValue') {\n                    return 'DeserializedValue';\n                }\n                return null;\n            },\n            'parseLiteral' => function (ValueAwareInterface $ast) {\n                if ($ast->getValue() === 'SerializedValue') {\n                    return 'DeserializedValue';\n                }\n                return null;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestInputObject = newInputObjectType([\n            'name'   => 'TestInputObject',\n            'fields' => [\n                'a' => ['type' => stringType()],\n                'b' => ['type' => newList(stringType())],\n                'c' => ['type' => newNonNull(stringType())],\n                'd' => ['type' => $TestComplexScalar]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestNestedInputObject = newInputObjectType([\n            'name'   => 'TestNestedInputObject',\n            'fields' => [\n                'na' => ['type' => newNonNull($TestInputObject)],\n                'nb' => ['type' => newNonNull(stringType())]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestType = newObjectType([\n            'name'   => 'TestType',\n            'fields' => [\n                'fieldWithObjectInput'                                   => $this->fieldWithInputArg(['type' => $TestInputObject]),\n                'fieldWithNullableStringInput'                           => $this->fieldWithInputArg(['type' => stringType()]),\n                'fieldWithNonNullableStringInput'                        => $this->fieldWithInputArg([\n                    'type' => newNonNull(stringType())\n                ]),\n                'fieldWithDefaultArgumentValue'                          => $this->fieldWithInputArg([\n                    'type'         => stringType(),\n                    'defaultValue' => 'Hello World'\n                ]),\n                'fieldWithNonNullableStringInputAndDefaultArgumentValue' => $this->fieldWithInputArg([\n                    'type'         => newNonNull(stringType()),\n                    'defaultValue' => 'Hello World'\n                ]),\n                'fieldWithNestedInputObject'                             => $this->fieldWithInputArg([\n                    'type'         => $TestNestedInputObject,\n                    'defaultValue' => 'Hello World'\n                ]),\n                'list'                                                   => $this->fieldWithInputArg([\n                    'type' => newList(stringType())\n                ]),\n                'nnList'                                                 => $this->fieldWithInputArg([\n                    'type' => newNonNull(newList(stringType())),\n                ]),\n                'listNN'                                                 => $this->fieldWithInputArg([\n                    'type' => newList(newNonNull(stringType())),\n                ]),\n                'nnListNN'                                               => $this->fieldWithInputArg([\n                    'type' => newNonNull(newList(newNonNull(stringType()))),\n                ]),\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schema = newSchema([\n            'query' => $TestType\n        ]);\n    }\n\n    /**\n     * @param array $inputArg\n     * @return array\n     */\n    function fieldWithInputArg(array $inputArg): array\n    {\n        return [\n            'type'    => stringType(),\n            'args'    => [\n                'input' => $inputArg\n            ],\n            'resolve' => function ($_, $args) {\n                return array_key_exists('input', $args) ? jsonEncode($args['input']) : null;\n            }\n        ];\n    }\n\n    // Execute: Handles inputs\n\n    // Handles objects and nullability\n\n    public function testExecutesWithComplexInput()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithObjectInput(input: {a: \"foo\", b: [\"bar\"], c: \"baz\"})\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":\"foo\",\"b\":[\"bar\"],\"c\":\"baz\"}'\n                ]\n            ]\n        );\n    }\n\n    public function testVariableNotProvided()\n    {\n        $this->assertQueryResult(\n            'query q($input: String) {\n              fieldWithNullableStringInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => null\n                ]\n            ],\n            // Intentionally missing variable values.\n            []\n        );\n    }\n\n    public function testVariableWithExplicitNullValue()\n    {\n        $this->assertQueryResult(\n            'query q($input: String) {\n              fieldWithNullableStringInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => 'null',\n                ]\n            ],\n            ['input' => null]\n        );\n    }\n\n    public function testUsesDefaultValueWhenValueNotProvided()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject = {a: \"foo\", b: [\"bar\"], c: \"baz\"}) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":\"foo\",\"b\":[\"bar\"],\"c\":\"baz\"}',\n                ]\n            ]\n        );\n    }\n\n    public function testDoesNotUseDefaultValueWhenValueProvided()\n    {\n        $this->assertQueryResult(\n            'query ($input: String = \"Default value\") {\n              fieldWithNullableStringInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => '\"Variable value\"',\n                ]\n            ],\n            ['input' => 'Variable value']\n        );\n    }\n\n    public function testUsesExplicitNullValueInsteadOfDefaultValue()\n    {\n        $this->assertQueryResult(\n            'query ($input: String = \"Default value\") {\n              fieldWithNullableStringInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => 'null',\n                ]\n            ],\n            ['input' => null]\n        );\n    }\n\n    public function testUsesNullDefaultValueWhenValueNotProvided()\n    {\n        $this->assertQueryResult(\n            'query ($input: String = null) {\n              fieldWithNullableStringInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => 'null',\n                ]\n            ],\n            // Intentionally missing variable values.\n            []\n        );\n    }\n\n    public function testProperlyParsesSingleValueToList()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithObjectInput(input: {a: \"foo\", b: \"bar\", c: \"baz\"})\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":\"foo\",\"b\":[\"bar\"],\"c\":\"baz\"}'\n                ]\n            ]\n        );\n    }\n\n    public function testProperlyParsesNullValueToNull()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithObjectInput(input: {a: null, b: null, c: \"C\", d: null})\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":null,\"b\":null,\"c\":\"C\",\"d\":null}'\n                ]\n            ]\n        );\n    }\n\n    public function testProperlyParsesNullValueInList()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithObjectInput(input: {b: [\"A\",null,\"C\"], c: \"C\"})\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"b\":[\"A\",null,\"C\"],\"c\":\"C\"}'\n                ]\n            ]\n        );\n    }\n\n    public function testDoesNotUseIncorrectValue()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithObjectInput(input: [\"foo\", \"bar\", \"baz\"])\n            }',\n            [\n                'data'   => [\n                    'fieldWithObjectInput' => null\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"input\" has invalid value [\"foo\",\"bar\",\"baz\"].',\n                        'path'      => ['fieldWithObjectInput'],\n                        'locations' => [['line' => 2, 'column' => 43]],\n                    ]\n                ]\n            ]\n        );\n    }\n\n    public function testProperlyRunsParseLiteralOnComplexScalarTypes()\n    {\n        $this->assertQueryResult(\n            '{\n                fieldWithObjectInput(input: {c: \"foo\", d: \"SerializedValue\"})\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"c\":\"foo\",\"d\":\"DeserializedValue\"}'\n                ]\n            ]\n        );\n    }\n\n    // USING VARIABLES\n\n    public function testExecutesWithComplexInputUsingVariables()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":\"foo\",\"b\":[\"bar\"],\"c\":\"baz\"}'\n                ]\n            ],\n            ['input' => ['a' => 'foo', 'b' => ['bar'], 'c' => 'baz']]\n        );\n    }\n\n    public function testUseDefaultValueWhenNotProvide()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject = {a: \"foo\", b: [\"bar\"], c: \"baz\"}) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":\"foo\",\"b\":[\"bar\"],\"c\":\"baz\"}'\n                ]\n            ]\n        );\n    }\n\n    public function testProperlyParsesSingleValueToListUsingVariable()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"a\":\"foo\",\"b\":[\"bar\"],\"c\":\"baz\"}'\n                ]\n            ],\n            ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz']]\n        );\n    }\n\n    public function testExecutesWithComplexScalarInputUsingVariable()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"c\":\"foo\",\"d\":\"DeserializedValue\"}'\n                ]\n            ],\n            ['input' => ['c' => 'foo', 'd' => 'SerializedValue']]\n        );\n    }\n\n    public function testErrorsOnNullForNestedNonNullUsingVariable()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" got invalid value {\"a\":\"foo\",\"b\":\"bar\",\"c\":null}; ' .\n                            'Field value.c of required type String! was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ]\n                ]\n            ],\n            ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => null]]\n        );\n    }\n\n    public function testErrorsOnDeepNestedErrorsWithManyErrors()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestNestedInputObject) {\n              fieldWithNestedObjectInput(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" got invalid value {\"na\":{\"a\":\"foo\"}}; ' .\n                            'Field value.na.c of required type String! was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ],\n                    [\n                        'message'   => 'Variable \"$input\" got invalid value {\"na\":{\"a\":\"foo\"}}; ' .\n                            'Field value.nb of required type String! was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n            ['input' => ['na' => ['a' => 'foo']]]\n        );\n    }\n\n    public function testErrorsOnAdditionOfUnknownInputField()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestInputObject) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" got invalid value ' .\n                            '{\"a\":\"foo\",\"b\":\"bar\",\"c\":\"baz\",\"extra\":\"dog\"}; ' .\n                            'Field \"extra\" is not defined by type TestInputObject.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ]\n                ]\n            ],\n            ['input' => ['a' => 'foo', 'b' => 'bar', 'c' => 'baz', 'extra' => 'dog']]\n        );\n    }\n\n    // HANDLES NULLABLE SCALARS\n\n    public function testAllowsNullableInputsToBeOmitted()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithNullableStringInput\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => null\n                ],\n            ]\n        );\n    }\n\n    public function testAllowsNullableInputsToBeOmittedInAVariable()\n    {\n        $this->assertQueryResult(\n            'query ($value: String) {\n              fieldWithNullableStringInput(input: $value)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => null\n                ],\n            ]\n        );\n    }\n\n    public function testAllowsNullableInputsToBeOmittedInUnlistedVariable()\n    {\n        $this->assertQueryResult(\n            'query {\n              fieldWithNullableStringInput(input: $value)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => null\n                ],\n            ]\n        );\n    }\n\n    public function testAllowsNullableInputsToBeSetToNullInVariable()\n    {\n        $this->assertQueryResult(\n            'query ($value: String) {\n              fieldWithNullableStringInput(input: $value)\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => 'null'\n                ],\n            ],\n            ['value' => null]\n        );\n    }\n\n    public function testAllowsNullableInputsToBeSetToAValueDirectly()\n    {\n        $this->assertQueryResult(\n            'query ($value: String) {\n              fieldWithNullableStringInput(input: \"a\")\n            }',\n            [\n                'data' => [\n                    'fieldWithNullableStringInput' => '\"a\"'\n                ],\n            ]\n        );\n    }\n\n    // HANDLES NON-NULLABLE SCALARS'\n\n    public function testAllowsNonNullableInputsToBeOmittedGivenADefault()\n    {\n        $this->assertQueryResult(\n            'query ($value: String = \"default\") {\n              fieldWithNonNullableStringInput(input: $value)\n            }',\n            [\n                'data' => [\n                    'fieldWithNonNullableStringInput' => '\"default\"'\n                ],\n            ]\n        );\n    }\n\n    public function testDoesNotAllowNonNullableInputsToBeOmittedInAVariable()\n    {\n        $this->assertQueryResult(\n            'query ($value: String!) {\n              fieldWithNonNullableStringInput(input: $value)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$value\" of required type \"String!\" was not provided.',\n                        'locations' => [\n                            [\n                                'column' => 8,\n                                'line'   => 1\n                            ]\n                        ],\n                    ],\n                ],\n            ]\n        );\n    }\n\n    public function testDoesNotAllowNonNullabeInputsToBeSetToNullInAVariable()\n    {\n        $this->assertQueryResult(\n            'query ($value: String!) {\n              fieldWithNonNullableStringInput(input: $value)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$value\" of required type \"String!\" was not provided.',\n                        'locations' => [\n                            [\n                                'column' => 8,\n                                'line'   => 1\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n            ['value' => null]\n        );\n    }\n\n    public function testAllowsNonNullableInputsToBeSetToAValueInAVariable()\n    {\n        $this->assertQueryResult(\n            'query ($value: String!) {\n              fieldWithNonNullableStringInput(input: $value)\n            }',\n            [\n                'data' => [\n                    'fieldWithNonNullableStringInput' => '\"a\"'\n                ]\n            ],\n            ['value' => 'a']\n        );\n    }\n\n    public function testAllowsNonNullableInputsToBeSetToAValueDirectly()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithNonNullableStringInput(input: \"a\")\n            }',\n            [\n                'data' => [\n                    'fieldWithNonNullableStringInput' => '\"a\"'\n                ]\n            ]\n        );\n    }\n\n    public function testReportErrorForMissingNonNullableInputs()\n    {\n        $this->assertQueryResult(\n            '{ fieldWithNonNullableStringInput }',\n            [\n                'data'   => [\n                    'fieldWithNonNullableStringInput' => null\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"input\" of required type \"String!\" was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 3\n                            ]\n                        ],\n                        'path'      => ['fieldWithNonNullableStringInput']\n                    ]\n                ]\n            ]\n        );\n    }\n\n    public function testReportErrorForArrayPassedIntoStringInput()\n    {\n        $this->assertQueryResult(\n            'query ($value: String!) {\n              fieldWithNonNullableStringInput(input: $value)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$value\" got invalid value [1,2,3]; Expected type String; ' .\n                            'String cannot represent a non-scalar value',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ]\n                ]\n            ],\n            ['value' => [1, 2, 3]]\n        );\n    }\n\n    public function testSerializingAnArrayViaGraphQLStringThrowsTypeError()\n    {\n        $this->expectException(InvalidTypeException::class);\n\n        stringType()->serialize([1, 2, 3]);\n    }\n\n    public function testReportErrorForNonProvidedVariableForNonNullableInputs()\n    {\n        // Note: this test would typically fail validation before encountering\n        // this execution error, however for queries which previously validated\n        // and are being run against a new schema which have introduced a breaking\n        // change to make a formerly non-required argument required, this asserts\n        // failure before allowing the underlying code to receive a non-null value.\n\n        $this->assertQueryResult(\n            '{\n              fieldWithNonNullableStringInput(input: $foo)\n            }',\n            [\n                'data'   => [\n                    'fieldWithNonNullableStringInput' => null\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"input\" of required type \"String!\" was provided the ' .\n                            'variable \"$foo\" which was not provided a runtime value.',\n                        'locations' => [\n                            [\n                                'line'   => 2,\n                                'column' => 54\n                            ]\n                        ],\n                        'path'      => ['fieldWithNonNullableStringInput']\n                    ]\n                ]\n            ]\n        );\n    }\n\n    // HANDLES LISTS AND NULLABILITY\n\n    public function testAllowsListsToBeNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String]) {\n              list(input: $input)\n            }',\n            [\n                'data' => [\n                    'list' => 'null'\n                ],\n            ],\n            ['input' => null]\n        );\n    }\n\n    public function testAllowsListsContainValues()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String]) {\n              list(input: $input)\n            }',\n            [\n                'data' => [\n                    'list' => '[\"A\"]'\n                ],\n            ],\n            ['input' => ['A']]\n        );\n    }\n\n\n    public function testAllowsListsContainNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String]) {\n              list(input: $input)\n            }',\n            [\n                'data' => [\n                    'list' => '[\"A\",null,\"B\"]'\n                ],\n            ],\n            ['input' => ['A', null, 'B']]\n        );\n    }\n\n    public function testDoesNotAllowNonNullListsToBeNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String]!) {\n              nnList(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" of required type \"[String]!\" was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n            ['input' => null]\n        );\n    }\n\n\n    public function testAllowsNonNullListsToContainValues()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String]!) {\n              nnList(input: $input)\n            }',\n            [\n                'data' => [\n                    'nnList' => '[\"A\"]'\n                ]\n            ],\n            ['input' => ['A']]\n        );\n    }\n\n    public function testAllowsListsOfNonNullsToBeNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String!]) {\n              listNN(input: $input)\n            }',\n            [\n                'data' => [\n                    'listNN' => 'null'\n                ]\n            ],\n            ['input' => null]\n        );\n    }\n\n    public function testAllowsListsOfNonNullsToContainValues()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String!]) {\n              listNN(input: $input)\n            }',\n            [\n                'data' => [\n                    'listNN' => '[\"A\"]'\n                ]\n            ],\n            ['input' => ['A']]\n        );\n    }\n\n    public function testDoesNotAllowsListsOfNonNullsToContainNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String!]) {\n              listNN(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" got invalid value [\"A\",null,\"B\"]; ' .\n                            'Expected non-nullable type String! not to be null at value[1].',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n            ['input' => ['A', null, 'B']]\n        );\n    }\n\n    public function testDoesNotAllowsListsOfNonNullsToBeNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String!]!) {\n              nnListNN(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" of required type \"[String!]!\" was not provided.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n            ['input' => null]\n        );\n    }\n\n    public function testDoesNotAllowsNonNullListsOfNonNullsToContainNull()\n    {\n        $this->assertQueryResult(\n            'query ($input: [String!]!) {\n              nnListNN(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" got invalid value [\"A\",null,\"B\"]; ' .\n                            'Expected non-nullable type String! not to be null at value[1].',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n            ['input' => ['A', null, 'B']]\n        );\n    }\n\n    public function testDoesNotAllowsInvalidTypesToBeUsedAsValues()\n    {\n        $this->assertQueryResult(\n            'query ($input: TestType!) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" expected value of type \"TestType!\" which ' .\n                            'cannot be used as an input type.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ]\n                ],\n            ],\n            ['input' => ['list' => ['A', null, 'B']]]\n        );\n    }\n\n    public function testDoesNotAllowsUnknownTypesToBeUsedAsValues()\n    {\n        $this->assertQueryResult(\n            'query ($input: UnknownType!) {\n              fieldWithObjectInput(input: $input)\n            }',\n            [\n                'data'   => null,\n                'errors' => [\n                    [\n                        'message'   => 'Variable \"$input\" expected value of type \"UnknownType!\" which ' .\n                            'cannot be used as an input type.',\n                        'locations' => [\n                            [\n                                'line'   => 1,\n                                'column' => 8\n                            ]\n                        ],\n                    ]\n                ],\n            ],\n            ['input' => 'whoknows']\n        );\n    }\n\n    // Execute: Uses argument default values\n\n    public function testWhenNoArgumentProvided()\n    {\n        $this->assertQueryResult(\n            '{ fieldWithDefaultArgumentValue }',\n            [\n                'data' => ['fieldWithDefaultArgumentValue' => '\"Hello World\"']\n            ]\n        );\n    }\n\n    public function testWhenOmittedVariableProvided()\n    {\n        $this->assertQueryResult(\n            'query ($optional: String) {\n              fieldWithDefaultArgumentValue(input: $optional)\n            }',\n            [\n                'data' => ['fieldWithDefaultArgumentValue' => '\"Hello World\"']\n            ]\n        );\n    }\n\n    public function testNotWhenArgumentCannotBeCoerced()\n    {\n        $this->assertQueryResult(\n            '{\n              fieldWithDefaultArgumentValue(input: WRONG_TYPE)\n            }',\n            [\n                'data'   => [\n                    'fieldWithDefaultArgumentValue' => null\n                ],\n                'errors' => [\n                    [\n                        'message'   => 'Argument \"input\" has invalid value WRONG_TYPE.',\n                        'locations' => [\n                            [\n                                'line'   => 2,\n                                'column' => 52\n                            ]\n                        ],\n                        'path'      => ['fieldWithDefaultArgumentValue']\n                    ]\n                ],\n            ]\n        );\n    }\n\n    public function testCustomDateTimeScalarType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $dateType = newScalarType([\n            'name'         => 'Date',\n            'serialize'    => function (\\DateTime $value) {\n                /** @noinspection PhpUndefinedMethodInspection */\n                return $value->format('Y-m-d');\n            },\n            'parseValue'   => function ($node) {\n                /** @noinspection PhpUndefinedMethodInspection */\n                return new \\DateTime($node->getValue(), new \\DateTimeZone('Europe/Helsinki'));\n            },\n            'parseLiteral' => function ($node) {\n                /** @noinspection PhpUndefinedMethodInspection */\n                return new \\DateTime($node->getValue(), new \\DateTimeZone('Europe/Helsinki'));\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestInputObject = newInputObjectType([\n            'name'   => 'TestInputObject',\n            'fields' => [\n                'a' => ['type' => stringType()],\n                'b' => ['type' => newList(stringType())],\n                'c' => ['type' => newNonNull(stringType())],\n                'd' => ['type' => $dateType]\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $TestType = newObjectType([\n            'name'   => 'TestType',\n            'fields' => [\n                'fieldWithObjectInput' => $this->fieldWithInputArg(['type' => $TestInputObject]),\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => $TestType\n        ]);\n\n        $this->assertQueryResultWithSchema(\n            $schema,\n            '{\n              fieldWithObjectInput(input: {c: \"foo\", d: \"2018-01-01\"})\n            }',\n            [\n                'data' => [\n                    'fieldWithObjectInput' => '{\"c\":\"foo\",\"d\":{\"date\":\"2018-01-01 00:00:00.000000\",\"timezone_type\":3,\"timezone\":\"Europe\\/Helsinki\"}}'\n                ]\n            ]\n        );\n    }\n\n    /**\n     * @noinspection PhpDocMissingThrowsInspection\n     *\n     * @param string $query\n     * @param array  $expected\n     * @param array  $variables\n     */\n    protected function assertQueryResult(string $query, array $expected, array $variables = [])\n    {\n        $this->assertQueryResultWithSchema($this->schema, $query, $expected, null, null, $variables);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Execution/testClasses.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Execution;\n\nclass Human\n{\n    public $name;\n\n    public function __construct(string $name)\n    {\n        $this->name = $name;\n    }\n}\n\nclass Person\n{\n    public $name;\n    public $pets;\n    public $friends;\n\n    public function __construct(string $name, array $pets = [], array $friends = [])\n    {\n        $this->name    = $name;\n        $this->friends = $friends;\n        $this->pets    = $pets;\n    }\n}\n\nclass Dog\n{\n    public $name;\n    public $woofs;\n\n    public function __construct(string $name, bool $woofs)\n    {\n        $this->name  = $name;\n        $this->woofs = $woofs;\n    }\n}\n\nclass Cat\n{\n    public $name;\n    public $meows;\n\n    public function __construct(string $name, bool $meows)\n    {\n        $this->name  = $name;\n        $this->meows = $meows;\n    }\n}"
  },
  {
    "path": "tests/Functional/IntrospectionTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\graphql;\n\nclass IntrospectionTest extends TestCase\n{\n    // Star Wars Introspection Tests\n\n    // Basic Introspection\n\n    // Allows querying the schema for types\n\n    public function testAllowsQueryingTheSchemaForTypes()\n    {\n        $query = '\n        query IntrospectionTypeQuery {\n          __schema {\n            types {\n              name\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__schema' => [\n                    'types' => [\n                        ['name' => 'Query'],\n                        ['name' => 'Episode'],\n                        ['name' => 'Character'],\n                        ['name' => 'String'],\n                        ['name' => 'Human'],\n                        ['name' => 'Droid'],\n                        ['name' => '__Schema'],\n                        ['name' => '__Type'],\n                        ['name' => '__TypeKind'],\n                        ['name' => 'Boolean'],\n                        ['name' => '__Field'],\n                        ['name' => '__InputValue'],\n                        ['name' => '__EnumValue'],\n                        ['name' => '__Directive'],\n                        ['name' => '__DirectiveLocation'],\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for query type\n\n    public function testAllowsQueryingTheSchemaForQueryType()\n    {\n        $query = '\n        query IntrospectionQueryTypeQuery {\n          __schema {\n            queryType {\n              name\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__schema' => [\n                    'queryType' => [\n                        'name' => 'Query',\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for a specific type\n\n    public function testAllowsQueryingTheSchemaForASpecificType()\n    {\n        $query = '\n        query IntrospectionDroidTypeQuery {\n          __type(name: \"Droid\") {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name' => 'Droid',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for an object kind\n\n    public function testAllowsQueryingTheSchemaForAnObjectKind()\n    {\n        $query = '\n        query IntrospectionDroidKindQuery {\n          __type(name: \"Droid\") {\n            name\n            kind\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name' => 'Droid',\n                    'kind' => 'OBJECT',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for an interface kind\n\n    public function testAllowsQueryingTheSchemaForAnInterfaceKind()\n    {\n        $query = '\n        query IntrospectionCharacterKindQuery {\n          __type(name: \"Character\") {\n            name\n            kind\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name' => 'Character',\n                    'kind' => 'INTERFACE',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for object fields\n\n    public function testAllowsQueryingTheSchemaForObjectFields()\n    {\n        $query = '\n        query IntrospectionDroidFieldsQuery {\n          __type(name: \"Droid\") {\n            name\n            fields {\n              name\n              type {\n                name\n                kind\n              }\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name'   => 'Droid',\n                    'fields' => [\n                        [\n                            'name' => 'id',\n                            'type' => [\n                                'name' => null,\n                                'kind' => 'NON_NULL',\n                            ],\n                        ],\n                        [\n                            'name' => 'name',\n                            'type' => [\n                                'name' => 'String',\n                                'kind' => 'SCALAR',\n                            ],\n                        ],\n                        [\n                            'name' => 'friends',\n                            'type' => [\n                                'name' => null,\n                                'kind' => 'LIST',\n                            ],\n                        ],\n                        [\n                            'name' => 'appearsIn',\n                            'type' => [\n                                'name' => null,\n                                'kind' => 'LIST',\n                            ],\n                        ],\n                        [\n                            'name' => 'secretBackstory',\n                            'type' => [\n                                'name' => 'String',\n                                'kind' => 'SCALAR',\n                            ],\n                        ],\n                        [\n                            'name' => 'primaryFunction',\n                            'type' => [\n                                'name' => 'String',\n                                'kind' => 'SCALAR',\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for nested object fields\n\n    public function testAllowsQueryingTheSchemaForNestedObjectFields()\n    {\n        $query = '\n        query IntrospectionDroidNestedFieldsQuery {\n          __type(name: \"Droid\") {\n            name\n            fields {\n              name\n              type {\n                name\n                kind\n                ofType {\n                  name\n                  kind\n                }\n              }\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name'   => 'Droid',\n                    'fields' => [\n                        [\n                            'name' => 'id',\n                            'type' => [\n                                'name'   => null,\n                                'kind'   => 'NON_NULL',\n                                'ofType' => [\n                                    'name' => 'String',\n                                    'kind' => 'SCALAR',\n                                ],\n                            ],\n                        ],\n                        [\n                            'name' => 'name',\n                            'type' => [\n                                'name'   => 'String',\n                                'kind'   => 'SCALAR',\n                                'ofType' => null,\n                            ],\n                        ],\n                        [\n                            'name' => 'friends',\n                            'type' => [\n                                'name'   => null,\n                                'kind'   => 'LIST',\n                                'ofType' => [\n                                    'name' => 'Character',\n                                    'kind' => 'INTERFACE',\n                                ],\n                            ],\n                        ],\n                        [\n                            'name' => 'appearsIn',\n                            'type' => [\n                                'name'   => null,\n                                'kind'   => 'LIST',\n                                'ofType' => [\n                                    'name' => 'Episode',\n                                    'kind' => 'ENUM',\n                                ],\n                            ],\n                        ],\n                        [\n                            'name' => 'secretBackstory',\n                            'type' => [\n                                'name'   => 'String',\n                                'kind'   => 'SCALAR',\n                                'ofType' => null,\n                            ],\n                        ],\n                        [\n                            'name' => 'primaryFunction',\n                            'type' => [\n                                'name'   => 'String',\n                                'kind'   => 'SCALAR',\n                                'ofType' => null,\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for field args\n\n    public function testAllowsQueryingTheSchemaForFieldArguments()\n    {\n        $query = '\n        query IntrospectionQueryTypeQuery {\n          __schema {\n            queryType {\n              fields {\n                name\n                args {\n                  name\n                  description\n                  type {\n                    name\n                    kind\n                    ofType {\n                      name\n                      kind\n                    }\n                  }\n                  defaultValue\n                }\n              }\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__schema' => [\n                    'queryType' => [\n                        'fields' => [\n                            [\n                                'name' => 'hero',\n                                'args' => [\n                                    [\n                                        'defaultValue' => null,\n                                        'description'  =>\n                                            'If omitted, returns the hero of the whole ' .\n                                            'saga. If provided, returns the hero of ' .\n                                            'that particular episode.',\n                                        'name'         => 'episode',\n                                        'type'         => [\n                                            'kind'   => 'ENUM',\n                                            'name'   => 'Episode',\n                                            'ofType' => null,\n                                        ],\n                                    ],\n                                ],\n                            ],\n                            [\n                                'name' => 'human',\n                                'args' => [\n                                    [\n                                        'name'         => 'id',\n                                        'description'  => 'id of the human',\n                                        'type'         => [\n                                            'kind'   => 'NON_NULL',\n                                            'name'   => null,\n                                            'ofType' => [\n                                                'kind' => 'SCALAR',\n                                                'name' => 'String',\n                                            ],\n                                        ],\n                                        'defaultValue' => null,\n                                    ],\n                                ],\n                            ],\n                            [\n                                'name' => 'droid',\n                                'args' => [\n                                    [\n                                        'name'         => 'id',\n                                        'description'  => 'id of the droid',\n                                        'type'         => [\n                                            'kind'   => 'NON_NULL',\n                                            'name'   => null,\n                                            'ofType' => [\n                                                'kind' => 'SCALAR',\n                                                'name' => 'String',\n                                            ],\n                                        ],\n                                        'defaultValue' => null,\n                                    ],\n                                ],\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows querying the schema for documentation\n\n    public function testAllowsQueryingTheSchemaForDocumentation()\n    {\n        $query = '\n        query IntrospectionDroidDescriptionQuery {\n          __type(name: \"Droid\") {\n            name\n            description\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name'        => 'Droid',\n                    'description' => 'A mechanical creature in the Star Wars universe.',\n                ],\n            ],\n        ], $result);\n    }\n\n    /**\n     * Test to check that we can introspect on a scalar, which does *not*\n     * have a name which clashes with a global PHP function or class\n     */\n    public function testCanIntrospectOnANonClashingScalar()\n    {\n        $schema = '\n        scalar Postcode\n        type Query {\n            hello: Postcode\n        }\n        ';\n\n\n        $schema = buildSchema($schema);\n\n        $query = '\n        query IntrospectionDroidDescriptionQuery {\n          __type(name: \"Postcode\") {\n            name\n          }\n        }\n        ';\n\n        $result = graphql($schema, $query);\n\n        $this->assertArrayNotHasKey('errors', $result);\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name' => 'Postcode',\n                ],\n            ],\n        ], $result);\n    }\n\n    /**\n     * Test to check that we can introspect on a scalar, which *does*\n     * have a name which clashes with a global PHP function or class\n     */\n    public function testCanIntrospectOnScalarWithClashingName()\n    {\n        $schema = '\n        scalar Date\n        type Query {\n            hello: Date\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema($schema);\n\n        $query = '\n        query IntrospectionDroidDescriptionQuery {\n          __type(name: \"Date\") {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql($schema, $query);\n\n        $this->assertArrayNotHasKey('errors', $result);\n        $this->assertEquals([\n            'data' => [\n                '__type' => [\n                    'name' => 'Date',\n                ],\n            ],\n        ], $result);\n    }\n\n}\n"
  },
  {
    "path": "tests/Functional/Language/FileSourceBuilderTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\Language\\FileSourceBuilder;\nuse Digia\\GraphQL\\Test\\TestCase;\n\n/**\n * Class FileSourceBuilderTest\n * @package Digia\\GraphQL\\Test\\Functional\\Language\n */\nclass FileSourceBuilderTest extends TestCase\n{\n\n    /**\n     * @expectedException \\Digia\\GraphQL\\Error\\FileNotFoundException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testFileNotFound(): void\n    {\n        $builder = new FileSourceBuilder('/not/existing/file.graphqls');\n\n        $builder->build();\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\FileNotFoundException\n     */\n    public function testSuccess(): void\n    {\n        $builder = new FileSourceBuilder(__DIR__ . '/schema-kitchen-sink.graphqls');\n\n        $source = $builder->build();\n\n        $this->assertGreaterThan(0, $source->getBodyLength());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Language/MultiFileSourceBuilderTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\Language\\MultiFileSourceBuilder;\nuse Digia\\GraphQL\\Test\\TestCase;\n\n/**\n * Class MultiFileSourceBuilderTest\n * @package Digia\\GraphQL\\Test\\Functional\\Language\n */\nclass MultiFileSourceBuilderTest extends TestCase\n{\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\FileNotFoundException\n     */\n    public function testBuildSource(): void\n    {\n        $builder = new MultiFileSourceBuilder([\n            __DIR__ . '/schema-kitchen-sink.graphqls',\n            __DIR__ . '/../starWars.graphqls',\n        ]);\n\n        $source = $builder->build();\n\n        $this->assertEquals(3747, $source->getBodyLength());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Language/ParserTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Language\\SyntaxErrorException;\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Language\\ParserInterface;\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\parseType;\nuse function Digia\\GraphQL\\parseValue;\nuse function Digia\\GraphQL\\Test\\readFileContents;\n\nclass ParserTest extends TestCase\n{\n\n    /**\n     * @throws InvariantException\n     */\n    public function testParsePartial()\n    {\n        /** @var ParserInterface $parser */\n        $parser = GraphQL::make(ParserInterface::class);\n\n        /** @var NameNode $nameNode */\n        $nameNode = $parser->parseName(new Source('foo'));\n\n        $this->assertInstanceOf(NameNode::class, $nameNode);\n        $this->assertEquals('foo', $nameNode->getValue());\n\n        /** @var OperationDefinitionNode $operationDefinition */\n        $operationDefinition = $parser->parseOperationDefinition(new Source('query FooQuery { foo }'));\n\n        $this->assertInstanceOf(OperationDefinitionNode::class, $operationDefinition);\n        $this->assertEquals('query', $operationDefinition->getOperation());\n        $this->assertEquals('FooQuery', $operationDefinition->getNameValue());\n\n        /** @var VariableDefinitionNode $variableDefinitionNode */\n        $variableDefinitionNode = $parser->parseVariableDefinition(new Source('$foo: String = \"bar\"'));\n\n        $this->assertInstanceOf(VariableDefinitionNode::class, $variableDefinitionNode);\n        $this->assertEquals('foo', $variableDefinitionNode->getVariable()->getNameValue());\n        /** @noinspection PhpUndefinedMethodInspection */\n        $this->assertEquals('String', $variableDefinitionNode->getType()->getNameValue());\n        /** @noinspection PhpUndefinedMethodInspection */\n        $this->assertEquals('bar', $variableDefinitionNode->getDefaultValue()->getValue());\n\n        /** @var VariableNode $variableNode */\n        $variableNode = $parser->parseVariable(new Source('$foo'));\n\n        $this->assertInstanceOf(VariableNode::class, $variableNode);\n        $this->assertEquals('foo', $variableNode->getNameValue());\n\n        /** @var ArgumentNode $argumentNode */\n        $argumentNode = $parser->parseArgument(new Source('foo: String'));\n\n        $this->assertInstanceOf(ArgumentNode::class, $argumentNode);\n        $this->assertEquals('foo', $argumentNode->getNameValue());\n\n        /** @var DirectiveNode $directiveNode */\n        $directiveNode = $parser->parseDirective(new Source('@foo(bar: String, baz: Int)'));\n        $directiveArgs = $directiveNode->getArguments();\n\n        $this->assertInstanceOf(DirectiveNode::class, $directiveNode);\n        $this->assertEquals('foo', $directiveNode->getNameValue());\n        $this->assertEquals('bar', $directiveArgs[0]->getNameValue());\n        $this->assertEquals('baz', $directiveArgs[1]->getNameValue());\n    }\n\n    public function testParseProvidesUsefulErrors()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected Name, found <EOF>');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('{');\n\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected {, found <EOF>');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('query', 'MyQuery.graphql');\n    }\n\n    public function testParsesVariableInlineValues()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('{ field(complex: { a: { b: [ $var ] } }) }');\n        $this->addToAssertionCount(1);\n    }\n\n    public function testParsesConstantDefaultValues()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Unexpected $');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('query Foo($x: Complex = { a: { b: [ $var ] } }) { field }');\n        $this->addToAssertionCount(1);\n    }\n\n    public function testDoesNotAcceptFragmentsNamedOn()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Unexpected Name \"on\"');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('fragment on on on { on }');\n        $this->addToAssertionCount(1);\n    }\n\n    public function testDoesNotAcceptFragmentSpreadOfOn()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected Name, found }');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('{ ...on }');\n        $this->addToAssertionCount(1);\n    }\n\n    public function testParsesMultiByteCharacters()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse(dedent('\n          # This comment has a \\u0A0A multi-byte character.\n          { field(arg: \"Has a \\u0A0A multi-byte character.\") }\n        '));\n\n        $this->assertArraySubset([\n            'definitions' => [\n                [\n                    'selectionSet' => [\n                        'selections' => [\n                            [\n                                'arguments' => [\n                                    [\n                                        'value' => [\n                                            'kind'  => NodeKindEnum::STRING,\n                                            'value' => 'Has a \\u0A0A multi-byte character.',\n                                        ],\n                                    ],\n                                ],\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ], $node->toAST());\n    }\n\n    public function testParsesKitchenSink()\n    {\n        $kitchenSink = readFileContents(__DIR__ . '/kitchen-sink.graphql');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse($kitchenSink);\n        $this->addToAssertionCount(1);\n    }\n\n    public function testAllowsNonKeywordsAnywhereANameIsAllowed()\n    {\n        $nonKeywords = [\n            'on',\n            'fragment',\n            'query',\n            'mutation',\n            'subscription',\n            'true',\n            'false',\n        ];\n\n        foreach ($nonKeywords as $keyword) {\n            $fragmentName = $keyword;\n\n            // You can't define or reference a fragment named `on`.\n            if ($keyword === 'on') {\n                $fragmentName = 'a';\n            }\n\n            /** @noinspection PhpUnhandledExceptionInspection */\n            parse(dedent(\"\n            query $keyword {\n              ... $fragmentName\n              ... on $keyword { field }\n            }\n            fragment $fragmentName on Type {\n              $keyword($keyword: $$keyword)\n                @$keyword($keyword: $keyword)\n            }\n            \"));\n\n            $this->addToAssertionCount(1);\n        }\n    }\n\n    public function testParsesAnonMutationOperations()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse(dedent('\n        mutation {\n            mutationField\n        }\n        '));\n        $this->addToAssertionCount(1);\n    }\n\n    public function testParsesAnonSubscriptionOperations()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse(dedent('\n        subscription {\n            subscriptionField\n        }\n        '));\n        $this->addToAssertionCount(1);\n    }\n\n    public function testParsesNamedMutationOperations()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse(dedent('\n        mutation Foo {\n            mutationField\n        }\n        '));\n        $this->addToAssertionCount(1);\n    }\n\n    public function testParsesNamedSubscriptionOperations()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse(dedent('\n        subscription Foo {\n            subscriptionField\n        }\n        '));\n        $this->addToAssertionCount(1);\n    }\n\n    public function testCreatesAST()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $actual = parse(dedent('\n        {\n          node(id: 4) {\n            id,\n            name\n          }\n        }\n        '));\n\n        $this->assertEquals([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'loc'         => ['start' => 0, 'end' => 41],\n            'definitions' => [\n                [\n                    'kind'                => NodeKindEnum::OPERATION_DEFINITION,\n                    'loc'                 => ['start' => 0, 'end' => 40],\n                    'operation'           => 'query',\n                    'name'                => null,\n                    'variableDefinitions' => [],\n                    'directives'          => [],\n                    'selectionSet'        => [\n                        'kind'       => NodeKindEnum::SELECTION_SET,\n                        'loc'        => ['start' => 0, 'end' => 40],\n                        'selections' => [\n                            [\n                                'kind'         => NodeKindEnum::FIELD,\n                                'loc'          => ['start' => 4, 'end' => 38],\n                                'alias'        => null,\n                                'name'         => [\n                                    'kind'  => NodeKindEnum::NAME,\n                                    'loc'   => ['start' => 4, 'end' => 8],\n                                    'value' => 'node',\n                                ],\n                                'arguments'    => [\n                                    [\n                                        'kind'  => NodeKindEnum::ARGUMENT,\n                                        'name'  => [\n                                            'kind'  => NodeKindEnum::NAME,\n                                            'loc'   => ['start' => 9, 'end' => 11],\n                                            'value' => 'id',\n                                        ],\n                                        'value' => [\n                                            'kind'  => NodeKindEnum::INT,\n                                            'loc'   => ['start' => 13, 'end' => 14],\n                                            'value' => '4',\n                                        ],\n                                        'loc'   => ['start' => 9, 'end' => 14],\n                                    ],\n                                ],\n                                'directives'   => [],\n                                'selectionSet' => [\n                                    'kind'       => NodeKindEnum::SELECTION_SET,\n                                    'loc'        => ['start' => 16, 'end' => 38],\n                                    'selections' => [\n                                        [\n                                            'kind'         => NodeKindEnum::FIELD,\n                                            'loc'          => ['start' => 22, 'end' => 24],\n                                            'alias'        => null,\n                                            'name'         => [\n                                                'kind'  => NodeKindEnum::NAME,\n                                                'loc'   => ['start' => 22, 'end' => 24],\n                                                'value' => 'id',\n                                            ],\n                                            'arguments'    => [],\n                                            'directives'   => [],\n                                            'selectionSet' => null,\n                                        ],\n                                        [\n                                            'kind'         => NodeKindEnum::FIELD,\n                                            'loc'          => ['start' => 30, 'end' => 34],\n                                            'alias'        => null,\n                                            'name'         => [\n                                                'kind'  => NodeKindEnum::NAME,\n                                                'loc'   => ['start' => 30, 'end' => 34],\n                                                'value' => 'name',\n                                            ],\n                                            'arguments'    => [],\n                                            'directives'   => [],\n                                            'selectionSet' => null,\n                                        ],\n                                    ],\n                                ],\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ], $actual->toAST());\n    }\n\n    public function testCreatesAstFromNamelessQueryWithoutVariables()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $actual = parse(dedent('\n        query {\n          node {\n            id\n          }\n        }\n        '));\n\n        $this->assertEquals([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'loc'         => ['start' => 0, 'end' => 30],\n            'definitions' => [\n                [\n                    'kind'                => NodeKindEnum::OPERATION_DEFINITION,\n                    'loc'                 => ['start' => 0, 'end' => 29],\n                    'operation'           => 'query',\n                    'name'                => null,\n                    'variableDefinitions' => [],\n                    'directives'          => [],\n                    'selectionSet'        => [\n                        'kind'       => NodeKindEnum::SELECTION_SET,\n                        'loc'        => ['start' => 6, 'end' => 29],\n                        'selections' => [\n                            [\n                                'kind'         => NodeKindEnum::FIELD,\n                                'loc'          => ['start' => 10, 'end' => 27],\n                                'alias'        => null,\n                                'name'         => [\n                                    'kind'  => NodeKindEnum::NAME,\n                                    'loc'   => ['start' => 10, 'end' => 14],\n                                    'value' => 'node',\n                                ],\n                                'arguments'    => [],\n                                'directives'   => [],\n                                'selectionSet' => [\n                                    'kind'       => NodeKindEnum::SELECTION_SET,\n                                    'loc'        => ['start' => 15, 'end' => 27],\n                                    'selections' => [\n                                        [\n                                            'kind'         => NodeKindEnum::FIELD,\n                                            'loc'          => ['start' => 21, 'end' => 23],\n                                            'alias'        => null,\n                                            'name'         => [\n                                                'kind'  => NodeKindEnum::NAME,\n                                                'loc'   => ['start' => 21, 'end' => 23],\n                                                'value' => 'id',\n                                            ],\n                                            'arguments'    => [],\n                                            'directives'   => [],\n                                            'selectionSet' => null,\n                                        ],\n                                    ],\n                                ],\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ], $actual->toAST());\n    }\n\n    // TODO: Consider adding test for 'allows parsing without source location information'\n\n    // TODO: Consider adding test for 'Experimental: allows parsing fragment defined variables'\n\n    // TODO: Consider adding test for 'contains location information that only stringifys start/end'\n\n    // Skip 'contains references to source' (not provided by cpp parser)\n\n    // Skip 'contains references to start and end tokens' (not provided by cpp parser)\n\n    public function testParsesNullValue()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseValue('null');\n\n        $this->assertEquals($node->toAST(), [\n            'kind' => NodeKindEnum::NULL,\n            'loc'  => ['start' => 0, 'end' => 4],\n        ]);\n    }\n\n    public function testParsesListValue()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseValue('[123 \"abc\"]');\n\n        $this->assertEquals($node->toAST(), [\n            'kind'   => NodeKindEnum::LIST,\n            'loc'    => ['start' => 0, 'end' => 11],\n            'values' => [\n                [\n                    'kind'  => NodeKindEnum::INT,\n                    'loc'   => ['start' => 1, 'end' => 4],\n                    'value' => '123',\n                ],\n                [\n                    'kind'  => NodeKindEnum::STRING,\n                    'loc'   => ['start' => 5, 'end' => 10],\n                    'block' => false,\n                    'value' => 'abc',\n                ],\n            ],\n        ]);\n    }\n\n    public function testParsesBlockStrings()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseValue('[\"\"\"long\"\"\" \"short\"]');\n\n        $this->assertEquals($node->toAST(), [\n            'kind'   => NodeKindEnum::LIST,\n            'loc'    => ['start' => 0, 'end' => 20],\n            'values' => [\n                [\n                    'kind'  => NodeKindEnum::STRING,\n                    'loc'   => ['start' => 1, 'end' => 11],\n                    'value' => 'long',\n                    'block' => true,\n\n                ],\n                [\n                    'kind'  => NodeKindEnum::STRING,\n                    'loc'   => ['start' => 12, 'end' => 19],\n                    'value' => 'short',\n                    'block' => false,\n                ],\n            ],\n        ]);\n    }\n\n    public function testParsesWellKnownTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseType('String');\n\n        $this->assertEquals($node->toAST(), [\n            'kind' => NodeKindEnum::NAMED_TYPE,\n            'loc'  => ['start' => 0, 'end' => 6],\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'loc'   => ['start' => 0, 'end' => 6],\n                'value' => 'String',\n            ],\n        ]);\n    }\n\n    public function testParsesCustomTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseType('MyType');\n\n        $this->assertEquals($node->toAST(), [\n            'kind' => NodeKindEnum::NAMED_TYPE,\n            'loc'  => ['start' => 0, 'end' => 6],\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'loc'   => ['start' => 0, 'end' => 6],\n                'value' => 'MyType',\n            ],\n        ]);\n    }\n\n    public function testParsesListTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseType('[MyType]');\n\n        $this->assertEquals($node->toAST(), [\n            'kind' => NodeKindEnum::LIST_TYPE,\n            'loc'  => ['start' => 0, 'end' => 8],\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'loc'  => ['start' => 1, 'end' => 7],\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'loc'   => ['start' => 1, 'end' => 7],\n                    'value' => 'MyType',\n                ],\n            ],\n        ]);\n    }\n\n    public function testParsesNonNullTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseType('MyType!');\n\n        $this->assertEquals($node->toAST(), [\n            'kind' => NodeKindEnum::NON_NULL_TYPE,\n            'loc'  => ['start' => 0, 'end' => 7],\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'loc'  => ['start' => 0, 'end' => 6],\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'loc'   => ['start' => 0, 'end' => 6],\n                    'value' => 'MyType',\n                ],\n            ],\n        ]);\n    }\n\n    public function testParsesNestedTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parseType('[MyType!]');\n\n        $this->assertEquals($node->toAST(), [\n            'kind' => NodeKindEnum::LIST_TYPE,\n            'loc'  => ['start' => 0, 'end' => 9],\n            'type' => [\n                'kind' => NodeKindEnum::NON_NULL_TYPE,\n                'loc'  => ['start' => 1, 'end' => 8],\n                'type' => [\n                    'kind' => NodeKindEnum::NAMED_TYPE,\n                    'loc'  => ['start' => 1, 'end' => 7],\n                    'name' => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'loc'   => ['start' => 1, 'end' => 7],\n                        'value' => 'MyType',\n                    ],\n                ],\n            ],\n        ]);\n    }\n\n    /**\n     * The purpose of this test case is that it should *not* crash with \"Syntax Error: Cannot contain the invalid character <EOF>\"\n     * @throws SyntaxErrorException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testParsesGitHubIssue253(): void\n    {\n        $document = parse(dedent('{\n  songs(first: 5, search: {name: \"Vårt land\"}) {\n    edges {\n      node {\n        name\n      }\n    }\n  }\n}\n        '));\n\n        $this->addToAssertionCount(1);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Language/SchemaParserTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\Language\\SyntaxErrorException;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\TypeNameEnum;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Test\\jsonEncode;\n\nclass SchemaParserTest extends TestCase\n{\n\n    public function testSimpleType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ntype Hello {\n  world: String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'interfaces'  => [],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNode(\n                            $this->nameNode('world', ['start' => 16, 'end' => 21]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 23, 'end' => 29]),\n                            ['start' => 16, 'end' => 29]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 31],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 31],\n        ]), $node->toJSON());\n    }\n\n    public function testParsesWithDescriptionString()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n\"Description\"\ntype Hello {\n  world: String\n}');\n\n        $this->assertArraySubset([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'name'        => $this->nameNode('Hello', ['start' => 20, 'end' => 25]),\n                    'description' => [\n                        'kind'  => NodeKindEnum::STRING,\n                        'value' => 'Description',\n                        'loc'   => ['start' => 1, 'end' => 14],\n                    ],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 45],\n        ], $node->toArray());\n    }\n\n    public function testParsesWithDescriptionMultiLineString()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n\"\"\"\nDescription\n\"\"\"\n# Even with comments between them\ntype Hello {\n  world: String\n}');\n\n        $this->assertArraySubset([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'name'        => $this->nameNode('Hello', ['start' => 60, 'end' => 65]),\n                    'description' => [\n                        'kind'  => NodeKindEnum::STRING,\n                        'value' => 'Description',\n                        'loc'   => ['start' => 1, 'end' => 20],\n                    ],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 85],\n        ], $node->toArray());\n    }\n\n    public function testSimpleExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\nextend type Hello {\n  world: String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'       => NodeKindEnum::OBJECT_TYPE_EXTENSION,\n                    'name'       => $this->nameNode('Hello', ['start' => 13, 'end' => 18]),\n                    'interfaces' => [],\n                    'directives' => [],\n                    'fields'     => [\n                        $this->fieldNode(\n                            $this->nameNode('world', ['start' => 23, 'end' => 28]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 30, 'end' => 36]),\n                            ['start' => 23, 'end' => 36]\n                        ),\n                    ],\n                    'loc'        => ['start' => 1, 'end' => 38],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 38],\n        ]), $node->toJSON());\n    }\n\n    public function testExtensionWithoutFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('extend type Hello implements Greeting');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'       => NodeKindEnum::OBJECT_TYPE_EXTENSION,\n                    'name'       => $this->nameNode('Hello', ['start' => 12, 'end' => 17]),\n                    'interfaces' => [\n                        $this->typeNode('Greeting', ['start' => 29, 'end' => 37]),\n                    ],\n                    'directives' => [],\n                    'fields'     => [],\n                    'loc'        => ['start' => 0, 'end' => 37],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 37],\n        ]), $node->toJSON());\n    }\n\n    public function testExtensionWithoutFieldsFollowedByExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n      extend type Hello implements Greeting\n\n      extend type Hello implements SecondGreeting\n    ');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'       => NodeKindEnum::OBJECT_TYPE_EXTENSION,\n                    'name'       => $this->nameNode('Hello', ['start' => 19, 'end' => 24]),\n                    'interfaces' => [\n                        $this->typeNode('Greeting', ['start' => 36, 'end' => 44]),\n                    ],\n                    'directives' => [],\n                    'fields'     => [],\n                    'loc'        => ['start' => 7, 'end' => 44],\n                ],\n                [\n                    'kind'       => NodeKindEnum::OBJECT_TYPE_EXTENSION,\n                    'name'       => $this->nameNode('Hello', ['start' => 64, 'end' => 69]),\n                    'interfaces' => [\n                        $this->typeNode('SecondGreeting', ['start' => 81, 'end' => 95]),\n                    ],\n                    'directives' => [],\n                    'fields'     => [],\n                    'loc'        => ['start' => 52, 'end' => 95],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 100],\n        ]), $node->toJSON());\n    }\n\n    public function testExtensionWithoutAnythingThrows()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Unexpected <EOF>');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('extend type Hello');\n    }\n\n    public function testExtensionsDoNotIncludeDescriptions()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Unexpected Name \"extend\"');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('\n\"Description\"\nextend type Hello {\n  world: String\n}');\n\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Unexpected String \"Description\"');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('\nextend \"Description\" type Hello {\n  world: String\n}');\n    }\n\n    public function testSchemaExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse(dedent('\n        extend schema {\n          mutation: Mutation\n        }\n        '));\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'           => NodeKindEnum::SCHEMA_EXTENSION,\n                    'directives'     => [],\n                    'operationTypes' => [\n                        [\n                            'kind'      => NodeKindEnum::OPERATION_TYPE_DEFINITION,\n                            'operation' => 'mutation',\n                            'type'      => $this->typeNode('Mutation', ['start' => 28, 'end' => 36]),\n                            'loc'       => ['start' => 18, 'end' => 36],\n                        ],\n                    ],\n                    'loc'            => ['start' => 0, 'end' => 38],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 39],\n        ]), $node->toJSON());\n    }\n\n    public function testSchemaExtensionWithOnlyDirectives()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('extend schema @directive');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'           => NodeKindEnum::SCHEMA_EXTENSION,\n                    'directives'     => [\n                        [\n                            'kind'      => NodeKindEnum::DIRECTIVE,\n                            'name'      => $this->nameNode('directive', ['start' => 15, 'end' => 24]),\n                            'arguments' => [],\n                            'loc'       => ['start' => 14, 'end' => 24],\n                        ],\n                    ],\n                    'operationTypes' => [],\n                    'loc'            => ['start' => 0, 'end' => 24],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 24],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleNonNullType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ntype Hello {\n  world: String!\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'interfaces'  => [],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNode(\n                            $this->nameNode('world', ['start' => 16, 'end' => 21]),\n                            [\n                                'kind' => NodeKindEnum::NON_NULL_TYPE,\n                                'type' => $this->typeNode(TypeNameEnum::STRING, ['start' => 23, 'end' => 29]),\n                                'loc'  => ['start' => 23, 'end' => 30],\n                            ],\n                            ['start' => 16, 'end' => 30]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 32],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 32],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleTypeInheritingInterface()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('type Hello implements World { field: String }');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 5, 'end' => 10]),\n                    'interfaces'  => [\n                        $this->typeNode('World', ['start' => 22, 'end' => 27]),\n                    ],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNode(\n                            $this->nameNode('field', ['start' => 30, 'end' => 35]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 37, 'end' => 43]),\n                            ['start' => 30, 'end' => 43]\n                        ),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 45],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 45],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleTypeInheritingMultipleInterface()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('type Hello implements Wo & rld { field: String }');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 5, 'end' => 10]),\n                    'interfaces'  => [\n                        $this->typeNode('Wo', ['start' => 22, 'end' => 24]),\n                        $this->typeNode('rld', ['start' => 27, 'end' => 30]),\n                    ],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNode(\n                            $this->nameNode('field', ['start' => 33, 'end' => 38]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 40, 'end' => 46]),\n                            ['start' => 33, 'end' => 46]\n                        ),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 48],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 48],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleTypeInheritingMultipleInterfaceWithLeadingAmpersand()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('type Hello implements & Wo & rld { field: String }');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 5, 'end' => 10]),\n                    'interfaces'  => [\n                        $this->typeNode('Wo', ['start' => 24, 'end' => 26]),\n                        $this->typeNode('rld', ['start' => 29, 'end' => 32]),\n                    ],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNode(\n                            $this->nameNode('field', ['start' => 35, 'end' => 40]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 42, 'end' => 48]),\n                            ['start' => 35, 'end' => 48]\n                        ),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 50],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 50],\n        ]), $node->toJSON());\n    }\n\n    public function testSingleValueEnum()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('enum Hello { WORLD }');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::ENUM_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 5, 'end' => 10]),\n                    'directives'  => [],\n                    'values'      => [\n                        $this->enumValueNode('WORLD', ['start' => 13, 'end' => 18]),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 20],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 20],\n        ]), $node->toJSON());\n    }\n\n    public function testDoubleValueEnum()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('enum Hello { WO, RLD }');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::ENUM_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 5, 'end' => 10]),\n                    'directives'  => [],\n                    'values'      => [\n                        $this->enumValueNode('WO', ['start' => 13, 'end' => 15]),\n                        $this->enumValueNode('RLD', ['start' => 17, 'end' => 20]),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 22],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 22],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleInterface()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ninterface Hello {\n  world: String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::INTERFACE_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 11, 'end' => 16]),\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNode(\n                            $this->nameNode('world', ['start' => 21, 'end' => 26]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 28, 'end' => 34]),\n                            ['start' => 21, 'end' => 34]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 36],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 36],\n        ]), $node->toJSON());\n    }\n\n    public function parseSimpleFieldWithArgument()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ntype Hello {\n  world(flag: Boolean): String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'interfaces'  => [],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNodeWithArguments(\n                            $this->nameNode('world', ['start' => 16, 'end' => 21]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 45, 'end' => 51]),\n                            [\n                                $this->inputValueNode(\n                                    $this->nameNode('flag', ['start' => 22, 'end' => 26]),\n                                    $this->typeNode(TypeNameEnum::BOOLEAN, ['start' => 28, 'end' => 35]),\n                                    null,\n                                    ['start' => 22, 'end' => 35]\n                                ),\n                            ],\n                            ['start' => 16, 'end' => 44]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 46],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 46],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleFieldWithArgumentWithDefaultValue()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ntype Hello {\n  world(flag: Boolean = true): String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'interfaces'  => [],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNodeWithArguments(\n                            $this->nameNode('world', ['start' => 16, 'end' => 21]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 45, 'end' => 51]),\n                            [\n                                $this->inputValueNode(\n                                    $this->nameNode('flag', ['start' => 22, 'end' => 26]),\n                                    $this->typeNode(TypeNameEnum::BOOLEAN, ['start' => 28, 'end' => 35]),\n                                    [\n                                        'kind'  => NodeKindEnum::BOOLEAN,\n                                        'value' => true,\n                                        'loc'   => ['start' => 38, 'end' => 42],\n                                    ],\n                                    ['start' => 22, 'end' => 42]\n                                ),\n                            ],\n                            ['start' => 16, 'end' => 51]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 53],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 53],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleFieldWithListArgument()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ntype Hello {\n  world(things: [String]): String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'interfaces'  => [],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNodeWithArguments(\n                            $this->nameNode('world', ['start' => 16, 'end' => 21]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 41, 'end' => 47]),\n                            [\n                                $this->inputValueNode(\n                                    $this->nameNode('things', ['start' => 22, 'end' => 28]),\n                                    [\n                                        'kind' => NodeKindEnum::LIST_TYPE,\n                                        'type' => $this->typeNode(TypeNameEnum::STRING, ['start' => 31, 'end' => 37]),\n                                        'loc'  => ['start' => 30, 'end' => 38],\n                                    ],\n                                    null,\n                                    ['start' => 22, 'end' => 38]\n                                ),\n                            ],\n                            ['start' => 16, 'end' => 47]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 49],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 49],\n        ]), $node->toJSON());\n    }\n\n    public function parseSimpleFieldWithTwoArguments()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ntype Hello {\n  world(argOne: Boolean, argTwo: Int): String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'interfaces'  => [],\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->fieldNodeWithArguments(\n                            $this->nameNode('world', ['start' => 16, 'end' => 21]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 53, 'end' => 59]),\n                            [\n                                $this->inputValueNode(\n                                    $this->nameNode('argOne', ['start' => 22, 'end' => 28]),\n                                    $this->typeNode(TypeNameEnum::BOOLEAN, ['start' => 30, 'end' => 37]),\n                                    null,\n                                    ['start' => 22, 'end' => 37]\n                                ),\n                                $this->inputValueNode(\n                                    $this->nameNode('argTwo', ['start' => 39, 'end' => 45]),\n                                    $this->typeNode(TypeNameEnum::INT, ['start' => 47, 'end' => 50]),\n                                    null,\n                                    ['start' => 39, 'end' => 50]\n                                ),\n                            ],\n                            ['start' => 16, 'end' => 59]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 61],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 61],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleUnion()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('union Hello = World');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::UNION_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'directives'  => [],\n                    'types'       => [\n                        $this->typeNode('World', ['start' => 14, 'end' => 19]),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 19],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 19],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleUnionWithTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('union Hello = Wo | Rld');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::UNION_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'directives'  => [],\n                    'types'       => [\n                        $this->typeNode('Wo', ['start' => 14, 'end' => 16]),\n                        $this->typeNode('Rld', ['start' => 19, 'end' => 22]),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 22],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 22],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleUnionWithTypesAndLeadingPipe()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('union Hello = | Wo | Rld');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::UNION_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),\n                    'directives'  => [],\n                    'types'       => [\n                        $this->typeNode('Wo', ['start' => 16, 'end' => 18]),\n                        $this->typeNode('Rld', ['start' => 21, 'end' => 24]),\n                    ],\n                    'loc'         => ['start' => 0, 'end' => 24],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 24],\n        ]), $node->toJSON());\n    }\n\n    public function testUnionFailsWithNoTypes()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected Name, found <EOF>');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('union Hello = |');\n    }\n\n    public function testUnionFailsWithLeadingDoublePipe()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected Name, found |');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('union Hello = || Wo | Rld');\n    }\n\n    public function testUnionFailsWithTrailingPipe()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected Name, found <EOF>');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('union Hello = | Wo | Rld |');\n    }\n\n    public function testSimpleScalar()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('scalar Hello');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::SCALAR_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 7, 'end' => 12]),\n                    'directives'  => [],\n                    'loc'         => ['start' => 0, 'end' => 12],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 12],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleInputObject()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\ninput Hello {\n  world: String\n}');\n\n        $this->assertEquals(jsonEncode([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                [\n                    'kind'        => NodeKindEnum::INPUT_OBJECT_TYPE_DEFINITION,\n                    'description' => null,\n                    'name'        => $this->nameNode('Hello', ['start' => 7, 'end' => 12]),\n                    'directives'  => [],\n                    'fields'      => [\n                        $this->inputValueNode(\n                            $this->nameNode('world', ['start' => 17, 'end' => 22]),\n                            $this->typeNode(TypeNameEnum::STRING, ['start' => 24, 'end' => 30]),\n                            null,\n                            ['start' => 17, 'end' => 30]\n                        ),\n                    ],\n                    'loc'         => ['start' => 1, 'end' => 32],\n                ],\n            ],\n            'loc'         => ['start' => 0, 'end' => 32],\n        ]), $node->toJSON());\n    }\n\n    public function testSimpleInputObjectWithArgumentsShouldFail()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Expected :, found (');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('\ninput Hello {\n  world(foo: Int): String\n}');\n    }\n\n    public function testDirectiveWithIncorrectLocations()\n    {\n        $this->expectException(SyntaxErrorException::class);\n        $this->expectExceptionMessage('Unexpected Name \"INCORRECT_LOCATION\"');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        parse('\ndirective @foo on FIELD | INCORRECT_LOCATION');\n    }\n\n    protected function typeNode($name, $loc)\n    {\n        return [\n            'kind' => NodeKindEnum::NAMED_TYPE,\n            'name' => $this->nameNode($name, $loc),\n            'loc'  => $loc,\n        ];\n    }\n\n    protected function nameNode($name, $loc)\n    {\n        return [\n            'kind'  => NodeKindEnum::NAME,\n            'value' => $name,\n            'loc'   => $loc,\n        ];\n    }\n\n    protected function fieldNode($name, $type, $loc)\n    {\n        return $this->fieldNodeWithArguments($name, $type, [], $loc);\n    }\n\n    protected function fieldNodeWithArguments($name, $type, $arguments, $loc)\n    {\n        return [\n            'kind'        => NodeKindEnum::FIELD_DEFINITION,\n            'description' => null,\n            'name'        => $name,\n            'arguments'   => $arguments,\n            'type'        => $type,\n            'directives'  => [],\n            'loc'         => $loc,\n        ];\n    }\n\n    protected function enumValueNode($name, $loc)\n    {\n        return [\n            'kind'        => NodeKindEnum::ENUM_VALUE_DEFINITION,\n            'description' => null,\n            'name'        => $this->nameNode($name, $loc),\n            'directives'  => [],\n            'loc'         => $loc,\n        ];\n    }\n\n    protected function inputValueNode($name, $type, $defaultValue, $loc)\n    {\n        return [\n            'kind'         => NodeKindEnum::INPUT_VALUE_DEFINITION,\n            'description'  => null,\n            'name'         => $name,\n            'type'         => $type,\n            'defaultValue' => $defaultValue,\n            'directives'   => [],\n            'loc'          => $loc,\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Language/SchemaPrinterTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\printNode;\nuse function Digia\\GraphQL\\Test\\readFileContents;\n\nclass SchemaPrinterTest extends TestCase\n{\n    public function testDoesNotAlterAST()\n    {\n        // This test seems kind of dumb test, but it makes sure that our parser\n        // can handle the kitchen sink schema.\n\n        $kitchenSink = readFileContents(__DIR__ . '/schema-kitchen-sink.graphqls');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse($kitchenSink);\n\n        $astBefore = $ast->toJSON();\n\n        printNode($ast);\n\n        $this->assertEquals($ast->toJSON(), $astBefore);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Language/StringSourceBuilderTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\Language\\StringSourceBuilder;\nuse Digia\\GraphQL\\Test\\TestCase;\n\nclass StringSourceBuilderTest extends TestCase\n{\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testBuild(): void\n    {\n        $body = \\file_get_contents(__DIR__ . '/schema-kitchen-sink.graphqls');\n\n        $builder = new StringSourceBuilder($body);\n        $source  = $builder->build();\n\n        $this->assertGreaterThan(0, $source->getBodyLength());\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Language/VisitorTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Language;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeInterface;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\NodeBuilderInterface;\nuse Digia\\GraphQL\\Language\\Visitor\\ParallelVisitor;\nuse Digia\\GraphQL\\Language\\Visitor\\TypeInfoVisitor;\nuse Digia\\GraphQL\\Language\\Visitor\\Visitor;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorBreak;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorInfo;\nuse Digia\\GraphQL\\Language\\Visitor\\VisitorResult;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\CompositeTypeInterface;\nuse Digia\\GraphQL\\Util\\TypeInfo;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\testSchema;\nuse function Digia\\GraphQL\\Test\\readFileContents;\nuse function Digia\\GraphQL\\Type\\getNamedType;\n\nclass VisitorTest extends TestCase\n{\n    public function testValidatesPathArgument()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a }');\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['enter', array_slice($node->getVisitorInfo()->getPath(), 0)];\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['leave', array_slice($node->getVisitorInfo()->getPath(), 0)];\n\n                return new VisitorResult($node);\n            }\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast->acceptVisitor(new VisitorInfo($visitor));\n\n        $this->assertEquals([\n            ['enter', []],\n            ['enter', ['definitions', 0]],\n            ['enter', ['definitions', 0, 'selectionSet']],\n            ['enter', ['definitions', 0, 'selectionSet', 'selections', 0]],\n            ['enter', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],\n            ['leave', ['definitions', 0, 'selectionSet', 'selections', 0, 'name']],\n            ['leave', ['definitions', 0, 'selectionSet', 'selections', 0]],\n            ['leave', ['definitions', 0, 'selectionSet']],\n            ['leave', ['definitions', 0]],\n            ['leave', []],\n        ], $visited);\n    }\n\n    public function testAllowsForEditingOnEnter()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $document = parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node): VisitorResult {\n                if ($node instanceof FieldNode && $node->getNameValue() === 'b') {\n                    return new VisitorResult(null, VisitorResult::ACTION_REPLACE);\n                }\n\n                return new VisitorResult($node);\n            }\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $editedDocument = $document->acceptVisitor(new VisitorInfo($visitor));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(\n            parse('{ a, b, c { a, b, c } }', ['noLocation' => true])->toArray(),\n            $document->toAST()\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(\n            parse('{ a,    c { a,    c } }', ['noLocation' => true])->toArray(),\n            $editedDocument->toAST()\n        );\n    }\n\n    public function testAllowsForEditingOnLeave()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $document = parse('{ a, b, c { a, b, c } }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            null,\n            function (NodeInterface $node): VisitorResult {\n                if ($node instanceof FieldNode && $node->getNameValue() === 'b') {\n                    return new VisitorResult(null, VisitorResult::ACTION_REPLACE);\n                }\n\n                return new VisitorResult($node);\n            }\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $editedDocument = $document->acceptVisitor(new VisitorInfo($visitor));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(\n            parse('{ a, b, c { a, b, c } }', ['noLocation' => true])->toArray(),\n            $document->toAST()\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(\n            parse('{ a,    c { a,    c } }', ['noLocation' => true])->toArray(),\n            $editedDocument->toAST()\n        );\n    }\n\n    public function testVisitsEditedNode()\n    {\n        $addedField = new AddedFieldNode(\n            null,\n            new NameNode('__typename', null),\n            [],\n            [],\n            null,\n            null\n        );\n\n        $didVisitEditedNode = false;\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a { x } }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$didVisitEditedNode, $addedField): VisitorResult {\n                if ($node instanceof FieldNode && $node->getNameValue() === 'a') {\n                    return new VisitorResult($addedField);\n                }\n\n                if ($node instanceof AddedFieldNode) {\n                    $didVisitEditedNode = true;\n                }\n\n                return new VisitorResult($node);\n            }\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast->acceptVisitor(new VisitorInfo($visitor));\n\n        $this->assertTrue($didVisitEditedNode);\n    }\n\n    public function testAllowsSkippingSubTree()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                if ($node instanceof FieldNode && $node->getNameValue() === 'b') {\n                    return new VisitorResult(null);\n                }\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                return new VisitorResult($node);\n            }\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast->acceptVisitor(new VisitorInfo($visitor));\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'OperationDefinition', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['leave', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'c'],\n            ['leave', 'Name', 'c'],\n            ['leave', 'Field', null],\n            ['leave', 'SelectionSet', null],\n            ['leave', 'OperationDefinition', null],\n            ['leave', 'Document', null],\n        ], $visited);\n    }\n\n    public function testAllowsEarlyExitWhileVisiting()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                if ($node instanceof NameNode && $node->getValue() === 'x') {\n                    return new VisitorResult($node, VisitorResult::ACTION_BREAK);\n                }\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                return new VisitorResult($node);\n            }\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'OperationDefinition', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['leave', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'b'],\n            ['leave', 'Name', 'b'],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'x'],\n        ], $visited);\n    }\n\n    public function testAllowsEarlyExitWhileLeaving()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                if ($node instanceof NameNode && $node->getValue() === 'x') {\n                    return new VisitorResult($node, VisitorResult::ACTION_BREAK);\n                }\n\n                return new VisitorResult($node);\n            }\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'OperationDefinition', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['leave', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'b'],\n            ['leave', 'Name', 'b'],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'x'],\n            ['leave', 'Name', 'x'],\n        ], $visited);\n    }\n\n    public function testAllowsAKindVisitor()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                if ($node instanceof NameNode || $node instanceof SelectionSetNode) {\n                    $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n                }\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                if ($node instanceof SelectionSetNode) {\n                    $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n                }\n\n                return new VisitorResult($node);\n            }\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Name', 'a'],\n            ['enter', 'Name', 'b'],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Name', 'x'],\n            ['leave', 'SelectionSet', null],\n            ['enter', 'Name', 'c'],\n            ['leave', 'SelectionSet', null],\n        ], $visited);\n    }\n\n    public function testVisitsVariablesDefinedInFragments()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('fragment a($v: Boolean = false) on t { f }', ['noLocation' => true]);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                return new VisitorResult($node);\n            }\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'FragmentDefinition', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['enter', 'VariableDefinition', null],\n            ['enter', 'Variable', null],\n            ['enter', 'Name', 'v'],\n            ['leave', 'Name', 'v'],\n            ['leave', 'Variable', null],\n            ['enter', 'NamedType', null],\n            ['enter', 'Name', 'Boolean'],\n            ['leave', 'Name', 'Boolean'],\n            ['leave', 'NamedType', null],\n            ['enter', 'BooleanValue', false],\n            ['leave', 'BooleanValue', false],\n            ['leave', 'VariableDefinition', null],\n            ['enter', 'NamedType', null],\n            ['enter', 'Name', 't'],\n            ['leave', 'Name', 't'],\n            ['leave', 'NamedType', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'f'],\n            ['leave', 'Name', 'f'],\n            ['leave', 'Field', null],\n            ['leave', 'SelectionSet', null],\n            ['leave', 'FragmentDefinition', null],\n            ['leave', 'Document', null],\n        ], $visited);\n    }\n\n    public function testVisitsKitchenSink()\n    {\n        $visited = [];\n\n        $kitchenSink = readFileContents(__DIR__ . '/kitchen-sink.graphql');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse($kitchenSink);\n\n        $visitor = new Visitor(\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $key       = $node->getVisitorInfo()->getKey();\n                $parent    = $node->getVisitorInfo()->getParent();\n                $visited[] = ['enter', $node->getKind(), $key, $parent ? $parent->getKind() : null];\n\n                return new VisitorResult($node);\n            },\n            function (NodeInterface $node) use (&$visited): VisitorResult {\n                $key       = $node->getVisitorInfo()->getKey();\n                $parent    = $node->getVisitorInfo()->getParent();\n                $visited[] = ['leave', $node->getKind(), $key, $parent ? $parent->getKind() : null];\n\n                return new VisitorResult($node);\n            }\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null, null],\n            ['enter', 'OperationDefinition', 0, null],\n            ['enter', 'Name', 'name', 'OperationDefinition'],\n            ['leave', 'Name', 'name', 'OperationDefinition'],\n            ['enter', 'VariableDefinition', 0, null],\n            ['enter', 'Variable', 'variable', 'VariableDefinition'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'variable', 'VariableDefinition'],\n            ['enter', 'NamedType', 'type', 'VariableDefinition'],\n            ['enter', 'Name', 'name', 'NamedType'],\n            ['leave', 'Name', 'name', 'NamedType'],\n            ['leave', 'NamedType', 'type', 'VariableDefinition'],\n            ['leave', 'VariableDefinition', 0, null],\n            ['enter', 'VariableDefinition', 1, null],\n            ['enter', 'Variable', 'variable', 'VariableDefinition'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'variable', 'VariableDefinition'],\n            ['enter', 'NamedType', 'type', 'VariableDefinition'],\n            ['enter', 'Name', 'name', 'NamedType'],\n            ['leave', 'Name', 'name', 'NamedType'],\n            ['leave', 'NamedType', 'type', 'VariableDefinition'],\n            ['enter', 'EnumValue', 'defaultValue', 'VariableDefinition'],\n            ['leave', 'EnumValue', 'defaultValue', 'VariableDefinition'],\n            ['leave', 'VariableDefinition', 1, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'alias', 'Field'],\n            ['leave', 'Name', 'alias', 'Field'],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'ListValue', 'value', 'Argument'],\n            ['enter', 'IntValue', 0, null],\n            ['leave', 'IntValue', 0, null],\n            ['enter', 'IntValue', 1, null],\n            ['leave', 'IntValue', 1, null],\n            ['leave', 'ListValue', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['enter', 'InlineFragment', 1, null],\n            ['enter', 'NamedType', 'typeCondition', 'InlineFragment'],\n            ['enter', 'Name', 'name', 'NamedType'],\n            ['leave', 'Name', 'name', 'NamedType'],\n            ['leave', 'NamedType', 'typeCondition', 'InlineFragment'],\n            ['enter', 'Directive', 0, null],\n            ['enter', 'Name', 'name', 'Directive'],\n            ['leave', 'Name', 'name', 'Directive'],\n            ['leave', 'Directive', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['enter', 'Field', 1, null],\n            ['enter', 'Name', 'alias', 'Field'],\n            ['leave', 'Name', 'alias', 'Field'],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'IntValue', 'value', 'Argument'],\n            ['leave', 'IntValue', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['enter', 'Argument', 1, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'Variable', 'value', 'Argument'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'value', 'Argument'],\n            ['leave', 'Argument', 1, null],\n            ['enter', 'Directive', 0, null],\n            ['enter', 'Name', 'name', 'Directive'],\n            ['leave', 'Name', 'name', 'Directive'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'Variable', 'value', 'Argument'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['leave', 'Directive', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['enter', 'FragmentSpread', 1, null],\n            ['enter', 'Name', 'name', 'FragmentSpread'],\n            ['leave', 'Name', 'name', 'FragmentSpread'],\n            ['leave', 'FragmentSpread', 1, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 1, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'],\n            ['leave', 'InlineFragment', 1, null],\n            ['enter', 'InlineFragment', 2, null],\n            ['enter', 'Directive', 0, null],\n            ['enter', 'Name', 'name', 'Directive'],\n            ['leave', 'Name', 'name', 'Directive'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'Variable', 'value', 'Argument'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['leave', 'Directive', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'],\n            ['leave', 'InlineFragment', 2, null],\n            ['enter', 'InlineFragment', 3, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'],\n            ['leave', 'InlineFragment', 3, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['leave', 'OperationDefinition', 0, null],\n            ['enter', 'OperationDefinition', 1, null],\n            ['enter', 'Name', 'name', 'OperationDefinition'],\n            ['leave', 'Name', 'name', 'OperationDefinition'],\n            ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'IntValue', 'value', 'Argument'],\n            ['leave', 'IntValue', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['enter', 'Directive', 0, null],\n            ['enter', 'Name', 'name', 'Directive'],\n            ['leave', 'Name', 'name', 'Directive'],\n            ['leave', 'Directive', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['leave', 'OperationDefinition', 1, null],\n            ['enter', 'OperationDefinition', 2, null],\n            ['enter', 'Name', 'name', 'OperationDefinition'],\n            ['leave', 'Name', 'name', 'OperationDefinition'],\n            ['enter', 'VariableDefinition', 0, null],\n            ['enter', 'Variable', 'variable', 'VariableDefinition'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'variable', 'VariableDefinition'],\n            ['enter', 'NamedType', 'type', 'VariableDefinition'],\n            ['enter', 'Name', 'name', 'NamedType'],\n            ['leave', 'Name', 'name', 'NamedType'],\n            ['leave', 'NamedType', 'type', 'VariableDefinition'],\n            ['leave', 'VariableDefinition', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'Variable', 'value', 'Argument'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['enter', 'Field', 1, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'SelectionSet', 'selectionSet', 'Field'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 1, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'Field'],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['leave', 'OperationDefinition', 2, null],\n            ['enter', 'FragmentDefinition', 3, null],\n            ['enter', 'Name', 'name', 'FragmentDefinition'],\n            ['leave', 'Name', 'name', 'FragmentDefinition'],\n            ['enter', 'NamedType', 'typeCondition', 'FragmentDefinition'],\n            ['enter', 'Name', 'name', 'NamedType'],\n            ['leave', 'Name', 'name', 'NamedType'],\n            ['leave', 'NamedType', 'typeCondition', 'FragmentDefinition'],\n            ['enter', 'SelectionSet', 'selectionSet', 'FragmentDefinition'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'Variable', 'value', 'Argument'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['enter', 'Argument', 1, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'Variable', 'value', 'Argument'],\n            ['enter', 'Name', 'name', 'Variable'],\n            ['leave', 'Name', 'name', 'Variable'],\n            ['leave', 'Variable', 'value', 'Argument'],\n            ['leave', 'Argument', 1, null],\n            ['enter', 'Argument', 2, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'ObjectValue', 'value', 'Argument'],\n            ['enter', 'ObjectField', 0, null],\n            ['enter', 'Name', 'name', 'ObjectField'],\n            ['leave', 'Name', 'name', 'ObjectField'],\n            ['enter', 'StringValue', 'value', 'ObjectField'],\n            ['leave', 'StringValue', 'value', 'ObjectField'],\n            ['leave', 'ObjectField', 0, null],\n            ['enter', 'ObjectField', 1, null],\n            ['enter', 'Name', 'name', 'ObjectField'],\n            ['leave', 'Name', 'name', 'ObjectField'],\n            ['enter', 'StringValue', 'value', 'ObjectField'],\n            ['leave', 'StringValue', 'value', 'ObjectField'],\n            ['leave', 'ObjectField', 1, null],\n            ['leave', 'ObjectValue', 'value', 'Argument'],\n            ['leave', 'Argument', 2, null],\n            ['leave', 'Field', 0, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'FragmentDefinition'],\n            ['leave', 'FragmentDefinition', 3, null],\n            ['enter', 'OperationDefinition', 4, null],\n            ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['enter', 'Field', 0, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['enter', 'Argument', 0, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'BooleanValue', 'value', 'Argument'],\n            ['leave', 'BooleanValue', 'value', 'Argument'],\n            ['leave', 'Argument', 0, null],\n            ['enter', 'Argument', 1, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'BooleanValue', 'value', 'Argument'],\n            ['leave', 'BooleanValue', 'value', 'Argument'],\n            ['leave', 'Argument', 1, null],\n            ['enter', 'Argument', 2, null],\n            ['enter', 'Name', 'name', 'Argument'],\n            ['leave', 'Name', 'name', 'Argument'],\n            ['enter', 'NullValue', 'value', 'Argument'],\n            ['leave', 'NullValue', 'value', 'Argument'],\n            ['leave', 'Argument', 2, null],\n            ['leave', 'Field', 0, null],\n            ['enter', 'Field', 1, null],\n            ['enter', 'Name', 'name', 'Field'],\n            ['leave', 'Name', 'name', 'Field'],\n            ['leave', 'Field', 1, null],\n            ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'],\n            ['leave', 'OperationDefinition', 4, null],\n            ['leave', 'Document', null, null],\n        ], $visited);\n    }\n\n    public function testVisitInParallel()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }');\n\n        $visitor = new ParallelVisitor([\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                    if ($node instanceof FieldNode && $node->getNameValue() === 'b') {\n                        return new VisitorResult(null);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                    return new VisitorResult($node);\n                }\n            ),\n        ]);\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'OperationDefinition', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['leave', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'c'],\n            ['leave', 'Name', 'c'],\n            ['leave', 'Field', null],\n            ['leave', 'SelectionSet', null],\n            ['leave', 'OperationDefinition', null],\n            ['leave', 'Document', null],\n        ], $visited);\n    }\n\n    public function testAllowsSkippingSubTreeWhenVisitingInParallel()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a { x }, b { y } }', ['noLocation' => true]);\n\n        $visitor = new ParallelVisitor([\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'no-a',\n                        'enter',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    if ($node instanceof FieldNode && $node->getNameValue() === 'a') {\n                        return new VisitorResult(null);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'no-a',\n                        'leave',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    return new VisitorResult($node);\n                }\n            ),\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'no-b',\n                        'enter',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    if ($node instanceof FieldNode && $node->getNameValue() === 'b') {\n                        return new VisitorResult(null);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'no-b',\n                        'leave',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    return new VisitorResult($node);\n                }\n            ),\n        ]);\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['no-a', 'enter', 'Document', null],\n            ['no-b', 'enter', 'Document', null],\n            ['no-a', 'enter', 'OperationDefinition', null],\n            ['no-b', 'enter', 'OperationDefinition', null],\n            ['no-a', 'enter', 'SelectionSet', null],\n            ['no-b', 'enter', 'SelectionSet', null],\n            ['no-a', 'enter', 'Field', null],\n            ['no-b', 'enter', 'Field', null],\n            ['no-b', 'enter', 'Name', 'a'],\n            ['no-b', 'leave', 'Name', 'a'],\n            ['no-b', 'enter', 'SelectionSet', null],\n            ['no-b', 'enter', 'Field', null],\n            ['no-b', 'enter', 'Name', 'x'],\n            ['no-b', 'leave', 'Name', 'x'],\n            ['no-b', 'leave', 'Field', null],\n            ['no-b', 'leave', 'SelectionSet', null],\n            ['no-b', 'leave', 'Field', null],\n            ['no-a', 'enter', 'Field', null],\n            ['no-b', 'enter', 'Field', null],\n            ['no-a', 'enter', 'Name', 'b'],\n            ['no-a', 'leave', 'Name', 'b'],\n            ['no-a', 'enter', 'SelectionSet', null],\n            ['no-a', 'enter', 'Field', null],\n            ['no-a', 'enter', 'Name', 'y'],\n            ['no-a', 'leave', 'Name', 'y'],\n            ['no-a', 'leave', 'Field', null],\n            ['no-a', 'leave', 'SelectionSet', null],\n            ['no-a', 'leave', 'Field', null],\n            ['no-a', 'leave', 'SelectionSet', null],\n            ['no-b', 'leave', 'SelectionSet', null],\n            ['no-a', 'leave', 'OperationDefinition', null],\n            ['no-b', 'leave', 'OperationDefinition', null],\n            ['no-a', 'leave', 'Document', null],\n            ['no-b', 'leave', 'Document', null],\n        ], $visited);\n    }\n\n    public function testAllowsEarlyExitWhileEnteringWhenVisitingInParallel()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }', ['noLocation' => true]);\n\n        $visitor = new ParallelVisitor([\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                    if ($node instanceof NameNode && $node->getValue() === 'x') {\n                        return new VisitorResult($node, VisitorResult::ACTION_BREAK);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                    return new VisitorResult($node);\n                }\n            ),\n        ]);\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'OperationDefinition', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['leave', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'b'],\n            ['leave', 'Name', 'b'],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'x'],\n        ], $visited);\n    }\n\n    public function testAllowsEarlyExitWhileLeavingWhenVisitingInParallel()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a, b { x }, c }', ['noLocation' => true]);\n\n        $visitor = new ParallelVisitor([\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = ['enter', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = ['leave', $node->getKind(), $node instanceof NameNode ? $node->getValue() : null];\n\n                    if ($node instanceof NameNode && $node->getValue() === 'x') {\n                        return new VisitorResult($node, VisitorResult::ACTION_BREAK);\n                    }\n\n                    return new VisitorResult($node);\n                }\n            ),\n        ]);\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null],\n            ['enter', 'OperationDefinition', null],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'a'],\n            ['leave', 'Name', 'a'],\n            ['leave', 'Field', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'b'],\n            ['leave', 'Name', 'b'],\n            ['enter', 'SelectionSet', null],\n            ['enter', 'Field', null],\n            ['enter', 'Name', 'x'],\n            ['leave', 'Name', 'x'],\n        ], $visited);\n    }\n\n    public function testAllowsEarlyExitFromDifferentPointsWhenVisitingInParallel()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ a { y }, b { x } }', ['noLocation' => true]);\n\n        $visitor = new ParallelVisitor([\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'break-a',\n                        'enter',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    if ($node instanceof NameNode && $node->getValue() === 'a') {\n                        return new VisitorResult($node, VisitorResult::ACTION_BREAK);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'break-a',\n                        'leave',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    return new VisitorResult($node);\n                }\n            ),\n            new Visitor(\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'break-b',\n                        'enter',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    if ($node instanceof NameNode && $node->getValue() === 'b') {\n                        return new VisitorResult($node, VisitorResult::ACTION_BREAK);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited): VisitorResult {\n                    $visited[] = [\n                        'break-b',\n                        'leave',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null\n                    ];\n\n                    return new VisitorResult($node);\n                }\n            ),\n        ]);\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['break-a', 'enter', 'Document', null],\n            ['break-b', 'enter', 'Document', null],\n            ['break-a', 'enter', 'OperationDefinition', null],\n            ['break-b', 'enter', 'OperationDefinition', null],\n            ['break-a', 'enter', 'SelectionSet', null],\n            ['break-b', 'enter', 'SelectionSet', null],\n            ['break-a', 'enter', 'Field', null],\n            ['break-b', 'enter', 'Field', null],\n            ['break-a', 'enter', 'Name', 'a'],\n            ['break-b', 'enter', 'Name', 'a'],\n            ['break-b', 'leave', 'Name', 'a'],\n            ['break-b', 'enter', 'SelectionSet', null],\n            ['break-b', 'enter', 'Field', null],\n            ['break-b', 'enter', 'Name', 'y'],\n            ['break-b', 'leave', 'Name', 'y'],\n            ['break-b', 'leave', 'Field', null],\n            ['break-b', 'leave', 'SelectionSet', null],\n            ['break-b', 'leave', 'Field', null],\n            ['break-b', 'enter', 'Field', null],\n            ['break-b', 'enter', 'Name', 'b'],\n        ], $visited);\n    }\n\n    public function testMaintainsTypeInfoDuringVisit()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ human(id: 4) { name, pets { ... { name } }, unknown } }');\n\n        $typeInfo = new TypeInfo(testSchema());\n        $visitor  = new TypeInfoVisitor(\n            $typeInfo,\n            new Visitor(\n                function (NodeInterface $node) use (&$visited, $typeInfo): VisitorResult {\n                    $parentType = $typeInfo->getParentType();\n                    $type       = $typeInfo->getType();\n                    $inputType  = $typeInfo->getInputType();\n                    $visited[]  = [\n                        'enter',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null,\n                        $parentType ? (string)$parentType : null,\n                        $type ? (string)$type : null,\n                        $inputType ? (string)$inputType : null,\n                    ];\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited, $typeInfo): VisitorResult {\n                    $parentType = $typeInfo->getParentType();\n                    $type       = $typeInfo->getType();\n                    $inputType  = $typeInfo->getInputType();\n                    $visited[]  = [\n                        'leave',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null,\n                        $parentType ? (string)$parentType : null,\n                        $type ? (string)$type : null,\n                        $inputType ? (string)$inputType : null,\n                    ];\n\n                    return new VisitorResult($node);\n                }\n            )\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        $this->assertEquals([\n            ['enter', 'Document', null, null, null, null],\n            ['enter', 'OperationDefinition', null, null, 'QueryRoot', null],\n            ['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],\n            ['enter', 'Field', null, 'QueryRoot', 'Human', null],\n            ['enter', 'Name', 'human', 'QueryRoot', 'Human', null],\n            ['leave', 'Name', 'human', 'QueryRoot', 'Human', null],\n            ['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'],\n            ['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],\n            ['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],\n            ['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],\n            ['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],\n            ['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'],\n            ['enter', 'SelectionSet', null, 'Human', 'Human', null],\n            ['enter', 'Field', null, 'Human', 'String', null],\n            ['enter', 'Name', 'name', 'Human', 'String', null],\n            ['leave', 'Name', 'name', 'Human', 'String', null],\n            ['leave', 'Field', null, 'Human', 'String', null],\n            ['enter', 'Field', null, 'Human', '[Pet]', null],\n            ['enter', 'Name', 'pets', 'Human', '[Pet]', null],\n            ['leave', 'Name', 'pets', 'Human', '[Pet]', null],\n            ['enter', 'SelectionSet', null, 'Pet', '[Pet]', null],\n            ['enter', 'InlineFragment', null, 'Pet', 'Pet', null],\n            ['enter', 'SelectionSet', null, 'Pet', 'Pet', null],\n            ['enter', 'Field', null, 'Pet', 'String', null],\n            ['enter', 'Name', 'name', 'Pet', 'String', null],\n            ['leave', 'Name', 'name', 'Pet', 'String', null],\n            ['leave', 'Field', null, 'Pet', 'String', null],\n            ['leave', 'SelectionSet', null, 'Pet', 'Pet', null],\n            ['leave', 'InlineFragment', null, 'Pet', 'Pet', null],\n            ['leave', 'SelectionSet', null, 'Pet', '[Pet]', null],\n            ['leave', 'Field', null, 'Human', '[Pet]', null],\n            ['enter', 'Field', null, 'Human', null, null],\n            ['enter', 'Name', 'unknown', 'Human', null, null],\n            ['leave', 'Name', 'unknown', 'Human', null, null],\n            ['leave', 'Field', null, 'Human', null, null],\n            ['leave', 'SelectionSet', null, 'Human', 'Human', null],\n            ['leave', 'Field', null, 'QueryRoot', 'Human', null],\n            ['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],\n            ['leave', 'OperationDefinition', null, null, 'QueryRoot', null],\n            ['leave', 'Document', null, null, null, null],\n        ], $visited);\n    }\n\n    public function testMaintainsTypeInfoDuringEdit()\n    {\n        $visited = [];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $ast = parse('{ human(id: 4) { name, pets }, alien }');\n\n        $nodeBuilder = GraphQL::make(NodeBuilderInterface::class);\n\n        $typeInfo = new TypeInfo(testSchema());\n        $visitor  = new TypeInfoVisitor(\n            $typeInfo,\n            new Visitor(\n                function (NodeInterface $node) use (&$visited, $typeInfo, $nodeBuilder): VisitorResult {\n                    $parentType = $typeInfo->getParentType();\n                    $type       = $typeInfo->getType();\n                    $inputType  = $typeInfo->getInputType();\n\n                    $visited[] = [\n                        'enter',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null,\n                        $parentType ? (string)$parentType : null,\n                        $type ? (string)$type : null,\n                        $inputType ? (string)$inputType : null,\n                    ];\n\n                    if ($node instanceof FieldNode\n                        && null === $node->getSelectionSet()\n                        && getNamedType($type) instanceof CompositeTypeInterface\n                    ) {\n                        return new VisitorResult($nodeBuilder->build([\n                            'kind'         => NodeKindEnum::FIELD,\n                            'alias'        => $node->getAliasAST(),\n                            'name'         => $node->getNameAST(),\n                            'arguments'    => $node->getArgumentsAST(),\n                            'directives'   => $node->getDirectivesAST(),\n                            'selectionSet' => [\n                                'kind'   => NodeKindEnum::SELECTION_SET,\n                                'fields' => [\n                                    [\n                                        'kind' => NodeKindEnum::FIELD,\n                                        'name' => ['value' => '__typename'],\n                                    ]\n                                ]\n                            ],\n                        ]), VisitorResult::ACTION_REPLACE);\n                    }\n\n                    return new VisitorResult($node);\n                },\n                function (NodeInterface $node) use (&$visited, $typeInfo): VisitorResult {\n                    $parentType = $typeInfo->getParentType();\n                    $type       = $typeInfo->getType();\n                    $inputType  = $typeInfo->getInputType();\n\n                    $visited[] = [\n                        'leave',\n                        $node->getKind(),\n                        $node instanceof NameNode ? $node->getValue() : null,\n                        $parentType ? (string)$parentType : null,\n                        $type ? (string)$type : null,\n                        $inputType ? (string)$inputType : null,\n                    ];\n\n                    return new VisitorResult($node);\n                }\n            )\n        );\n\n        try {\n            $ast->acceptVisitor(new VisitorInfo($visitor));\n        } catch (VisitorBreak $e) {\n        }\n\n        // TODO: Add asserts for print once the printer is implemented\n\n        $this->markTestIncomplete('BUG: Nodes added by visitors are visited either too early or too late.');\n\n        $this->assertEquals([\n            ['enter', 'Document', null, null, null, null],\n            ['enter', 'OperationDefinition', null, null, 'QueryRoot', null],\n            ['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],\n            ['enter', 'Field', null, 'QueryRoot', 'Human', null],\n            ['enter', 'Name', 'human', 'QueryRoot', 'Human', null],\n            ['leave', 'Name', 'human', 'QueryRoot', 'Human', null],\n            ['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'],\n            ['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],\n            ['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'],\n            ['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],\n            ['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'],\n            ['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'],\n            ['enter', 'SelectionSet', null, 'Human', 'Human', null],\n            ['enter', 'Field', null, 'Human', 'String', null],\n            ['enter', 'Name', 'name', 'Human', 'String', null],\n            ['leave', 'Name', 'name', 'Human', 'String', null],\n            ['leave', 'Field', null, 'Human', 'String', null],\n            ['enter', 'Field', null, 'Human', '[Pet]', null],\n            ['enter', 'Name', 'pets', 'Human', '[Pet]', null],\n            ['leave', 'Name', 'pets', 'Human', '[Pet]', null],\n            ['enter', 'SelectionSet', null, 'Pet', '[Pet]', null],\n            ['enter', 'Field', null, 'Pet', 'String!', null],\n            ['enter', 'Name', '__typename', 'Pet', 'String!', null],\n            ['leave', 'Name', '__typename', 'Pet', 'String!', null],\n            ['leave', 'Field', null, 'Pet', 'String!', null],\n            ['leave', 'SelectionSet', null, 'Pet', '[Pet]', null],\n            ['leave', 'Field', null, 'Human', '[Pet]', null],\n            ['leave', 'SelectionSet', null, 'Human', 'Human', null],\n            ['leave', 'Field', null, 'QueryRoot', 'Human', null],\n            ['enter', 'Field', null, 'QueryRoot', 'Alien', null],\n            ['enter', 'Name', 'alien', 'QueryRoot', 'Alien', null],\n            ['leave', 'Name', 'alien', 'QueryRoot', 'Alien', null],\n            ['enter', 'SelectionSet', null, 'Alien', 'Alien', null],\n            ['enter', 'Field', null, 'Alien', 'String!', null],\n            ['enter', 'Name', '__typename', 'Alien', 'String!', null],\n            ['leave', 'Name', '__typename', 'Alien', 'String!', null],\n            ['leave', 'Field', null, 'Alien', 'String!', null],\n            ['leave', 'SelectionSet', null, 'Alien', 'Alien', null],\n            ['leave', 'Field', null, 'QueryRoot', 'Alien', null],\n            ['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null],\n            ['leave', 'OperationDefinition', null, null, 'QueryRoot', null],\n            ['leave', 'Document', null, null, null, null],\n        ], $visited);\n    }\n}\n\nclass AddedFieldNode extends FieldNode\n{\n}\n"
  },
  {
    "path": "tests/Functional/Language/kitchen-sink.graphql",
    "content": "# Copyright (c) 2015-present, Facebook, Inc.\n#\n# This source code is licensed under the MIT license found in the\n# LICENSE file in the root directory of this source tree.\n\nquery queryName($foo: ComplexType, $site: Site = MOBILE) {\n  whoever123is: node(id: [123, 456]) {\n    id ,\n    ... on User @defer {\n      field2 {\n        id ,\n        alias: field1(first:10, after:$foo,) @include(if: $foo) {\n          id,\n          ...frag\n        }\n      }\n    }\n    ... @skip(unless: $foo) {\n      id\n    }\n    ... {\n      id\n    }\n  }\n}\n\nmutation likeStory {\n  like(story: 123) @defer {\n    story {\n      id\n    }\n  }\n}\n\nsubscription StoryLikeSubscription($input: StoryLikeSubscribeInput) {\n  storyLikeSubscribe(input: $input) {\n    story {\n      likers {\n        count\n      }\n      likeSentence {\n        text\n      }\n    }\n  }\n}\n\nfragment frag on Friend {\n  foo(size: $size, bar: $b, obj: {key: \"value\", block: \"\"\"\n\n      block string uses \\\"\"\"\n\n  \"\"\"})\n}\n\n{\n  unnamed(truthy: true, falsey: false, nullish: null),\n  query\n}\n"
  },
  {
    "path": "tests/Functional/Language/schema-kitchen-sink.graphqls",
    "content": "schema {\n  query: QueryType\n  mutation: MutationType\n}\n\n\"\"\"\nThis is a description\nof the `Foo` type.\n\"\"\"\ntype Foo implements Bar & Baz {\n  one: Type\n  two(argument: InputType!): Type\n  three(argument: InputType, other: String): Int\n  four(argument: String = \"string\"): String\n  five(argument: [String] = [\"string\", \"string\"]): String\n  six(argument: InputType = {key: \"value\"}): Type\n  seven(argument: Int = null): Type\n}\n\ntype AnnotatedObject @onObject(arg: \"value\") {\n  annotatedField(arg: Type = \"default\" @onArg): Type @onField\n}\n\ntype UndefinedType\n\nextend type Foo {\n  seven(argument: [String]): Type\n}\n\nextend type Foo @onType\n\ninterface Bar {\n  one: Type\n  four(argument: String = \"string\"): String\n}\n\ninterface AnnotatedInterface @onInterface {\n  annotatedField(arg: Type @onArg): Type @onField\n}\n\ninterface UndefinedInterface\n\nextend interface Bar {\n  two(argument: InputType!): Type\n}\n\nextend interface Bar @onInterface\n\nunion Feed = Story | Article | Advert\n\nunion AnnotatedUnion @onUnion = A | B\n\nunion AnnotatedUnionTwo @onUnion = | A | B\n\nunion UndefinedUnion\n\nextend union Feed = Photo | Video\n\nextend union Feed @onUnion\n\nscalar CustomScalar\n\nscalar AnnotatedScalar @onScalar\n\nextend scalar CustomScalar @onScalar\n\nenum Site {\n  DESKTOP\n  MOBILE\n}\n\nenum AnnotatedEnum @onEnum {\n  ANNOTATED_VALUE @onEnumValue\n  OTHER_VALUE\n}\n\nenum UndefinedEnum\n\nextend enum Site {\n  VR\n}\n\nextend enum Site @onEnum\n\ninput InputType {\n  key: String!\n  answer: Int = 42\n}\n\ninput AnnotatedInput @onInputObject {\n  annotatedField: Type @onField\n}\n\ninput UndefinedInput\n\nextend input InputType {\n  other: Float = 1.23e4\n}\n\nextend input InputType @onInputObject\n\ndirective @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\ndirective @include(if: Boolean!)\n  on FIELD\n    | FRAGMENT_SPREAD\n    | INLINE_FRAGMENT\n\ndirective @include2(if: Boolean!) on\n  | FIELD\n  | FRAGMENT_SPREAD\n  | INLINE_FRAGMENT\n"
  },
  {
    "path": "tests/Functional/QueryTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\graphql;\nuse function Digia\\GraphQL\\Language\\locationShorthandToArray;\n\nclass QueryTest extends TestCase\n{\n    // Star Wars Query Tests\n\n    // Basic Queries\n\n    // Correctly identifies R2-D2 as the hero of the Star Wars Saga\n\n    public function testCorrectlyIdentifiesR2D2AsTheHeroOfTheStarWarsSaga()\n    {\n        $query = '\n        query HeroNameQuery {\n          hero {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'hero' => [\n                    'name' => 'R2-D2',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Skip: \"Accepts an object with named properties to graphql()\"\n\n    // Allows us to query for the ID and friends of R2-D2\n\n    public function testAllowsUsToQueryForTheIDAndFieldsOfR2D2()\n    {\n        $query = '\n        query HeroNameQuery {\n          hero {\n            id\n            name\n            friends {\n              name\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'hero' => [\n                    'id'      => '2001',\n                    'name'    => 'R2-D2',\n                    'friends' => [\n                        ['name' => 'Luke Skywalker'],\n                        ['name' => 'Han Solo'],\n                        ['name' => 'Leia Organa'],\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Nested Queries\n\n    // Allows us to query for the friends of friends of R2-D2\n\n    public function testAllowsUsToQueryForTheFriendsOfFriendsOfR2D2()\n    {\n        $query = '\n        query HeroNameQuery {\n          hero {\n            name\n            friends {\n              name\n              appearsIn\n              friends {\n                name\n              }\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'hero' => [\n                    'name'    => 'R2-D2',\n                    'friends' => [\n                        [\n                            'name'      => 'Luke Skywalker',\n                            'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n                            'friends'   => [\n                                ['name' => 'Han Solo'],\n                                ['name' => 'Leia Organa'],\n                                ['name' => 'C-3PO'],\n                                ['name' => 'R2-D2'],\n                            ]\n                        ],\n                        [\n                            'name'      => 'Han Solo',\n                            'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n                            'friends'   => [\n                                ['name' => 'Luke Skywalker'],\n                                ['name' => 'Leia Organa'],\n                                ['name' => 'R2-D2'],\n                            ]\n                        ],\n                        [\n                            'name'      => 'Leia Organa',\n                            'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n                            'friends'   => [\n                                ['name' => 'Luke Skywalker'],\n                                ['name' => 'Han Solo'],\n                                ['name' => 'C-3PO'],\n                                ['name' => 'R2-D2'],\n                            ]\n                        ],\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    // Using IDs and query parameters to refetch objects\n\n    // Allows us to query for Luke Skywalker directly, using his ID\n\n    public function testAllowsUsToQueryForLukeSkywalkerDirectlyUsingHisID()\n    {\n        $query = '\n        query FetchLukeQuery {\n          human(id: \"1000\") {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'human' => [\n                    'name' => 'Luke Skywalker',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows us to create a generic query, then use it to fetch Luke Skywalker using his ID\n\n    public function testAllowsUsToCreateAGenericQueryThenUseItToFetchLukeSkywalkerUsingHisID()\n    {\n        $query = '\n        query FetchSomeIDQuery($someId: String!) {\n          human(id: $someId) {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query, null, null, ['someId' => '1000']);\n\n        $this->assertEquals([\n            'data' => [\n                'human' => [\n                    'name' => 'Luke Skywalker',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows us to create a generic query, then use it to fetch Han Solo using his ID\n\n    public function testAllowsUsToCreateAGenericQueryThenUseItToFetchHanSoloUsingHisID()\n    {\n        $query = '\n        query FetchSomeIDQuery($someId: String!) {\n          human(id: $someId) {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query, null, null, ['someId' => '1002']);\n\n        $this->assertEquals([\n            'data' => [\n                'human' => [\n                    'name' => 'Han Solo',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows us to create a generic query, then pass an invalid ID to get null back\n\n    public function testAllowsUsToCreateAGenericQueryThenPassAnInvalidIdToGetBackNull()\n    {\n        $query = '\n        query FetchSomeIDQuery($someId: String!) {\n          human(id: $someId) {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query, null, null, ['someId' => 'not a valid id']);\n\n        $this->assertEquals([\n            'data' => [\n                'human' => null,\n            ],\n        ], $result);\n    }\n\n    // Using aliases to change the key in the response\n\n    // Allows us to query for Luke, changing his key with an alias\n\n    public function testAllowsUsToQueryForLukeChangingHisKeyWithAnAlias()\n    {\n        $query = '\n        query FetchLukeAliased {\n          luke: human(id: \"1000\") {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'luke' => [\n                    'name' => 'Luke Skywalker',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows us to query for both Luke and Leia, using two root fields and an alias\n\n    public function testAllowsUsToQueryForBothLukeAndLeiaUsingTwoRootFieldsAndAnAlias()\n    {\n        $query = '\n        query FetchLukeAndLeiaAliased {\n          luke: human(id: \"1000\") {\n            name\n          }\n          leia: human(id: \"1003\") {\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'luke' => [\n                    'name' => 'Luke Skywalker',\n                ],\n                'leia' => [\n                    'name' => 'Leia Organa',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Uses fragments to express more complex queries\n\n    // Allows us to query using duplicated content\n\n    public function testAllowsUsToQueryUsingDuplicatedContent()\n    {\n        $query = '\n        query FetchLukeAndLeiaAliased {\n          luke: human(id: \"1000\") {\n            name\n            homePlanet\n          }\n          leia: human(id: \"1003\") {\n            name\n            homePlanet\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'luke' => [\n                    'name'       => 'Luke Skywalker',\n                    'homePlanet' => 'Tatooine',\n                ],\n                'leia' => [\n                    'name'       => 'Leia Organa',\n                    'homePlanet' => 'Alderaan',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows us to use a fragment to avoid duplicating content\n\n    public function testAllowsUstoUseAFragmentToAvoidDuplicatingContent()\n    {\n        $query = '\n        query FetchLukeAndLeiaAliased {\n          luke: human(id: \"1000\") {\n            ...HumanFragment\n          }\n          leia: human(id: \"1003\") {\n            ...HumanFragment\n          }\n        }\n        \n        fragment HumanFragment on Human {\n          name\n          homePlanet\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'luke' => [\n                    'name'       => 'Luke Skywalker',\n                    'homePlanet' => 'Tatooine',\n                ],\n                'leia' => [\n                    'name'       => 'Leia Organa',\n                    'homePlanet' => 'Alderaan',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Using __typename to find the type of an object\n\n    // Allows us to verify that R2-D2 is a droid\n\n    public function testAllowsUsToVerifyThatR2D2IsADroid()\n    {\n        $query = '\n        query CheckTypeOfR2 {\n          hero {\n            __typename\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'hero' => [\n                    '__typename' => 'Droid',\n                    'name'       => 'R2-D2',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Allows us to verify that Luke is a human\n\n    public function testAllowsUsToVerifyThatLukeIsAHuman()\n    {\n        $query = '\n        query CheckTypeOfLuke {\n          hero(episode: EMPIRE) {\n            __typename\n            name\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data' => [\n                'hero' => [\n                    '__typename' => 'Human',\n                    'name'       => 'Luke Skywalker',\n                ],\n            ],\n        ], $result);\n    }\n\n    // Reporting errors raised in resolvers\n\n    // Correctly reports error on accessing secretBackstory\n\n    public function testCorrectlyReportsErrorOnAccessingSecretBackstory()\n    {\n        $query = '\n        query HeroNameQuery {\n          hero {\n            name\n            secretBackstory\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data'   => [\n                'hero' => [\n                    'name'            => 'R2-D2',\n                    'secretBackstory' => null,\n                ],\n            ],\n            'errors' => [\n                [\n                    'message'   => 'secretBackstory is secret.',\n                    'locations' => [locationShorthandToArray([5, 13])],\n                    'path'      => ['hero', 'secretBackstory'],\n                ]\n            ],\n        ], $result);\n    }\n\n    // Correctly reports error on accessing secretBackstory in a list\n\n    public function testCorrectlyReportsErrorOnAccessingSecretBackstoryInAList()\n    {\n        $query = '\n        query HeroNameQuery {\n          hero {\n            name\n            friends {\n              name\n              secretBackstory\n            }\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data'   => [\n                'hero' => [\n                    'name'    => 'R2-D2',\n                    'friends' => [\n                        [\n                            'name'            => 'Luke Skywalker',\n                            'secretBackstory' => null,\n                        ],\n                        [\n                            'name'            => 'Han Solo',\n                            'secretBackstory' => null,\n                        ],\n                        [\n                            'name'            => 'Leia Organa',\n                            'secretBackstory' => null,\n                        ],\n                    ],\n                ],\n            ],\n            'errors' => [\n                [\n                    'message'   => 'secretBackstory is secret.',\n                    'locations' => [locationShorthandToArray([7, 15])],\n                    'path'      => ['hero', 'friends', 0, 'secretBackstory'],\n                ],\n                [\n                    'message'   => 'secretBackstory is secret.',\n                    'locations' => [locationShorthandToArray([7, 15])],\n                    'path'      => ['hero', 'friends', 1, 'secretBackstory'],\n                ],\n                [\n                    'message'   => 'secretBackstory is secret.',\n                    'locations' => [locationShorthandToArray([7, 15])],\n                    'path'      => ['hero', 'friends', 2, 'secretBackstory'],\n                ]\n            ],\n        ], $result);\n    }\n\n    // Correctly reports error on accessing through an alias\n\n    public function testCorrectlyReportsErrorOnAccessingThroughAnAlias()\n    {\n        $query = '\n        query HeroNameQuery {\n          mainHero: hero {\n            name\n            story: secretBackstory\n          }\n        }\n        ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql(starWarsSchema(), $query);\n\n        $this->assertEquals([\n            'data'   => [\n                'mainHero' => [\n                    'name'  => 'R2-D2',\n                    'story' => null,\n                ],\n            ],\n            'errors' => [\n                [\n                    'message'   => 'secretBackstory is secret.',\n                    'locations' => [locationShorthandToArray([5, 13])],\n                    'path'      => ['mainHero', 'story'],\n                ]\n            ],\n        ], $result);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Schema/BuildingTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Schema;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\Test\\readFileContents;\n\nclass BuildingTest extends TestCase\n{\n    public function testBuildsSchema()\n    {\n        $source = readFileContents(__DIR__ . '/../starWars.graphqls');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema($source);\n\n        $this->assertInstanceOf(Schema::class, $schema);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Schema/DefinitionPrinterTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Schema;\n\nuse Digia\\GraphQL\\Schema\\DefinitionPrinter;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\Language\\dedent;\n\n/**\n * Class DefinitionPrinterTest\n * @package Digia\\GraphQL\\Test\\Functional\\Schema\n */\nclass DefinitionPrinterTest extends TestCase\n{\n\n    /**\n     * @param string $source\n     *\n     * @dataProvider printStringFieldsDataProvider\n     *\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintStringFields(string $source): void\n    {\n        $this->assertPrintedSchemaEqualsBuiltSchema(dedent($source));\n    }\n\n    /**\n     * @return array\n     */\n    public function printStringFieldsDataProvider(): array\n    {\n        return [\n//            // String field\n//            [\n//                '\n//                type Query {\n//                  singleField: String\n//                }\n//                ',\n//            ],\n//            // [String] field\n//            [\n//                '\n//                type Query {\n//                  singleField: [String]\n//                }\n//                ',\n//            ],\n//            // String! field\n//            [\n//                '\n//                type Query {\n//                  singleField: String!\n//                }\n//                ',\n//            ],\n//            // [String]! field\n//            [\n//                '\n//                type Query {\n//                  singleField: [String]!\n//                }\n//                ',\n//            ],\n//            // [String!] field\n//            [\n//                '\n//                type Query {\n//                  singleField: [String!]\n//                }\n//                ',\n//            ],\n//            // [String!]! field\n//            [\n//                '\n//                type Query {\n//                  singleField: [String!]!\n//                }\n//                ',\n//            ],\n//            // String field with Int argument\n//            [\n//                '\n//                type Query {\n//                  singleField(argOne: Int): String\n//                }\n//                ',\n//            ],\n//            // String field with Int argument with default value\n//            [\n//                '\n//                type Query {\n//                  singleField(argOne: Int = 2): String\n//                }\n//                ',\n//            ],\n            // String field with String argument with default value\n            // TODO: Make this data set work\n//            [\n//                '\n//                type Query {\n//                  singleField(argOne: String = \"tes\\t de\\fault\"): String\n//                }\n//                ',\n//            ],\n            // String field with Int argument with default null\n            // TODO: Make this data set work, needs https://github.com/digiaonline/graphql-php/issues/239\n//            [\n//                '\n//                type Query {\n//                  singleField(argOne: Int = null): String\n//                }\n//                ',\n//            ],\n            // String field with Int! argument\n            [\n                '\n                type Query {\n                  singleField(argOne: Int!): String\n                }\n                ',\n            ],\n            // String field with multiple arguments\n            [\n                '\n                type Query {\n                  singleField(argOne: Int, argTwo: String): String\n                }\n                ',\n            ],\n            // String field with multiple arguments, first is default\n            [\n                '\n                type Query {\n                  singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String\n                }\n                ',\n            ],\n            // String field with multiple arguments, second is default\n            [\n                '\n                type Query {\n                  singleField(argOne: Int, argTwo: String = \"foo\", argThree: Boolean): String\n                }\n                ',\n            ],\n            // String field with multiple arguments, last is default\n            [\n                '\n                type Query {\n                  singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String\n                }\n                ',\n            ],\n        ];\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintObjectFields(): void\n    {\n        $source = dedent('\n            type Foo {\n              str: String\n            }\n            \n            type Query {\n              foo: Foo\n            }\n              ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintCustomRootQuery(): void\n    {\n        $source = dedent('\n            schema {\n              query: CustomQueryType\n            }\n            \n            type CustomQueryType {\n              bar: String\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintInterfaces(): void\n    {\n        // Single interface\n        $source = dedent('\n            type Bar implements Foo {\n              str: String\n            }\n            \n            interface Foo {\n              str: String\n            }\n            \n            type Query {\n              bar: Bar\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n\n        // Multiple interfaces\n        $source = dedent('\n            interface Baaz {\n              int: Int\n            }\n            \n            type Bar implements Foo & Baaz {\n              str: String\n              int: Int\n            }\n            \n            interface Foo {\n              str: String\n            }\n            \n            type Query {\n              bar: Bar\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintUnions(): void\n    {\n        $source = dedent('\n            type Bar {\n              str: String\n            }\n            \n            type Foo {\n              bool: Boolean\n            }\n            \n            union MultipleUnion = Foo | Bar\n            \n            type Query {\n              single: SingleUnion\n              multiple: MultipleUnion\n            }\n            \n            union SingleUnion = Foo\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintInputType(): void\n    {\n        $source = dedent('\n            input InputType {\n              int: Int\n            }\n            \n            type Query {\n              str(argOne: InputType): String\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintCustomScalar(): void\n    {\n        $source = dedent('\n            scalar Odd\n            \n            type Query {\n              odd: Odd\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    public function testPrintEnum(): void\n    {\n        $source = dedent('\n            type Query {\n              rgb: RGB\n            }\n            \n            enum RGB {\n              RED\n              GREEN\n              BLUE\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     *\n     * TODO: Add support for printing directives first\n     */\n    public function testPrintCustomDirectives(): void\n    {\n        $source = dedent('\n            directive @customDirective on FIELD\n            \n            type Query {\n              field: String\n            }\n            ');\n\n        $this->assertPrintedSchemaEqualsBuiltSchema($source);\n    }\n\n    // TODO: Add tests for description printing, it's currently quite broken so no point in writing the tests yet\n\n    public function testPrintIntrospectionSchema(): void\n    {\n        $source = dedent('\n             \"\"\"\n             Directs the executor to include this field or fragment only when the \\`if\\` argument is true.\n             \"\"\"\n             directive @include(\n               \"\"\"Included when true.\"\"\"\n               if: Boolean!\n             ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\n             \"\"\"\n             Directs the executor to skip this field or fragment when the \\`if\\` argument is true.\n             \"\"\"\n             directive @skip(\n               \"\"\"Skipped when true.\"\"\"\n               if: Boolean!\n             ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\n             \"\"\"Marks an element of a GraphQL schema as no longer supported.\"\"\"\n             directive @deprecated(\n               \"\"\"\n               Explains why this element was deprecated, usually also including a suggestion\n               for how to access supported similar data. Formatted using the Markdown syntax\n               (as specified by [CommonMark](https://commonmark.org/).\n               \"\"\"\n               reason: String = \"No longer supported\"\n             ) on FIELD_DEFINITION | ENUM_VALUE\n\n             \"\"\"\n             A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\n             In some cases, you need to provide options to alter GraphQL\\'s execution behavior\n             in ways field arguments will not suffice, such as conditionally including or\n             skipping a field. Directives provide this by describing additional information\n             to the executor.\n             \"\"\"\n             type __Directive {\n               name: String!\n               description: String\n               locations: [__DirectiveLocation!]!\n               args: [__InputValue!]!\n             }\n\n             \"\"\"\n             A Directive can be adjacent to many parts of the GraphQL language, a\n             __DirectiveLocation describes one such possible adjacencies.\n             \"\"\"\n             enum __DirectiveLocation {\n               \"\"\"Location adjacent to a query operation.\"\"\"\n               QUERY\n\n               \"\"\"Location adjacent to a mutation operation.\"\"\"\n               MUTATION\n\n               \"\"\"Location adjacent to a subscription operation.\"\"\"\n               SUBSCRIPTION\n\n               \"\"\"Location adjacent to a field.\"\"\"\n               FIELD\n\n               \"\"\"Location adjacent to a fragment definition.\"\"\"\n               FRAGMENT_DEFINITION\n\n               \"\"\"Location adjacent to a fragment spread.\"\"\"\n               FRAGMENT_SPREAD\n\n               \"\"\"Location adjacent to an inline fragment.\"\"\"\n               INLINE_FRAGMENT\n\n               \"\"\"Location adjacent to a variable definition.\"\"\"\n               VARIABLE_DEFINITION\n\n               \"\"\"Location adjacent to a schema definition.\"\"\"\n               SCHEMA\n\n               \"\"\"Location adjacent to a scalar definition.\"\"\"\n               SCALAR\n\n               \"\"\"Location adjacent to an object type definition.\"\"\"\n               OBJECT\n\n               \"\"\"Location adjacent to a field definition.\"\"\"\n               FIELD_DEFINITION\n\n               \"\"\"Location adjacent to an argument definition.\"\"\"\n               ARGUMENT_DEFINITION\n\n               \"\"\"Location adjacent to an interface definition.\"\"\"\n               INTERFACE\n\n               \"\"\"Location adjacent to a union definition.\"\"\"\n               UNION\n\n               \"\"\"Location adjacent to an enum definition.\"\"\"\n               ENUM\n\n               \"\"\"Location adjacent to an enum value definition.\"\"\"\n               ENUM_VALUE\n\n               \"\"\"Location adjacent to an input object type definition.\"\"\"\n               INPUT_OBJECT\n\n               \"\"\"Location adjacent to an input object field definition.\"\"\"\n               INPUT_FIELD_DEFINITION\n             }\n\n             \"\"\"\n             One possible value for a given Enum. Enum values are unique values, not a\n             placeholder for a string or numeric value. However an Enum value is returned in\n             a JSON response as a string.\n             \"\"\"\n             type __EnumValue {\n               name: String!\n               description: String\n               isDeprecated: Boolean!\n               deprecationReason: String\n             }\n\n             \"\"\"\n             Object and Interface types are described by a list of Fields, each of which has\n             a name, potentially a list of arguments, and a return type.\n             \"\"\"\n             type __Field {\n               name: String!\n               description: String\n               args: [__InputValue!]!\n               type: __Type!\n               isDeprecated: Boolean!\n               deprecationReason: String\n             }\n\n             \"\"\"\n             Arguments provided to Fields or Directives and the input fields of an\n             InputObject are represented as Input Values which describe their type and\n             optionally a default value.\n             \"\"\"\n             type __InputValue {\n               name: String!\n               description: String\n               type: __Type!\n\n               \"\"\"\n               A GraphQL-formatted string representing the default value for this input value.\n               \"\"\"\n               defaultValue: String\n             }\n\n             \"\"\"\n             A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all\n             available types and directives on the server, as well as the entry points for\n             query, mutation, and subscription operations.\n             \"\"\"\n             type __Schema {\n               \"\"\"A list of all types supported by this server.\"\"\"\n               types: [__Type!]!\n\n               \"\"\"The type that query operations will be rooted at.\"\"\"\n               queryType: __Type!\n\n               \"\"\"\n               If this server supports mutation, the type that mutation operations will be rooted at.\n               \"\"\"\n               mutationType: __Type\n\n               \"\"\"\n               If this server support subscription, the type that subscription operations will be rooted at.\n               \"\"\"\n               subscriptionType: __Type\n\n               \"\"\"A list of all directives supported by this server.\"\"\"\n               directives: [__Directive!]!\n             }\n\n             \"\"\"\n             The fundamental unit of any GraphQL Schema is the type. There are many kinds of\n             types in GraphQL as represented by the \\`__TypeKind\\` enum.\n\n             Depending on the kind of a type, certain fields describe information about that\n             type. Scalar types provide no information beyond a name and description, while\n             Enum types provide their values. Object and Interface types provide the fields\n             they describe. Abstract types, Union and Interface, provide the Object types\n             possible at runtime. List and NonNull types compose other types.\n             \"\"\"\n             type __Type {\n               kind: __TypeKind!\n               name: String\n               description: String\n               fields(includeDeprecated: Boolean = false): [__Field!]\n               interfaces: [__Type!]\n               possibleTypes: [__Type!]\n               enumValues(includeDeprecated: Boolean = false): [__EnumValue!]\n               inputFields: [__InputValue!]\n               ofType: __Type\n             }\n\n             \"\"\"An enum describing what kind of type a given \\`__Type\\` is.\"\"\"\n             enum __TypeKind {\n               \"\"\"Indicates this type is a scalar.\"\"\"\n               SCALAR\n\n               \"\"\"\n               Indicates this type is an object. \\`fields\\` and \\`interfaces\\` are valid fields.\n               \"\"\"\n               OBJECT\n\n               \"\"\"\n               Indicates this type is an interface. \\`fields\\` and \\`possibleTypes\\` are valid fields.\n               \"\"\"\n               INTERFACE\n\n               \"\"\"Indicates this type is a union. \\`possibleTypes\\` is a valid field.\"\"\"\n               UNION\n\n               \"\"\"Indicates this type is an enum. \\`enumValues\\` is a valid field.\"\"\"\n               ENUM\n\n               \"\"\"\n               Indicates this type is an input object. \\`inputFields\\` is a valid field.\n               \"\"\"\n               INPUT_OBJECT\n\n               \"\"\"Indicates this type is a list. \\`ofType\\` is a valid field.\"\"\"\n               LIST\n\n               \"\"\"Indicates this type is a non-null. \\`ofType\\` is a valid field.\"\"\"\n               NON_NULL\n             }\n            ');\n\n        $schema = buildSchema($source);\n\n        $printer = new DefinitionPrinter();\n\n        $this->assertEquals($source, $printer->printIntrospectionSchema($schema));\n    }\n\n    /**\n     * @param string $source\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\PrintException\n     */\n    private function assertPrintedSchemaEqualsBuiltSchema(string $source): void\n    {\n        $schema = buildSchema($source);\n\n        $printer = new DefinitionPrinter();\n\n        $this->assertSame($source, $printer->printSchema($schema));\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Schema/ExtensionTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Schema;\n\nuse Digia\\GraphQL\\Schema\\Extension\\SchemaExtensionException;\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Schema\\Extension\\SchemaExtenderInterface;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\EnumValue;\nuse Digia\\GraphQL\\Type\\Definition\\Field;\nuse Digia\\GraphQL\\Type\\Definition\\NonNullType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse function Digia\\GraphQL\\graphql;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Type\\idType;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\newUnionType;\nuse function Digia\\GraphQL\\validateSchema;\n\nclass ExtensionTest extends TestCase\n{\n    /**\n     * @var SchemaExtenderInterface\n     */\n    protected $extender;\n\n    protected $testSchema;\n    protected $someInterfaceType;\n    protected $fooType;\n    protected $barType;\n    protected $bizType;\n    protected $someUnionType;\n    protected $someEnumType;\n\n    public function setUp()\n    {\n        $this->extender = GraphQL::make(SchemaExtenderInterface::class);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someInterfaceType = newInterfaceType([\n            'name'   => 'SomeInterface',\n            'fields' => function () {\n                return [\n                    'name' => ['type' => stringType()],\n                    'some' => ['type' => $this->someInterfaceType],\n                ];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->fooType = newObjectType([\n            'name'       => 'Foo',\n            'interfaces' => [$this->someInterfaceType],\n            'fields'     => function () {\n                return [\n                    'name' => ['type' => stringType()],\n                    'some' => ['type' => $this->someInterfaceType],\n                    'tree' => ['type' => newNonNull(newList($this->fooType))],\n                ];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->barType = newObjectType([\n            'name'       => 'Bar',\n            'interfaces' => [$this->someInterfaceType],\n            'fields'     => function () {\n                return [\n                    'name' => ['type' => stringType()],\n                    'some' => ['type' => $this->someInterfaceType],\n                    'foo'  => ['type' => $this->fooType],\n                ];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->bizType = newObjectType([\n            'name'   => 'Biz',\n            'fields' => function () {\n                return [\n                    'fizz' => ['type' => stringType()]\n                ];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someUnionType = newUnionType([\n            'name'  => 'SomeUnion',\n            'types' => [$this->fooType, $this->bizType],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someEnumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => [\n                'ONE' => ['value' => 1],\n                'TWO' => ['value' => 2],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->testSchema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => function () {\n                    return [\n                        'foo'           => ['type' => $this->fooType],\n                        'someUnion'     => ['type' => $this->someUnionType],\n                        'someEnum'      => ['type' => $this->someEnumType],\n                        'someInterface' => [\n                            'type' => $this->someInterfaceType,\n                            'args' => ['id' => ['type' => newNonNull(idType())]],\n                        ],\n                    ];\n                },\n            ]),\n            'types' => [$this->fooType, $this->barType],\n        ]);\n    }\n\n    // returns the original schema when there are no type definitions\n\n    public function testReturnsTheOriginalSchemaWhenThereAreNoTypeDefinitions()\n    {\n        $extendedSchema = $this->extendTestSchema('{ field }');\n        $this->assertEquals($this->testSchema, $extendedSchema);\n    }\n\n    // extends without altering original schema\n\n    public function testExtendsWithoutAlteringOriginalSchema()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        extend type Query {\n          newField: String\n        }\n        '));\n\n        $this->assertNotEquals($this->testSchema, $extendedSchema);\n        // TODO: Assert printed schemas\n    }\n\n    // can be used for limited execution\n\n    public function testCanBeUsedForLimitedExecution()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        extend type Query {\n          newField: String\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = graphql($extendedSchema, '{ newField }', ['newField' => 123]);\n\n        $this->assertEquals(['newField' => '123'], $result['data']);\n    }\n\n    // can describe the extended fields\n\n    public function testCanDescribeTheExtendedFields()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        extend type Query {\n          \"New field description.\"\n          newField: String\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(\n            'New field description.',\n            $extendedSchema->getQueryType()->getField('newField')->getDescription()\n        );\n    }\n\n    // Skip: can describe the extended fields with legacy comments\n\n    // TODO: describes extended fields with strings when present\n\n    // correctly assign AST nodes to new and extended types\n\n    public function testCorrectlyAssignASTNodesToNewAndExtendedTypes()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        extend type Query {\n          newField(testArg: TestInput): TestEnum\n        }\n        \n        enum TestEnum {\n          TEST_VALUE\n        }\n        \n        input TestInput {\n          testInputField: TestEnum\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $secondExtensionAST = parse(dedent('\n        extend type Query {\n          oneMoreNewField: TestUnion\n        }\n        \n        union TestUnion = TestType\n        \n        interface TestInterface {\n          interfaceField: String\n        }\n        \n        type TestType implements TestInterface {\n          interfaceField: String\n        }\n        \n        directive @test(arg: Int) on FIELD\n        '));\n\n        $extendedTwiceSchema = $this->extendSchema(\n            $extendedSchema,\n            $secondExtensionAST\n        );\n\n        $query         = $extendedTwiceSchema->getQueryType();\n        $testInput     = $extendedTwiceSchema->getType('TestInput');\n        $testEnum      = $extendedTwiceSchema->getType('TestEnum');\n        $testUnion     = $extendedTwiceSchema->getType('TestUnion');\n        $testInterface = $extendedTwiceSchema->getType('TestInterface');\n        $testType      = $extendedTwiceSchema->getType('TestType');\n        $testDirective = $extendedTwiceSchema->getDirective('test');\n\n        $this->assertCount(2, $query->getExtensionAstNodes());\n        $this->assertCount(0, $testType->getExtensionAstNodes());\n\n        // TODO: Assert printed types\n    }\n\n    // builds types with deprecated fields/values\n\n    public function gestBuildTypesWithDeprecatedFieldsOrValues()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        type TypeWithDeprecatedField {\n          newDeprecatedField: String @deprecated(reason: \"not used anymore\")\n        }\n        \n        enum EnumWithDeprecatedValue {\n          DEPRECATED @deprecated(reason: \"do not use\")\n        }\n        '));\n\n        /** @var Field $deprecatedFieldDefinition */\n        /** @noinspection PhpUndefinedMethodInspection */\n        $deprecatedFieldDefinition = $extendedSchema\n            ->getType('TypeWithDeprecatedField')\n            ->getField('newDeprecatedField');\n\n        $this->assertTrue($deprecatedFieldDefinition->isDeprecated());\n        $this->assertEquals('not used anymore', $deprecatedFieldDefinition->getDeprecationReason());\n\n        /** @var EnumValue $deprecatedEnumDefinition */\n        /** @noinspection PhpUndefinedMethodInspection */\n        $deprecatedEnumDefinition = $extendedSchema\n            ->getType('EnumWithDeprecatedValue')\n            ->getValue('DEPRECATED');\n\n        $this->assertTrue($deprecatedEnumDefinition->isDeprecated());\n        $this->assertEquals('do not use', $deprecatedEnumDefinition->getDeprecationReason());\n    }\n\n    // extends objects with deprecated fields\n\n    public function testExtendsObjectsWithDeprecatedFields()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        extend type Foo {\n          deprecatedField: String @deprecated(reason: \"not used anymore\")\n        }\n        '));\n\n        /** @var Field $deprecatedFieldDefinition */\n        /** @noinspection PhpUndefinedMethodInspection */\n        $deprecatedFieldDefinition = $extendedSchema\n            ->getType('Foo')\n            ->getField('deprecatedField');\n\n        $this->assertTrue($deprecatedFieldDefinition->isDeprecated());\n        $this->assertEquals('not used anymore', $deprecatedFieldDefinition->getDeprecationReason());\n    }\n\n    // extends objects by adding new unused types\n\n    public function testExtendsObjectsByAddingNewUnusedTypes()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        type Unused {\n          someField: String\n        }\n        '));\n\n        $this->assertNotEquals($this->testSchema, $extendedSchema);\n        // TODO: Assert printed schemas\n    }\n\n    // TODO: extends objects by adding new fields with arguments\n\n    // TODO: extends objects by adding new fields with existing types\n\n    // TODO: extends objects by adding implemented interfaces\n\n    // TODO: extends objects by including new types\n\n    // TODO: extends objects by adding implemented new interfaces\n\n    // TODO: extends objects multiple times\n\n    // TODO: extends interfaces by adding new fields\n\n    // allows extension of interface with missing Object fields\n\n    public function testAllowsExtensionOfInterfaceWithMissingObjectFields()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        extend interface SomeInterface {\n          newField: String\n        }\n        '));\n\n        $errors = validateSchema($extendedSchema);\n        $this->assertNotEmpty($errors);\n\n        // TODO: Assert printed schemas\n    }\n\n    // TODO: extends interfaces multiple times\n\n    // may extend mutations and subscriptions\n\n    public function testMayExtendMutationsAndSubscriptions()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $mutationSchema = newSchema([\n            'query'        => newObjectType([\n                'name'   => 'Query',\n                'fields' => function () {\n                    return [\n                        'queryField' => ['type' => stringType()],\n                    ];\n                },\n            ]),\n            'mutation'     => newObjectType([\n                'name'   => 'Mutation',\n                'fields' => function () {\n                    return [\n                        'mutationField' => ['type' => stringType()],\n                    ];\n                },\n            ]),\n            'subscription' => newObjectType([\n                'name'   => 'Subscription',\n                'fields' => function () {\n                    return [\n                        'subscriptionField' => ['type' => stringType()],\n                    ];\n                },\n            ]),\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $document = parse(dedent('\n        extend type Query {\n          newQueryField: Int\n        }\n        \n        extend type Mutation {\n          newMutationField: Int\n        }\n        \n        extend type Subscription {\n          newSubscriptionField: Int\n        }\n        '));\n\n        $extendedSchema = $this->extendSchema($mutationSchema, $document);\n        $this->assertNotEquals($mutationSchema, $extendedSchema);\n\n        // TODO: Assert printed schemas\n    }\n\n    // may extend directives with new simple directive\n\n    public function testMayExtendDirectivesWithNewSimpleDirective()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        directive @neat on QUERY\n        '));\n\n        $extendedDirective = $extendedSchema->getDirective('neat');\n        $this->assertEquals('neat', $extendedDirective->getName());\n        $this->assertContains('QUERY', $extendedDirective->getLocations());\n    }\n\n    // sets correct description when extending with a new directive\n\n    public function testSetsCorrectDescriptionWhenExtendingWithANewDirective()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        \"\"\"\n        new directive\n        \"\"\"\n        directive @new on QUERY\n        '));\n\n        $extendedDirective = $extendedSchema->getDirective('new');\n        $this->assertEquals('new directive', $extendedDirective->getDescription());\n    }\n\n    // Skip: sets correct description using legacy comments\n\n    // may extend directives with new complex directive\n\n    public function testMayExtendDirectivesWithNewComplexDirective()\n    {\n        $extendedSchema = $this->extendTestSchema(dedent('\n        directive @profile(enable: Boolean! tag: String) on QUERY | FIELD\n        '));\n\n        $extendedDirective = $extendedSchema->getDirective('profile');\n        $this->assertContains('QUERY', $extendedDirective->getLocations());\n        $this->assertContains('FIELD', $extendedDirective->getLocations());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $arguments = $extendedDirective->getArguments();\n        $argument0 = $arguments[0];\n        $argument1 = $arguments[1];\n\n        $this->assertCount(2, $arguments);\n\n        $this->assertEquals('enable', $argument0->getName());\n        $this->assertInstanceOf(NonNullType::class, $argument0->getType());\n        $this->assertInstanceOf(ScalarType::class, $argument0->getType()->getOfType());\n\n        $this->assertEquals('tag', $argument1->getName());\n        $this->assertInstanceOf(ScalarType::class, $argument1->getType());\n    }\n\n    // does not allow replacing a default directive\n\n    public function testDoesNotAllowReplacingADefaultDirective()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Directive \"include\" already exists in the schema. It cannot be redefined.');\n        $this->extendTestSchema('directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD');\n    }\n\n    // does not allow replacing a custom directive\n\n    public function testDoesNotAllowReplacingACustomDirective()\n    {\n        $extendedSchema = $this->extendTestSchema('directive @meow(if: Boolean!) on FIELD | FRAGMENT_SPREAD');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $sdl = parse('directive @meow(if: Boolean!) on FIELD | QUERY');\n\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Directive \"meow\" already exists in the schema. It cannot be redefined.');\n        $this->extendSchema($extendedSchema, $sdl);\n    }\n\n    // does not allow replacing an existing type\n\n    public function testDoesNotAllowReplacingAnExistingType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage(\n            'Field \"Bar.foo\" already exists in the schema. It cannot also be ' .\n            'defined in this type extension.'\n        );\n        $this->extendTestSchema(dedent('\n        extend type Bar {\n          foo: Foo\n        }\n        '));\n    }\n\n    // does not allow referencing an unknown type\n\n    public function testDoesNotAllowReferencingAnUnknownType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage(\n            'Unknown type: \"Quix\". Ensure that this type exists either in the ' .\n            'original schema, or is added in a type definition.'\n        );\n        $this->extendTestSchema(dedent('\n        extend type Bar {\n          quix: Quix\n        }\n        '));\n    }\n\n    // does not allow extending an unknown type\n\n    public function testDoesNotAllowExtendingAnUnknownType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage(\n            'Cannot extend type \"UnknownType\" because it does not exist in the existing schema.'\n        );\n        $this->extendTestSchema(dedent('\n        extend type UnknownType {\n          baz: String\n        }\n        '));\n    }\n\n    // does not allow extending an unknown interface type\n\n    public function testDoesNotAllowExtendingAnUnknownInterfaceType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage(\n            'Cannot extend type \"UnknownInterfaceType\" because it does not exist in the existing schema.'\n        );\n        $this->extendTestSchema(dedent('\n        extend interface UnknownInterfaceType {\n          baz: String\n        }\n        '));\n    }\n\n    // Skip: maintains configuration of the original schema object\n\n    // Skip: adds to the configuration of the original schema object\n\n    // does not allow extending a non-object type\n\n    // not an object\n\n    public function testDoesNotAllowExtendingANonObjectType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Cannot extend non-object type \"SomeInterface\".');\n        $this->extendTestSchema(dedent('\n        extend type SomeInterface {\n          baz: String\n        }\n        '));\n    }\n\n    // not an interface\n\n    public function testDoesNotAllowExtendingANonObjectInterfaceType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Cannot extend non-interface type \"Foo\".');\n        $this->extendTestSchema(dedent('\n        extend interface Foo {\n          baz: String\n        }\n        '));\n    }\n\n    // not a scalar\n\n    public function testDoesNotAllowExtendingANonObjectScalarType()\n    {\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Cannot extend non-object type \"String\".');\n        $this->extendTestSchema(dedent('\n        extend type String {\n          baz: String\n        }\n        '));\n    }\n\n    // can add additional root operation types\n\n    // does not automatically include common root type names\n\n    public function testDoesNotAutomaticallyIncludeCommonRootTypeNames()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        type Mutation {\n          doSomething: String\n        }\n        ');\n\n        $schema = $this->extendSchema($this->testSchema, $node);\n\n        $this->assertNull($schema->getMutationType());\n    }\n\n    // does not allow new schema within an extension\n\n    public function testDoesNotAllowNewSchemaWithinAnExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        schema {\n          mutation: Mutation\n        }\n        \n        type Mutation {\n          doSomething: String\n        }\n        ');\n\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Cannot define a new schema within a schema extension.');\n        $this->extendSchema($this->testSchema, $node);\n    }\n\n    // adds new root types via schema extension\n\n    public function testAddsNewRootTypesViaSchemaExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        extend schema {\n          mutation: Mutation\n        }\n        \n        type Mutation {\n          doSomething: String\n        }\n        ');\n\n        $schema = $this->extendSchema($this->testSchema, $node);\n\n        $this->assertEquals('Mutation', $schema->getMutationType()->getName());\n    }\n\n    // adds multiple new root types via schema extension\n\n    public function testAddsMultipleNewRootTypesViaSchemaExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        extend schema {\n          mutation: Mutation\n          subscription: Subscription\n        }\n        \n        type Mutation {\n          doSomething: String\n        }\n        \n        type Subscription {\n          hearSomething: String\n        }\n        ');\n\n        $schema = $this->extendSchema($this->testSchema, $node);\n\n        $this->assertEquals('Mutation', $schema->getMutationType()->getName());\n        $this->assertEquals('Subscription', $schema->getSubscriptionType()->getName());\n    }\n\n    // applies multiple schema extensions\n\n    public function testAppliesMultipleSchemaExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        extend schema {\n          mutation: Mutation\n        }\n        \n        extend schema {\n          subscription: Subscription\n        }\n        \n        type Mutation {\n          doSomething: String\n        }\n        \n        type Subscription {\n          hearSomething: String\n        }\n        ');\n\n        $schema = $this->extendSchema($this->testSchema, $node);\n\n        $this->assertEquals('Mutation', $schema->getMutationType()->getName());\n        $this->assertEquals('Subscription', $schema->getSubscriptionType()->getName());\n    }\n\n    // TODO: schema extension AST are available from schema object\n\n    // does not allow redefining an existing root type\n\n    public function testDoesNotAllowRedefiningAnExistingRootType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        extend schema {\n          query: SomeType\n        }\n        \n        type SomeType {\n          seeSomething: String\n        }\n        ');\n\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Must provide only one query type in schema.');\n        $this->extendSchema($this->testSchema, $node);\n    }\n\n    // does not allow defining a root operation type twice\n\n    public function testDoesNotAllowDefiningARootTypeTwice()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        extend schema {\n          mutation: Mutation\n        }\n        \n        extend schema {\n          mutation: Mutation\n        }\n        \n        type Mutation {\n          doSomething: String\n        }\n        ');\n\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Must provide only one mutation type in schema.');\n        $this->extendSchema($this->testSchema, $node);\n    }\n    \n    // does not allow defining a root operation type with different types\n\n    public function testDoesNotAllowDefiningARootTypeWithDifferentTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $node = parse('\n        extend schema {\n          mutation: Mutation\n        }\n        \n        extend schema {\n          mutation: SomethingElse\n        }\n        \n        type Mutation {\n          doSomething: String\n        }\n        \n        type SomethingElse {\n          doSomethingElse: String\n        }\n        ');\n\n        $this->expectException(SchemaExtensionException::class);\n        $this->expectExceptionMessage('Must provide only one mutation type in schema.');\n        $this->extendSchema($this->testSchema, $node);\n    }\n\n    protected function extendSchema($schema, $document)\n    {\n        return $this->extender->extend($schema, $document);\n    }\n\n    protected function extendTestSchema($sdl)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $document       = parse($sdl);\n        $extendedSchema = $this->extendSchema($this->testSchema, $document);\n        // TODO: Assert printed schemas\n        return $extendedSchema;\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Schema/SchemaBuilderTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Schema;\n\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\graphql;\n\nclass SchemaBuilderTest extends TestCase\n{\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testSpecifyingInterfaceTypeUsingTypeNameMetaFieldDefinition()\n    {\n        $source = '\n           type Query {\n            characters: [Character]\n          }\n    \n          interface Character {\n            name: String!\n          }\n    \n          type Human implements Character {\n            name: String!\n            totalCredits: Int\n          }\n    \n          type Droid implements Character {\n            name: String!\n            primaryFunction: String\n          }\n      ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema($source);\n\n        $query = '\n         {\n            characters {\n              name\n              ... on Human {\n                totalCredits\n              }\n              ... on Droid {\n                primaryFunction\n              }\n            }\n          }\n        ';\n\n        $rootValue = [\n            'characters' => [\n                [\n                    'name'         => 'Han Solo',\n                    'totalCredits' => 10,\n                    '__typename'   => 'Human',\n                ],\n                [\n                    'name'            => 'R2-D2',\n                    'primaryFunction' => 'Astromech',\n                    '__typename'      => 'Droid',\n                ],\n            ],\n        ];\n\n        $result = graphql($schema, $query, $rootValue);\n\n        $this->assertEquals([\n            'data' => [\n                'characters' => [\n                    [\n                        'name'         => 'Han Solo',\n                        'totalCredits' => 10,\n                    ],\n                    [\n                        'name'            => 'R2-D2',\n                        'primaryFunction' => 'Astromech',\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    public function testSpecifyingUnionTypeUsingTypeNameMetaFieldDefinition()\n    {\n        $source = '\n          type Query {\n            fruits: [Fruit]\n          }\n    \n          union Fruit = Apple | Banana\n    \n          type Apple {\n            color: String\n          }\n    \n          type Banana {\n            length: Int\n          }\n      ';\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema($source);\n\n        $query = '\n          {\n            fruits {\n              ... on Apple {\n                color\n              }\n              ... on Banana {\n                length\n              }\n            }\n          }\n        ';\n\n        $rootValue = [\n            'fruits' => [\n                [\n                    'color'      => 'green',\n                    '__typename' => 'Apple',\n                ],\n                [\n                    'length'     => 5,\n                    '__typename' => 'Banana',\n                ],\n            ],\n        ];\n\n        $result = graphql($schema, $query, $rootValue);\n\n        $this->assertEquals([\n            'data' => [\n                'fruits' => [\n                    [\n                        'color' => 'green',\n                    ],\n                    [\n                        'length' => 5,\n                    ],\n                ],\n            ],\n        ], $result);\n    }\n}"
  },
  {
    "path": "tests/Functional/Schema/SchemaTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Schema;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\Directive;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse function Digia\\GraphQL\\Type\\newDirective;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass SchemaTest extends TestCase\n{\n\n    /**\n     * @var InterfaceType\n     */\n    protected $interfaceType;\n\n    /**\n     * @var ObjectType\n     */\n    protected $implementingType;\n\n    /**\n     * @var InputObjectType\n     */\n    protected $directiveInputType;\n\n    /**\n     * @var InputObjectType\n     */\n    protected $wrappedDirectiveInputType;\n\n    /**\n     * @var Directive\n     */\n    protected $directive;\n\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    /**\n     * @inheritdoc\n     */\n    public function setUp()\n    {\n        $this->interfaceType = newInterfaceType([\n            'name'   => 'Interface',\n            'fields' => [\n                'fieldName' => [\n                    'type' => stringType(),\n                ],\n            ],\n        ]);\n\n        $this->implementingType = newObjectType([\n            'name'       => 'Object',\n            'interfaces' => [$this->interfaceType],\n            'fields'     => [\n                'fieldName' => [\n                    'type'    => stringType(),\n                    'resolve' => function () {\n                        return '';\n                    },\n                ]\n            ],\n        ]);\n\n        $this->directiveInputType = newInputObjectType([\n            'name'   => 'DirInput',\n            'fields' => [\n                'field' => [\n                    'type' => stringType(),\n                ]\n            ],\n        ]);\n\n        $this->wrappedDirectiveInputType = newInputObjectType([\n            'name'   => 'WrappedDirInput',\n            'fields' => [\n                'field' => [\n                    'type' => stringType(),\n                ],\n            ],\n        ]);\n\n        $this->directive = newDirective([\n            'name'      => 'dir',\n            'locations' => ['OBJECT'],\n            'args'      => [\n                'arg'     => [\n                    'type' => $this->directiveInputType,\n                ],\n                'argList' => [\n                    'type' => newList($this->wrappedDirectiveInputType),\n                ],\n            ],\n            'fields'    => [\n                'field' => [\n                    'type' => stringType(),\n                ],\n            ],\n        ]);\n\n        $this->schema = newSchema([\n            'query'      => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'getObject' => [\n                        'type'    => $this->interfaceType,\n                        'resolve' => function () {\n                            return '';\n                        }\n                    ],\n                ],\n            ]),\n            'directives' => [\n                $this->directive,\n            ],\n        ]);\n\n        $this->schema;\n    }\n\n    /**\n     * @expectedException \\Exception\n     */\n    public function testThrowsHumanReadableErrorIfSchemaTypesIsNotDefined()\n    {\n        $this->schema->isPossibleType($this->interfaceType, $this->implementingType);\n    }\n\n    public function testIncludesInputTypesOnlyUsedInDirectives()\n    {\n        $typeMap = $this->schema->getTypeMap();\n\n        $this->assertArrayHasKey('DirInput', $typeMap);\n        $this->assertArrayHasKey('WrappedDirInput', $typeMap);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Schema/ValidationTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Schema;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Schema\\Validation\\SchemaValidatorInterface;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Validation\\ValidationExceptionInterface;\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\extendSchema;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Language\\locationShorthandToArray;\nuse function Digia\\GraphQL\\Language\\locationsShorthandToArray;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\newUnionType;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass ValidationTest extends TestCase\n{\n    /**\n     * @var SchemaValidatorInterface\n     */\n    protected $schemaValidator;\n\n    protected $someScalarType;\n    protected $someObjectType;\n    protected $someUnionType;\n    protected $someInterfaceType;\n    protected $someEnumType;\n    protected $someInputObjectType;\n    protected $outputTypes;\n    protected $noOutputTypes;\n    protected $inputTypes;\n    protected $noInputTypes;\n\n    public function setUp()\n    {\n        $this->schemaValidator = GraphQL::make(SchemaValidatorInterface::class);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someScalarType = newScalarType([\n            'name'         => 'SomeScalar',\n            'serialize'    => function () {\n            },\n            'parseValue'   => function () {\n            },\n            'parseLiteral' => function () {\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someObjectType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someUnionType = newUnionType([\n            'name'  => 'SomeUnion',\n            'types' => [$this->someObjectType],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someInterfaceType = newInterfaceType([\n            'name'   => 'SomeInterface',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someEnumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => ['ONLY' => []],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->someInputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => [\n                'val' => ['type' => stringType(), 'defaultValue' => 'hello'],\n            ],\n        ]);\n\n        $this->outputTypes = $this->withModifiers([\n            stringType(),\n            $this->someScalarType,\n            $this->someEnumType,\n            $this->someObjectType,\n            $this->someUnionType,\n            $this->someInterfaceType,\n        ]);\n\n        $this->noOutputTypes = $this->withModifiers([$this->someInputObjectType]);\n\n        $this->inputTypes = $this->withModifiers([\n            stringType(),\n            $this->someScalarType,\n            $this->someEnumType,\n            $this->someInputObjectType,\n        ]);\n\n        $this->noInputTypes = $this->withModifiers([\n            $this->someObjectType,\n            $this->someUnionType,\n            $this->someInterfaceType,\n        ]);\n    }\n\n    // Type System: A Schema must have Object root types\n\n    // accepts a Schema whose query type is an object type\n\n    public function testAcceptsASchemaWhoseQueryTypeIsAnObjectType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: String\n        }\n        '));\n\n        $this->expectValid($schema);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schemaWithDef = buildSchema(dedent('\n        schema {\n          query: QueryRoot\n        }\n        \n        type QueryRoot {\n          test: String\n        }\n        '));\n\n        $this->expectValid($schemaWithDef);\n    }\n\n    // accepts a Schema whose query and mutation types are object types\n\n    public function testAcceptsASchemaWhoseQueryAndMutationTypesAreObjectTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: String\n        }\n        \n        type Mutation {\n          test: String\n        }\n        '));\n\n        $this->expectValid($schema);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schemaWithDef = buildSchema(dedent('\n        schema {\n          query: QueryRoot\n        }\n        \n        type QueryRoot {\n          test: String\n        }\n        \n        type MutationRoot {\n          test: String\n        }\n        '));\n\n        $this->expectValid($schemaWithDef);\n    }\n\n    // accepts a Schema whose query and subscription types are object types\n\n    public function testAcceptsASchemaWhoseQueryAndSubscriptionTypesAreObjectTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: String\n        }\n        \n        type Subscription {\n          test: String\n        }\n        '));\n\n        $this->expectValid($schema);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schemaWithDef = buildSchema(dedent('\n        schema {\n          query: QueryRoot\n        }\n        \n        type QueryRoot {\n          test: String\n        }\n        \n        type SubscriptionRoot {\n          test: String\n        }\n        '));\n\n        $this->expectValid($schemaWithDef);\n    }\n\n    // rejects a Schema without a query type\n\n    public function testRejectsASchemaWithoutAQueryType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Mutation {\n          test: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Query root type must be provided.',\n                'locations' => null,\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schemaWithDef = buildSchema(dedent('\n        schema {\n          mutation: MutationRoot\n        }\n        \n        type MutationRoot {\n          test: String\n        }\n        '));\n\n        $this->expectInvalid($schemaWithDef, [\n            [\n                'message'   => 'Query root type must be provided.',\n                'locations' => [locationShorthandToArray([1, 1])],\n            ]\n        ]);\n    }\n\n    // Skip: rejects a Schema whose query root type is not an Object type\n\n    // Skip: rejects a Schema whose mutation type is an input type\n\n    // Skip: rejects a Schema whose subscription type is an input type\n\n    // rejects a Schema whose directives are incorrectly typed\n\n//    public function testRejectsASchemaWhoseDirectivesAreIncorrectlyTypes()\n//    {\n//        /** @noinspection PhpUnhandledExceptionInspection */\n//        $schema = newSchema([\n//            'query'      => $this->someObjectType,\n//            'directives' => ['somedirective']\n//        ]);\n//\n//        $this->expectInvalid($schema, [\n//            [\n//                'message' => 'Expected directive but got: somedirective.',\n//            ]\n//        ]);\n//    }\n\n    // Type System: Objects must have fields\n\n    // accepts an Object type with fields object\n\n    public function testAcceptsAnObjectTypeWithFieldsObject()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field: SomeObject\n        }\n        \n        type SomeObject {\n          field: String\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects an Object type with missing fields\n\n    public function testRejectsAnObjectTypeWithMissingFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: IncompleteObject\n        }\n        \n        type IncompleteObject\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Type IncompleteObject must define one or more fields.',\n                'locations' => [],\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $manualSchema = $this->schemaWithFieldType(\n            newObjectType([\n                'name'   => 'IncompleteObject',\n                'fields' => [],\n            ])\n        );\n\n        $this->expectInvalid($manualSchema, [\n            [\n                'message' => 'Type IncompleteObject must define one or more fields.',\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $manualSchema2 = $this->schemaWithFieldType(\n            newObjectType([\n                'name'   => 'IncompleteObject',\n                'fields' => function () {\n                    return [];\n                },\n            ])\n        );\n\n        $this->expectInvalid($manualSchema2, [\n            [\n                'message' => 'Type IncompleteObject must define one or more fields.',\n            ]\n        ]);\n    }\n\n    // rejects an Object type with incorrectly named fields\n\n    public function testRejectsAnObjectTypeWithIncorrectlyNamedFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = $this->schemaWithFieldType(\n            newObjectType([\n                'name'   => 'SomeObject',\n                'fields' => [\n                    'bad-name-with-dashes' => ['type' => stringType()],\n                ],\n            ])\n        );\n\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"bad-name-with-dashes\" does not.',\n            ]\n        ]);\n    }\n\n    // Skip: accepts an Object type with explicitly allowed legacy named fields\n\n    // Skip: throws with bad value for explicitly allowed legacy names\n\n    // Type System: Fields args must be properly named\n\n    // accepts field args with valid names\n\n    public function testAcceptsFieldArgumentsWithValidNames()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = $this->schemaWithFieldType(\n            newObjectType([\n                'name'   => 'SomeObject',\n                'fields' => [\n                    'goodField' => [\n                        'type' => stringType(),\n                        'args' => [\n                            'goodArg' => ['type' => stringType()],\n                        ],\n                    ],\n                ],\n            ])\n        );\n\n        $this->expectValid($schema);\n    }\n\n    // rejects field arg with invalid names\n\n    public function testRejectsFieldArgumentsWithInvalidNames()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = $this->schemaWithFieldType(\n            newObjectType([\n                'name'   => 'SomeObject',\n                'fields' => [\n                    'badField' => [\n                        'type' => stringType(),\n                        'args' => [\n                            'bad-name-with-dashes' => ['type' => stringType()],\n                        ],\n                    ],\n                ],\n            ])\n        );\n\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"bad-name-with-dashes\" does not.',\n            ]\n        ]);\n    }\n\n    // Type System: Union types must be valid\n\n    // accepts a Union type with member types\n\n    public function testAcceptsAUnionTypeWithMemberTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: GoodUnion\n        }\n        \n        type TypeA {\n          field: String\n        }\n        \n        type TypeB {\n          field: String\n        }\n        \n        union GoodUnion =\n          | TypeA\n          | TypeB\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects a Union type with empty types\n\n    public function testRejectsAUnionTypeWithEmptyTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: BadUnion\n        }\n        \n        union BadUnion\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Union type BadUnion must define one or more member types.',\n                'locations' => [locationShorthandToArray([5, 1])]\n            ]\n        ]);\n    }\n\n    // rejects a Union type with duplicated member type\n\n    public function testRejectsAUnionTypeWithDuplicatedMemberTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: BadUnion\n        }\n        \n        type TypeA {\n          field: String\n        }\n        \n        type TypeB {\n          field: String\n        }\n        \n        union BadUnion =\n          | TypeA\n          | TypeB\n          | TypeA\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Union type BadUnion can only include type TypeA once.',\n                'locations' => locationsShorthandToArray([[14, 5], [16, 5]])\n            ]\n        ]);\n    }\n\n    // rejects a Union type with non-Object members types\n\n    public function testRejectsAUnionTypeWithNonObjectMemberTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: BadUnion\n        }\n        \n        type TypeA {\n          field: String\n        }\n        \n        type TypeB {\n          field: String\n        }\n        \n        union BadUnion =\n          | TypeA\n          | String\n          | TypeB\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Union type BadUnion can only include Object types, it cannot include String.',\n                'locations' => [locationShorthandToArray([15, 5])],\n            ]\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $badUnionMemberTypes = [\n            stringType(),\n            newNonNull($this->someObjectType),\n            newList($this->someObjectType),\n            $this->someInterfaceType,\n            $this->someUnionType,\n            $this->someEnumType,\n            $this->someInputObjectType,\n        ];\n\n        foreach ($badUnionMemberTypes as $memberType) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $badSchema = $this->schemaWithFieldType(\n                newUnionType(['name' => 'BadUnion', 'types' => [$memberType]])\n            );\n\n            $this->expectInvalid($badSchema, [\n                [\n                    'message' => sprintf(\n                        'Union type BadUnion can only include Object types, it cannot include %s.',\n                        (string)$memberType\n                    ),\n                ]\n            ]);\n        }\n    }\n\n    // Type System: Input Objects must have fields\n\n    // accepts an Input Object type with fields\n\n    public function testAcceptsAnInputObjectTypeWithFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field(arg: SomeInputObject): String\n        }\n        \n        input SomeInputObject {\n          field: String\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects an Input Object type with missing fields\n\n    public function testRejectsAnInputObjectTypeWithMissingFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field(arg: SomeInputObject): String\n        }\n        \n        input SomeInputObject\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Input Object type SomeInputObject must define one or more fields.',\n                'locations' => [locationShorthandToArray([5, 1])],\n            ]\n        ]);\n    }\n\n    // rejects an Input Object type with incorrectly typed fields\n\n    public function testRejectsAnInputObjectTypeWithIncorrectlyTypedFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field(arg: SomeInputObject): String\n        }\n        \n        type SomeObject {\n          field: String\n        }\n        \n        union SomeUnion = SomeObject\n        \n        input SomeInputObject {\n          badObject: SomeObject\n          badUnion: SomeUnion\n          goodInputObject: SomeInputObject\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'The type of SomeInputObject.badObject must be Input Type but got: SomeObject.',\n                'locations' => [locationShorthandToArray([12, 3])],\n            ],\n            [\n                'message'   => 'The type of SomeInputObject.badUnion must be Input Type but got: SomeUnion.',\n                'locations' => [locationShorthandToArray([13, 3])],\n            ]\n        ]);\n    }\n\n    // Type System: Enum types must be well defined\n\n    // rejects an Enum type without values\n\n    public function testRejectsAnEnumTypeWithoutValues()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field: SomeEnum\n        }\n        \n        enum SomeEnum\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Enum type SomeEnum must define one or more values.',\n                'locations' => [locationShorthandToArray([5, 1])],\n            ]\n        ]);\n    }\n\n    // rejects an Enum type with duplicate values\n\n    public function testRejectsAnEnumTypeWithDuplicateValues()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field: SomeEnum\n        }\n        \n        enum SomeEnum {\n          SOME_VALUE\n          SOME_VALUE\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Enum type SomeEnum can include value SOME_VALUE only once.',\n                'locations' => locationsShorthandToArray([[6, 3], [7, 3]]),\n            ]\n        ]);\n    }\n\n    // rejects an Enum type with incorrectly named values\n\n    public function testRejectsAnEnumTypeWithIncorrectlyNamedValues()\n    {\n        $schemaWithEnum = function ($name) {\n            return $this->schemaWithFieldType(\n                newEnumType([\n                    'name'   => 'SomeEnum',\n                    'values' => [\n                        $name => [],\n                    ],\n                ])\n            );\n        };\n\n        $badEnumValues = ['#value', '1value', 'KEBAB-CASE'];\n\n        foreach ($badEnumValues as $enumValue) {\n            $this->expectInvalid($schemaWithEnum($enumValue), [\n                [\n                    'message' => sprintf('Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"%s\" does not.', $enumValue)\n                ]\n            ]);\n        }\n\n        $forbiddenEnumValues = ['true', 'false', 'null'];\n\n        foreach ($forbiddenEnumValues as $enumValue) {\n            $this->expectInvalid($schemaWithEnum($enumValue), [\n                [\n                    'message' => sprintf('Enum type SomeEnum cannot include value: %s.', $enumValue)\n                ]\n            ]);\n        }\n    }\n\n    // Type System: Object fields must have output types\n\n    // accepts an output type as an Object field type: ${type}\n\n    public function testAcceptsOutputTypesAsObjectFieldTypes()\n    {\n        foreach ($this->outputTypes as $outputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->objectWithFieldOfType($outputType)\n            );\n            $this->expectValid($schema);\n        }\n    }\n\n    // rejects an empty Object field type\n\n    public function testRejectsAnEmptyObjectFieldType()\n    {\n        $schema = $this->schemaWithFieldType(\n            $this->objectWithFieldOfType(null)\n        );\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'The type of BadObject.badField must be Output Type but got: null.'\n            ]\n        ]);\n    }\n\n    // rejects a non-output type as an Object field type: ${type}\n\n    public function testRejectsNonOutputTypeAsObjectFieldTypes()\n    {\n        foreach ($this->noOutputTypes as $notOutputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->objectWithFieldOfType($notOutputType)\n            );\n            $this->expectInvalid($schema, [\n                [\n                    'message' => \\sprintf(\n                        'The type of BadObject.badField must be Output Type but got: %s.',\n                        toString($notOutputType)\n                    )\n                ]\n            ]);\n        }\n    }\n\n    // rejects with relevant locations for a non-output type as an Object field type\n\n    public function testRejectsWithLocationsForANonOutputTypeAsAnObjectFieldType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          field: [SomeInputObject]\n        }\n        \n        input SomeInputObject {\n          field: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'The type of Query.field must be Output Type but got: [SomeInputObject].',\n                'locations' => [locationShorthandToArray([2, 10])]\n            ]\n        ]);\n    }\n\n    // Type System: Objects can only implement unique interfaces\n\n    // rejects an Object implementing a non-type values\n\n    public function testRejectsAnObjectImplementingANonTypeValues()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'       => 'BadObject',\n                'fields'     => ['f' => ['type' => stringType()]],\n                'interfaces' => [null],\n            ]),\n        ]);\n\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'Type BadObject must only implement Interface types, it cannot implement null.'\n            ]\n        ]);\n    }\n\n    // rejects an Object implementing a non-Interface type\n\n    public function testRejectsAnObjectImplementingANonInterfaceType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: BadObject\n        }\n        \n        input SomeInputObject {\n          field: String\n        }\n        \n        type BadObject implements SomeInputObject {\n          field: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Type BadObject must only implement Interface types, it cannot implement SomeInputObject.',\n                'locations' => [locationShorthandToArray([9, 27])]\n            ]\n        ]);\n    }\n\n    // rejects an Object implementing the same interface twice\n\n    public function testRejectsAnObjectImplementingTheSameInterfaceTwice()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface & AnotherInterface {\n          field: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Type AnotherObject can only implement AnotherInterface once.',\n                'locations' => locationsShorthandToArray([[9, 31], [9, 50]]),\n            ]\n        ]);\n    }\n\n    // rejects an Object implementing the same interface twice due to extension\n\n    public function testRejectsAnObjectImplementingTheSameInterfaceTwiceDueToExtension()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $extendedSchema = extendSchema(\n            $schema,\n            'extend type AnotherObject implements AnotherInterface'\n        );\n\n        $this->expectInvalid($extendedSchema, [\n            [\n                'message'   => 'Type AnotherObject can only implement AnotherInterface once.',\n                'locations' => locationsShorthandToArray([[9, 31], [1, 38]]),\n            ]\n        ]);\n    }\n\n    // Type System: Interface extensions should be valid\n\n    // rejects an Object implementing the extended interface due to missing field\n\n    public function testRejectsAnObjectImplementingTheExtendedInterfaceDueToMissingField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $extendedSchema = extendSchema(\n            $schema,\n            dedent('\n            extend interface AnotherInterface {\n              newField: String\n            }\n            ')\n        );\n\n        $this->expectInvalid($extendedSchema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.newField expected ' .\n                    'but AnotherObject does not provide it.',\n                'locations' => locationsShorthandToArray([[2, 3], [9, 1]]),\n            ]\n        ]);\n    }\n\n    // rejects an Object implementing the extended interface due to missing field args\n\n    public function testRejectsAnObjectImplementingTheExtendedInterfaceDueToMissingFieldArguments()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $extendedSchema = extendSchema(\n            $schema,\n            dedent('\n            extend interface AnotherInterface {\n              newField(test: Boolean): String\n            }\n            \n            extend type AnotherObject {\n              newField: String\n            }\n            ')\n        );\n\n        $this->expectInvalid($extendedSchema, [\n            [\n                'message'   =>\n                    'Interface field argument AnotherInterface.newField(test:) expected ' .\n                    'but AnotherObject.newField does not provide it.',\n                'locations' => locationsShorthandToArray([[2, 12], [6, 3]]),\n            ]\n        ]);\n    }\n\n    // rejects Objects implementing the extended interface due to mismatching interface type\n\n    public function testRejectsObjectsImplementingTheExtendedInterfaceDueToMisMatchingInterfaceType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $extendedSchema = extendSchema(\n            $schema,\n            dedent('\n            extend interface AnotherInterface {\n              newInterfaceField: NewInterface\n            }\n            \n            interface NewInterface {\n              newField: String\n            }\n            \n            interface MismatchingInterface {\n              newField: String\n            }\n            \n            extend type AnotherObject {\n              newInterfaceField: MismatchingInterface\n            }\n            ')\n        );\n\n        $this->expectInvalid($extendedSchema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.newInterfaceField expects type NewInterface but ' .\n                    'AnotherObject.newInterfaceField is type MismatchingInterface.',\n                'locations' => locationsShorthandToArray([[2, 22], [14, 22]]),\n            ]\n        ]);\n    }\n\n    // Type System: Interface fields must have output types\n\n    // accepts an output type as an Interface field type: ${type}\n\n    public function testAcceptsOutputTypesAsInterfaceFieldTypes()\n    {\n        foreach ($this->outputTypes as $outputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->interfaceWithFieldOfType($outputType)\n            );\n            $this->expectValid($schema);\n        }\n    }\n\n    // rejects an empty Interface field type\n\n    public function testRejectsAnEmptyInterfaceFieldType()\n    {\n        $schema = $this->schemaWithFieldType(\n            $this->interfaceWithFieldOfType(null)\n        );\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'The type of BadInterface.badField must be Output Type but got: null.'\n            ]\n        ]);\n    }\n\n    // rejects a non-output type as an Interface field type: ${type}\n\n    public function testRejectsNonOutputTypesAsInterfaceFieldTypes()\n    {\n        foreach ($this->noOutputTypes as $notOutputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->interfaceWithFieldOfType($notOutputType)\n            );\n            $this->expectInvalid($schema, [\n                [\n                    'message' => \\sprintf(\n                        'The type of BadInterface.badField must be Output Type but got: %s.',\n                        toString($notOutputType)\n                    )\n                ]\n            ]);\n        }\n    }\n\n    // rejects a non-output type as an Interface field type with locations\n\n    public function testRejectsWithLocationsForANonOutputTypeAsAnInterfaceFieldType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: SomeInterface\n        }\n        \n        interface SomeInterface {\n          field: SomeInputObject\n        }\n        \n        input SomeInputObject {\n          foo: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'The type of SomeInterface.field must be Output Type but got: SomeInputObject.',\n                'locations' => [locationShorthandToArray([6, 10])]\n            ]\n        ]);\n    }\n\n    // Type System: Field arguments must have input types\n\n    // accepts an input type as a field arg type: ${type}\n\n    public function testAcceptsInputTypesAsFieldArgumentTypes()\n    {\n        foreach ($this->inputTypes as $inputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->objectWithFieldArgumentOfType($inputType)\n            );\n            $this->expectValid($schema);\n        }\n    }\n\n    // rejects an empty field arg type\n\n    public function testRejectsAnEmptyFieldArgumentType()\n    {\n        $schema = $this->schemaWithFieldType(\n            $this->objectWithFieldArgumentOfType(null)\n        );\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'The type of BadObject.badField(badArg:) must be Input Type but got: null.'\n            ]\n        ]);\n    }\n\n    // rejects a non-input type as a field arg type: ${type}\n\n    public function testRejectsNonInputTypesAsFieldArgumentTypes()\n    {\n        foreach ($this->noInputTypes as $notInputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->objectWithFieldArgumentOfType($notInputType)\n            );\n            $this->expectInvalid($schema, [\n                [\n                    'message' => \\sprintf(\n                        'The type of BadObject.badField(badArg:) must be Input Type but got: %s.',\n                        toString($notInputType)\n                    )\n                ]\n            ]);\n        }\n    }\n\n    // rejects a non-input type as a field arg with locations\n\n    public function testRejectsWithLocationsForANonInputTypeAsAFieldArgumentType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test(arg: SomeObject): String\n        }\n        \n        type SomeObject {\n          foo: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'The type of Query.test(arg:) must be Input Type but got: SomeObject.',\n                'locations' => [locationShorthandToArray([2, 8])]\n            ]\n        ]);\n    }\n\n    // Type System: Input Object fields must have input types\n\n    // accepts an input type as an input field type: ${type}\n\n    public function testAcceptsInputTypesAsInputFieldTypes()\n    {\n        foreach ($this->inputTypes as $inputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->inputObjectWithFieldOfType($inputType)\n            );\n            $this->expectValid($schema);\n        }\n    }\n\n    // rejects an empty input field type\n\n    public function testRejectsAnEmptyInputFieldType()\n    {\n        $schema = $this->schemaWithFieldType(\n            $this->inputObjectWithFieldOfType(null)\n        );\n        $this->expectInvalid($schema, [\n            [\n                'message' => 'The type of BadInputObject.badField must be Input Type but got: null.'\n            ]\n        ]);\n    }\n\n    // rejects a non-input type as an input field type: ${type}\n\n    public function testRejectsNonInputTypesAsInputFieldTypes()\n    {\n        foreach ($this->noInputTypes as $notInputType) {\n            $schema = $this->schemaWithFieldType(\n                $this->inputObjectWithFieldOfType($notInputType)\n            );\n            $this->expectInvalid($schema, [\n                [\n                    'message' => \\sprintf(\n                        'The type of BadInputObject.badField must be Input Type but got: %s.',\n                        toString($notInputType)\n                    )\n                ]\n            ]);\n        }\n    }\n\n    // rejects a non-input type as an input object field with locations\n\n    public function testRejectsWithLocationsForANonInputTypeAsAInputFieldType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n        test(arg: SomeInputObject): String\n        }\n        \n        input SomeInputObject {\n          foo: SomeObject\n        }\n        \n        type SomeObject {\n          bar: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'The type of SomeInputObject.foo must be Input Type but got: SomeObject.',\n                'locations' => [locationShorthandToArray([6, 3])]\n            ]\n        ]);\n    }\n\n    // Objects must adhere to Interface they implement\n\n    // accepts an Object which implements an Interface\n\n    public function testAcceptsAnObjectWhichImplementsAnInterface()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: String): String\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // accepts an Object which implements an Interface along with more fields\n\n    public function testAcceptAnObjectWhichImplementsAnInterfaceAlongWithMoreFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: String): String\n          anotherField: String\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // accepts an Object which implements an Interface field along with additional optional arguments\n\n    public function testAcceptsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalOptionalArguments()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: String, anotherInput: String): String\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects an Object missing an Interface field\n\n    public function testRejectsAnObjectMissingAnInterfaceField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          anotherField: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Interface field AnotherInterface.field expected but AnotherObject does not provide it.',\n                'locations' => locationsShorthandToArray([[6, 3], [9, 1]])\n            ]\n        ]);\n    }\n\n    // rejects an Object with an incorrectly typed Interface field\n\n    public function testRejectsAnObjectWithIncorrectlyTypedInterfaceField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: String): Int\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.field expects ' .\n                    'type String but AnotherObject.field is type Int.',\n                'locations' => locationsShorthandToArray([[6, 25], [10, 25]])\n            ]\n        ]);\n    }\n\n    // rejects an Object with a differently typed Interface field\n\n    public function testRejectsAnObjectWithADifferentlyTypedInterfaceField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        type A { foo: String }\n        type B { foo: String }\n        \n        interface AnotherInterface {\n          field: A\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: B\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   => 'Interface field AnotherInterface.field expects type A but AnotherObject.field is type B.',\n                'locations' => locationsShorthandToArray([[9, 10], [13, 10]])\n            ]\n        ]);\n    }\n\n    // accepts an Object with a subtyped Interface field (interface)\n\n    public function testAcceptsAnObjectWithASubtypedInterfaceField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: AnotherInterface\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: AnotherObject\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // accepts an Object with a subtyped Interface field (union)\n\n    public function testAcceptAnObjectWithASubtypedInterfaceField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        type SomeObject {\n          field: String\n        }\n        \n        union SomeUnionType = SomeObject\n        \n        interface AnotherInterface {\n          field: SomeUnionType\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: SomeObject\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects an Object missing an Interface argument\n\n    public function testRejectsAnObjectMissingAnInterfaceArgument()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field argument AnotherInterface.field(input:) expected ' .\n                    'but AnotherObject.field does not provide it.',\n                'locations' => locationsShorthandToArray([[6, 9], [10, 3]])\n            ]\n        ]);\n    }\n\n    // rejects an Object with an incorrectly typed Interface argument\n\n    public function testRejectsAnObjectWithAnIncorrectlyTypedInterfaceArgument()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: Int): String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field argument AnotherInterface.field(input:) expects ' .\n                    'type String but AnotherObject.field(input:) is type Int.',\n                'locations' => locationsShorthandToArray([[6, 16], [10, 16]])\n            ]\n        ]);\n    }\n\n    // rejects an Object with both an incorrectly typed field and argument\n\n    public function testRejectsAnObjectWithBothAnIncorrectlyTypedFieldAndArgument()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: Int): Int\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.field expects type String but ' .\n                    'AnotherObject.field is type Int.',\n                'locations' => locationsShorthandToArray([[6, 25], [10, 22]])\n            ],\n            [\n                'message'   =>\n                    'Interface field argument AnotherInterface.field(input:) expects ' .\n                    'type String but AnotherObject.field(input:) is type Int.',\n                'locations' => locationsShorthandToArray([[6, 16], [10, 16]])\n            ]\n        ]);\n    }\n\n    // rejects an Object which implements an Interface field along with additional required arguments\n\n    public function testRejectsAnObjectWhichImplementsAnInterfaceFieldAlongWithAdditionalRequiredArguments()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field(input: String): String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field(input: String, anotherInput: String!): String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Object field argument AnotherObject.field(anotherInput:) is of ' .\n                    'required type String! but is not also provided by the Interface ' .\n                    'field AnotherInterface.field.',\n                'locations' => locationsShorthandToArray([[10, 24], [6, 3]])\n            ]\n        ]);\n    }\n\n    // accepts an Object with an equivalently wrapped Interface field type\n\n    public function testAcceptsAnObjectWithAnEquivalentlyWrappedInterfaceFieldType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: [String]!\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: [String]!\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects an Object with a non-list Interface field list type\n\n    public function testRejectsAnObjectWithANonListInterfaceFieldListType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: [String]\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.field expects type [String] ' .\n                    'but AnotherObject.field is type String.',\n                'locations' => locationsShorthandToArray([[6, 10], [10, 10]])\n            ]\n        ]);\n    }\n\n    // rejects an Object with a list Interface field non-list type\n\n    public function testRejectsAnObjectWithAListInterfaceFieldNonListType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: [String]\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.field expects type String but ' .\n                    'AnotherObject.field is type [String].',\n                'locations' => locationsShorthandToArray([[6, 10], [10, 10]])\n            ]\n        ]);\n    }\n\n    // accepts an Object with a subset non-null Interface field type\n\n    public function testAcceptsAnObjectWithASubsetNonNullInterfaceFieldType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String!\n        }\n        '));\n\n        $this->expectValid($schema);\n    }\n\n    // rejects an Object with a superset nullable Interface field type\n\n    public function testRejectsAnObjectWithASupersetNullableInterfaceFieldType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = buildSchema(dedent('\n        type Query {\n          test: AnotherObject\n        }\n        \n        interface AnotherInterface {\n          field: String!\n        }\n        \n        type AnotherObject implements AnotherInterface {\n          field: String\n        }\n        '));\n\n        $this->expectInvalid($schema, [\n            [\n                'message'   =>\n                    'Interface field AnotherInterface.field expects type String! ' .\n                    'but AnotherObject.field is type String.',\n                'locations' => locationsShorthandToArray([[6, 10], [10, 10]])\n            ]\n        ]);\n    }\n\n    protected function expectValid($schema)\n    {\n        $errors = $this->schemaValidator->validate($schema);\n        $this->assertEquals([], $errors);\n    }\n\n    protected function expectInvalid($schema, $expectedErrors)\n    {\n        $errors = $this->schemaValidator->validate($schema);\n        $this->assertArraySubset($expectedErrors, \\array_map(function (ValidationExceptionInterface $error) {\n            return $error->toArray();\n        }, $errors));\n    }\n\n    protected function withModifiers($types)\n    {\n        return \\array_merge(\n            $types,\n            array_map(function ($type) {\n                return newList($type);\n            }, $types),\n            array_map(function ($type) {\n                return newNonNull($type);\n            }, $types),\n            array_map(function ($type) {\n                return newNonNull(newList($type));\n            }, $types)\n        );\n    }\n\n    protected function schemaWithFieldType($fieldType)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => ['f' => ['type' => $fieldType]]\n            ]),\n            'types' => [$fieldType],\n        ]);\n    }\n\n    protected function objectWithFieldOfType($fieldType)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newObjectType([\n            'name'   => 'BadObject',\n            'fields' => [\n                'badField' => ['type' => $fieldType],\n            ],\n        ]);\n    }\n\n    protected function interfaceWithFieldOfType($fieldType)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newInterfaceType([\n            'name'   => 'BadInterface',\n            'fields' => [\n                'badField' => ['type' => $fieldType],\n            ],\n        ]);\n    }\n\n    protected function objectWithFieldArgumentOfType($argumentType)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newObjectType([\n            'name'   => 'BadObject',\n            'fields' => [\n                'badField' => [\n                    'type' => stringType(),\n                    'args' => [\n                        'badArg' => ['type' => $argumentType],\n                    ],\n                ],\n            ],\n        ]);\n    }\n\n    protected function inputObjectWithFieldOfType($fieldType)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newObjectType([\n            'name'   => 'BadObject',\n            'fields' => [\n                'badField' => [\n                    'type' => stringType(),\n                    'args' => [\n                        'badArg' => [\n                            'type' => newInputObjectType([\n                                'name'   => 'BadInputObject',\n                                'fields' => [\n                                    'badField' => ['type' => $fieldType],\n                                ],\n                            ])\n                        ],\n                    ],\n                ],\n            ],\n        ]);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Type/DefinitionTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Type;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ListType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\TypeInterface;\nuse Digia\\GraphQL\\Type\\Definition\\TypeNameEnum;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\isOutputType;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\newUnionType;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass DefinitionTest extends TestCase\n{\n    /**\n     * @var ObjectType\n     */\n    protected $blogImage;\n\n    /**\n     * @var ObjectType\n     */\n    protected $blogAuthor;\n\n    /**\n     * @var ObjectType\n     */\n    protected $blogArticle;\n\n    /**\n     * @var ObjectType\n     */\n    protected $blogQuery;\n\n    /**\n     * @var ObjectType\n     */\n    protected $blogMutation;\n\n    /**\n     * @var ObjectType\n     */\n    protected $blogSubscription;\n\n    /**\n     * @var ObjectType\n     */\n    protected $objectType;\n\n    /**\n     * @var InterfaceType\n     */\n    protected $interfaceType;\n\n    /**\n     * @var UnionType\n     */\n    protected $unionType;\n\n    /**\n     * @var EnumType\n     */\n    protected $enumType;\n\n    /**\n     * @var InputObjectType\n     */\n    protected $inputObjectType;\n\n    /**\n     * @var ScalarType\n     */\n    protected $scalarType;\n\n    /**\n     * @inheritdoc\n     */\n    public function setUp()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->blogImage = newObjectType([\n            'name'   => 'Image',\n            'fields' => [\n                'url'    => ['type' => stringType()],\n                'width'  => ['type' => intType()],\n                'height' => ['type' => intType()],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->blogAuthor = newObjectType([\n            'name'   => 'Author',\n            'fields' => function () {\n                return [\n                    'id'            => ['type' => stringType()],\n                    'name'          => ['type' => stringType()],\n                    'pic'           => [\n                        'type' => $this->blogImage,\n                        'args' => [\n                            'width'  => ['type' => intType()],\n                            'height' => ['type' => intType()],\n                        ],\n                    ],\n                    'recentArticle' => ['type' => $this->blogArticle],\n                ];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->blogArticle = newObjectType([\n            'name'   => 'Article',\n            'fields' => [\n                'id'          => ['type' => stringType()],\n                'isPublished' => ['type' => booleanType()],\n                'author'      => ['type' => $this->blogAuthor],\n                'title'       => ['type' => stringType()],\n                'body'        => ['type' => stringType()],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->blogQuery = newObjectType([\n            'name'   => 'Query',\n            'fields' => [\n                'article' => [\n                    'args' => ['id' => ['type' => stringType()]],\n                    'type' => $this->blogArticle,\n                ],\n                'feed'    => [\n                    'type' => newList($this->blogArticle),\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->blogMutation = newObjectType([\n            'name'   => 'Mutation',\n            'fields' => [\n                'writeArticle' => [\n                    'type' => $this->blogArticle,\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->blogSubscription = newObjectType([\n            'name'   => 'Subscription',\n            'fields' => [\n                'articleSubscribe' => [\n                    'args' => ['id' => ['type' => stringType()]],\n                    'type' => $this->blogArticle,\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->objectType = newObjectType(['name' => 'Object']);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->interfaceType = newInterfaceType(['name' => 'Interface']);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->unionType = newUnionType(['name' => 'Union', 'types' => [$this->objectType]]);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->enumType = newEnumType(['name' => 'Enum', 'values' => ['foo' => []]]);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->inputObjectType = newInputObjectType(['name' => 'InputObject']);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->scalarType = newScalarType([\n            'name'         => 'Scalar',\n            'serialize'    => function () {\n            },\n            'parseValue'   => function () {\n            },\n            'parseLiteral' => function () {\n            },\n        ]);\n    }\n\n    /**\n     * @param TypeInterface $type\n     * @return Schema\n     * @throws InvariantException\n     */\n    protected function schemaWithField(TypeInterface $type): Schema\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'field' => ['type' => $type],\n                ],\n            ]),\n            'types' => [$type],\n        ]);\n    }\n\n    /**\n     * @param mixed $resolveValue\n     * @return Schema\n     * @throws InvariantException\n     */\n    protected function schemaWithObjectWithFieldResolver($resolveValue): Schema\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $badResolverType = newObjectType([\n            'name'   => 'BadResolver',\n            'fields' => [\n                'badField' => [\n                    'type'    => stringType(),\n                    'resolve' => $resolveValue\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'f' => ['type' => $badResolverType],\n                ],\n            ])\n        ]);\n    }\n\n    // Type System: Example\n\n    // defines a query only schema\n\n    public function testQueryOnlySchema()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => $this->blogQuery,\n        ]);\n\n        $this->assertEquals($this->blogQuery, $schema->getQueryType());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $articleField = $this->blogQuery->getFields()['article'];\n\n        $this->assertEquals($this->blogArticle, $articleField->getType());\n        $this->assertEquals($this->blogArticle->getName(), $articleField->getType()->getName());\n        $this->assertSame('article', $articleField->getName());\n\n        /** @var ObjectType $articleFieldType */\n        $articleFieldType = $articleField->getType();\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $titleField = $articleFieldType->getFields()['title'];\n        $this->assertSame('title', $titleField->getName());\n        $this->assertSame(stringType(), $titleField->getType());\n        $this->assertSame('String', $titleField->getType()->getName());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $authorField = $articleFieldType->getFields()['author'];\n\n        /** @var ObjectType $authorFieldType */\n        $authorFieldType = $authorField->getType();\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $recentArticleField = $authorFieldType->getFields()['recentArticle'];\n        $this->assertEquals($this->blogArticle, !$recentArticleField ?: $recentArticleField->getType());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $feedField = $this->blogQuery->getFields()['feed'];\n\n        /** @var ListType $feedFieldType */\n        $feedFieldType = $feedField->getType();\n        $this->assertEquals($this->blogArticle, $feedFieldType->getOfType());\n\n        $this->assertSame('feed', $feedField->getName());\n    }\n\n    // defines a mutation schema\n\n    public function testMutationSchema()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'mutation' => $this->blogMutation,\n        ]);\n\n        $this->assertEquals($this->blogMutation, $schema->getMutationType());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $writeArticleField = $this->blogMutation->getFields()['writeArticle'];\n\n        $this->assertEquals($this->blogArticle, $writeArticleField->getType());\n        $this->assertSame('Article', $writeArticleField->getType()->getName());\n        $this->assertSame('writeArticle', $writeArticleField->getName());\n    }\n\n    // defines a subscription schema\n\n    public function testSubscriptionSchema()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'subscription' => $this->blogSubscription,\n        ]);\n\n        $this->assertEquals($this->blogSubscription, $schema->getSubscriptionType());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $articleSubscribeField = $this->blogSubscription->getFields()['articleSubscribe'];\n\n        $this->assertEquals($this->blogArticle, $articleSubscribeField->getType());\n        $this->assertSame('Article', $articleSubscribeField->getType()->getName());\n        $this->assertSame('articleSubscribe', $articleSubscribeField->getName());\n    }\n\n    // defines an enum type with deprecated value\n\n    public function testEnumTypeWithDeprecatedValue()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumWithDeprecatedValue = newEnumType([\n            'name'   => 'EnumWithDeprecatedValue',\n            'values' => ['foo' => ['deprecationReason' => 'Just because']],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumValue = $enumWithDeprecatedValue->getValues()[0];\n\n        $this->assertSame('foo', $enumValue->getName());\n        $this->assertTrue($enumValue->isDeprecated());\n        $this->assertSame('Just because', $enumValue->getDeprecationReason());\n        $this->assertSame('foo', $enumValue->getValue());\n    }\n\n    // defines an enum type with a value of `null`\n\n    public function testEnumTypeWithAValueOfNull()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumTypeWithNullValue = newEnumType([\n            'name'   => 'EnumWithNullValue',\n            'values' => ['NULL' => ['value' => null]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumValue = $enumTypeWithNullValue->getValues()[0];\n        $this->assertSame('NULL', $enumValue->getName());\n        $this->assertNull($enumValue->getDescription());\n        $this->assertSame(false, $enumValue->isDeprecated());\n        $this->assertNull($enumValue->getValue());\n        $this->assertNull($enumValue->getAstNode());\n    }\n\n    // defines an object type with deprecated field\n\n    public function testObjectWithDeprecatedField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $typeWithDeprecatedField = newObjectType([\n            'name'   => 'foo',\n            'fields' => [\n                'bar' => [\n                    'type'              => stringType(),\n                    'deprecationReason' => 'A terrible reason',\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $field = $typeWithDeprecatedField->getFields()['bar'];\n\n        $this->assertSame(stringType(), $field->getType());\n        $this->assertSame('A terrible reason', $field->getDeprecationReason());\n        $this->assertTrue($field->isDeprecated());\n        $this->assertSame('bar', $field->getName());\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEmpty($field->getArguments());\n    }\n\n    // includes nested input objects in the map\n\n    public function testIncludesNestedInputObjectsInSchemaTypeMap()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $nestedInputObject = newInputObjectType([\n            'name'   => 'NestedInputObject',\n            'fields' => ['value' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someInputObject = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => ['nested' => ['type' => $nestedInputObject]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someMutation = newObjectType([\n            'name'   => 'SomeMutation',\n            'fields' => [\n                'mutateSomething' => [\n                    'type' => $this->blogArticle,\n                    'args' => ['input' => ['type' => $someInputObject]],\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someSubscription = newObjectType([\n            'name'   => 'SomeSubscription',\n            'fields' => [\n                'subscribeToSomething' => [\n                    'type' => $this->blogArticle,\n                    'args' => ['input' => ['type' => $someInputObject]],\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query'        => $this->blogQuery,\n            'mutation'     => $someMutation,\n            'subscription' => $someSubscription,\n        ]);\n\n        $this->assertEquals($nestedInputObject, $schema->getTypeMap()[$nestedInputObject->getName()]);\n    }\n\n    // includes interface possible types in the type map\n\n    public function testIncludesInterfacePossibleTypesInSchemaTypeMap()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someInterface = newInterfaceType([\n            'name'   => 'SomeInterface',\n            'fields' => [\n                'f' => ['type' => intType()],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someSubtype = newObjectType([\n            'name'       => 'SomeSubtype',\n            'fields'     => [\n                'f' => ['type' => intType()],\n            ],\n            'interfaces' => [$someInterface],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => [\n                    'iface' => ['type' => $someInterface],\n                ],\n            ]),\n            'types' => [$someSubtype],\n        ]);\n\n        $this->assertEquals($someSubtype, $schema->getTypeMap()[$someSubtype->getName()]);\n    }\n\n    // includes interfaces' thunk subtypes in the type map\n\n    public function testIncludesInterfacesThunkSubtypesInTheSchemaTypeMap()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someInterface = newInterfaceType([\n            'name'   => 'SomeInterface',\n            'fields' => ['f' => ['type' => intType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $someSubtype = newObjectType([\n            'name'       => 'SomeSubtype',\n            'fields'     => ['f' => ['type' => intType()]],\n            'interfaces' => function () use ($someInterface) {\n                return [$someInterface];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'Query',\n                'fields' => ['iface' => ['type' => $someInterface]],\n            ]),\n            'types' => [$someSubtype],\n        ]);\n\n        $this->assertEquals($someSubtype, $schema->getTypeMap()[$someSubtype->getName()]);\n    }\n\n    // stringifies simple types\n\n    public function testStringifySimpleTypes()\n    {\n        $this->assertEquals(TypeNameEnum::INT, (string)intType());\n        $this->assertEquals('Article', (string)$this->blogArticle);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('Interface', (string)newInterfaceType(['name' => 'Interface']));\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('Union', (string)newUnionType(['name' => 'Union']));\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('Enum', (string)newEnumType(['name' => 'Enum']));\n        $this->assertEquals(TypeNameEnum::INT, (string)intType());\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('Int!', (string)newNonNull(intType()));\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('[Int]!', (string)newNonNull(newList(intType())));\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('[Int!]', (string)newList(newNonNull(intType())));\n        $this->assertEquals('[[Int]]', (string)newList(newList(intType())));\n    }\n\n    // identifies input types\n\n    /**\n     * @param TypeInterface|null $type\n     * @param mixed              $answer\n     * @dataProvider identifiesInputTypesDataProvider\n     * @throws \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testIdentifiesInputTypes(?TypeInterface $type, $answer)\n    {\n        $this->assertEquals($answer, isOutputType($type));\n        $this->assertEquals($answer, isOutputType(newList($type)));\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals($answer, isOutputType(newNonNull($type)));\n    }\n\n    public function identifiesInputTypesDataProvider(): array\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        // We cannot use the class fields here because they do not get instantiated for data providers.\n        return [\n            [intType(), true],\n            [newObjectType(['name' => 'Object']), true],\n            [newInterfaceType(['name' => 'Interface']), true],\n            [newUnionType(['name' => 'Union']), true],\n            [newEnumType(['name' => 'Enum']), true],\n            [newInputObjectType(['name' => 'InputObjectType']), false],\n        ];\n    }\n\n    // prohibits nesting NonNull inside NonNull\n\n    public function testProhibitsNestingNonNullInsideNonNull()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('Expected Int! to be a GraphQL nullable type.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        newNonNull(newNonNull(intType()));\n\n        $this->addToAssertionCount(1);\n    }\n\n    // allows a thunk for Union member types\n\n    public function testAllowsAThunkForUnionMemberTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $union = newUnionType([\n            'name'  => 'ThunkUnion',\n            'types' => function () {\n                return [$this->objectType];\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $types = $union->getTypes();\n\n        $this->assertCount(1, $types);\n        $this->assertEquals($this->objectType, $types[0]);\n    }\n\n    // does not mutate passed field definitions\n\n    public function testDoesNotMutatePassedFieldDefinitions()\n    {\n        $fields = [\n            'field1' => ['type' => stringType()],\n            'field2' => [\n                'type' => stringType(),\n                'args' => [\n                    'id' => ['type' => stringType()],\n                ],\n            ],\n        ];\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $testObject1 = newObjectType([\n            'name'   => 'Test1',\n            'fields' => $fields,\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $testObject2 = newObjectType([\n            'name'   => 'Test2',\n            'fields' => $fields,\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals($testObject2->getFields(), $testObject1->getFields());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $testInputObject1 = newInputObjectType([\n            'name'   => 'Test1',\n            'fields' => $fields,\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $testInputObject2 = newInputObjectType([\n            'name'   => 'Test2',\n            'fields' => $fields,\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals($testInputObject2->getFields(), $testInputObject1->getFields());\n\n        $this->assertEquals(stringType(), $fields['field1']['type']);\n        $this->assertEquals(stringType(), $fields['field2']['type']);\n        $this->assertEquals(stringType(), $fields['field2']['args']['id']['type']);\n    }\n\n    // Field config must be object\n\n    // accepts an Object type with a field function\n\n    public function testAcceptsAnObjectTypeWithAFieldFunction()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objectType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => function () {\n                return ['f' => ['type' => stringType()]];\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(stringType(), $objectType->getField('f')->getType());\n    }\n\n    // rejects an Object type field with undefined config\n\n    public function testRejectsAnObjectTypeFieldWithNullConfig()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => ['f' => null],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeObject.f field config must be an associative array.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Object type with incorrectly typed fields\n\n    function testRejectsAnObjectTypeWithIncorrectlyTypedFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => [['f' => null]],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeObject fields must be an associative array with field names as keys or a ' .\n            'callable which returns such an array.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Object type with a field function that returns incorrect type\n\n    public function testRejectsAnObjectTypeWithAFieldFunctionThatReturnsIncorrectType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => function () {\n                return [['f' => null]];\n            },\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeObject fields must be an associative array with field names as keys or a ' .\n            'callable which returns such an array.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Field arg config must be object\n\n    // accepts an Object type with field args\n\n    public function testAcceptsAnObjectTypeWithFieldArgs()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => [\n                'goodField' => [\n                    'type' => stringType(),\n                    'args' => [\n                        'goodArg' => ['type' => stringType()],\n                    ],\n                ],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Object type with incorrectly typed field args\n\n    public function testRejectsAnObjectTypeWithIncorrectlyTypedFieldArgs()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'   => 'SomeObject',\n            'fields' => [\n                'badField' => [\n                    'type' => stringType(),\n                    'args' => [['badArg' => stringType()]],\n                ],\n            ],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeObject.badField args must be an object with argument names as keys.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // does not allow isDeprecated without deprecationReason on field\n\n    public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnField()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $oldObject = newObjectType([\n            'name'   => 'OldObject',\n            'fields' => [\n                'field' => [\n                    'type'         => stringType(),\n                    'isDeprecated' => true,\n                ],\n            ],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('OldObject.field should provide \"deprecationReason\" instead of \"isDeprecated\".');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField($oldObject);\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Object interfaces must be array\n\n    // accepts an Object type with array interfaces\n\n    public function testAcceptsAnObjectTypeWithArrayInterfaces()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'       => 'SomeObject',\n            'interfaces' => [$this->interfaceType],\n            'fields'     => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals($this->interfaceType, $objType->getInterfaces()[0]);\n    }\n\n    // accepts an Object type with interfaces as a function returning an array\n\n    public function testAcceptsAnObjectTypeWithInterfacesAsAFunctionReturningAnArray()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'       => 'SomeObject',\n            'interfaces' => [$this->interfaceType],\n            'fields'     => [\n                'f' => function () {\n                    return ['type' => stringType()];\n                },\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals($this->interfaceType, $objType->getInterfaces()[0]);\n    }\n\n    // rejects an Object type with incorrectly typed interfaces\n\n    public function testRejectsAnObjectTypeWithIncorrectlyTypedInterfaces()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'       => 'SomeObject',\n            'interfaces' => '',\n            'fields'     => ['f' => ['type' => stringType()]],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeObject interfaces must be an array or a function which returns an array.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getInterfaces();\n    }\n\n    // rejects an Object type with interfaces as a function returning an incorrect type\n\n    public function testRejectsAnObjectTypeWithInterfacesAsAFunctionReturningAnIncorrectType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType = newObjectType([\n            'name'       => 'SomeObject',\n            'interfaces' => function () {\n                return '';\n            },\n            'fields'     => ['f' => ['type' => stringType()]],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeObject interfaces must be an array or a function which returns an array.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objType->getInterfaces();\n    }\n\n    // Type System: Object fields must have valid resolve values\n\n    // accepts a lambda as an Object field resolver\n\n    public function testAcceptsALambdaAsAnObjectFieldResolver()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithObjectWithFieldResolver(function () {\n            return [];\n        });\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an empty Object field resolver\n\n    public function testRejectsAnEmptyArrayFieldResolver()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'BadResolver.badField field resolver must be a function if provided, but got: Array.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithObjectWithFieldResolver([]);\n\n        $this->addToAssertionCount(1);\n    }\n\n    // ejects a constant scalar value resolver\n\n    public function testRejectsAnScalarFieldResolver()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'BadResolver.badField field resolver must be a function if provided, but got: 0.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithObjectWithFieldResolver(0);\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: Interface types must be resolvable\n\n    // accepts an Interface type defining resolveType\n\n    public function testAcceptsAnInterfaceTypeDefiningResolveType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $anotherInterfaceType = newInterfaceType([\n            'name'        => 'AnotherInterface',\n            'fields'      => ['f' => ['type' => stringType()]],\n            'resolveType' => function () {\n                return '';\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newObjectType([\n                'name'       => 'SomeObject',\n                'interfaces' => [$anotherInterfaceType],\n                'fields'     => ['f' => ['type' => stringType()]],\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // accepts an Interface with implementing type defining isTypeOf\n\n    public function testAcceptsAnInterfaceTypeWithImplementingTypeDefiningIsTypeOf()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $anotherInterfaceType = newInterfaceType([\n            'name'   => 'AnotherInterface',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newObjectType([\n                'name'       => 'SomeObject',\n                'interfaces' => [$anotherInterfaceType],\n                'fields'     => ['f' => ['type' => stringType()]],\n                'isTypeOf'   => function () {\n                    return true;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // accepts an Interface type defining resolveType with implementing type defining isTypeOf\n\n    public function testAcceptsAnInterfaceTypeDefiningResolveTypeWithImplementingTypeDefiningIsTypeOf()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $anotherInterfaceType = newInterfaceType([\n            'name'        => 'AnotherInterface',\n            'fields'      => ['f' => ['type' => stringType()]],\n            'resolveType' => function () {\n                return '';\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newObjectType([\n                'name'       => 'SomeObject',\n                'interfaces' => [$anotherInterfaceType],\n                'fields'     => ['f' => ['type' => stringType()]],\n                'isTypeOf'   => function () {\n                    return true;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Interface type with an incorrect type for resolveType\n\n    public function testRejectsAnInterfaceTypeWithAnIncorrectTypeForResolveType()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('AnotherInterface must provide \"resolveType\" as a function.');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        newInterfaceType([\n            'name'        => 'AnotherInterface',\n            'resolveType' => '',\n            'fields'      => ['f' => ['type' => stringType()]],\n        ]);\n    }\n\n    // Type System: Union types must be resolvable\n\n    // accepts a Union type defining resolveType\n\n    public function testAcceptsUnionTypeDefiningResolveType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'  => 'SomeUnion',\n                'types' => [$this->objectType],\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // accepts a Union of Object types defining isTypeOf\n\n    public function testAcceptsAUnionOfObjectTypesDefiningIsTypeOf()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objectWithIsTypeOf = newObjectType([\n            'name'     => 'ObjectWithIsTypeOf',\n            'fields'   => ['f' => ['type' => stringType()]],\n            'isTypeOf' => function () {\n                return true;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'  => 'SomeUnion',\n                'types' => [$objectWithIsTypeOf],\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // accepts a Union type defining resolveType of Object types defining isTypeOf\n\n    public function testAcceptsAUnionTypeDefiningResolveTypeOfObjectTypesDefiningIsTypeOf()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objectWithIsTypeOf = newObjectType([\n            'name'     => 'ObjectWithIsTypeOf',\n            'fields'   => ['f' => ['type' => stringType()]],\n            'isTypeOf' => function () {\n                return true;\n            }\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'        => 'SomeUnion',\n                'types'       => [$objectWithIsTypeOf],\n                'resolveType' => function () {\n                    return 'ObjectWithIsTypeOf';\n                }\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Interface type with an incorrect type for resolveType\n\n    public function testRejectsAnInterfaceWithAnIncorrectTypeForResolveType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $objectWithIsTypeOf = newObjectType([\n            'name'     => 'ObjectWithIsTypeOf',\n            'fields'   => ['f' => ['type' => stringType()]],\n            'isTypeOf' => function () {\n                return true;\n            }\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeUnion must provide \"resolveType\" as a function.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'        => 'SomeUnion',\n                'types'       => [$objectWithIsTypeOf],\n                'resolveType' => ''\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: Scalar types must be serializable\n\n    // accepts a Scalar type defining serialize\n\n    public function testAcceptsAScalarTypeDefiningSerialize()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name'      => 'SomeScalar',\n                'serialize' => function () {\n                    return null;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Scalar type not defining serialize\n\n    public function testRejectsAScalarTypeNotDefiningSerialize()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeScalar must provide \"serialize\" function. If this custom Scalar ' .\n            'is also used as an input type, ensure \"parseValue\" and \"parseLiteral\" ' .\n            'functions are also provided.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name' => 'SomeScalar',\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Scalar type defining serialize with an incorrect type\n\n    public function testRejectsAScalarTypeDefiningSerializeWithAnIncorrectType()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeScalar must provide \"serialize\" function. If this custom Scalar ' .\n            'is also used as an input type, ensure \"parseValue\" and \"parseLiteral\" ' .\n            'functions are also provided.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name'      => 'SomeScalar',\n                'serialize' => '',\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // accepts a Scalar type defining parseValue and parseLiteral\n\n    public function testAcceptsAScalarTypeDefiningParseValueAndParseLiteral()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name'         => 'SomeScalar',\n                'serialize'    => function () {\n                    return null;\n                },\n                'parseValue'   => function () {\n                    return null;\n                },\n                'parseLiteral' => function () {\n                    return null;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Scalar type defining parseValue but not parseLiteral\n\n    public function testRejectsAScalarTypeDefiningParseValueButNotParseLiteral()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeScalar must provide both \"parseValue\" and \"parseLiteral\" functions.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name'       => 'SomeScalar',\n                'serialize'  => function () {\n                    return null;\n                },\n                'parseValue' => function () {\n                    return null;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Scalar type defining parseLiteral but not parseValue\n\n    public function testRejectsAScalarTypeDefiningParseLiteralButNotParseValue()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeScalar must provide both \"parseValue\" and \"parseLiteral\" functions.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name'         => 'SomeScalar',\n                'serialize'    => function () {\n                    return null;\n                },\n                'parseLiteral' => function () {\n                    return null;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Scalar type defining parseValue and parseLiteral with an incorrect type\n\n    public function testRejectsAScalarTypeDefiningParseValueAndParseLiteralWithAnIncorrectType()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeScalar must provide both \"parseValue\" and \"parseLiteral\" functions.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newScalarType([\n                'name'         => 'SomeScalar',\n                'serialize'    => function () {\n                    return null;\n                },\n                'parseValue'   => '',\n                'parseLiteral' => '',\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: Object types must be assertable\n\n    // accepts an Object type with an isTypeOf function\n\n    public function testAcceptsAnObjectTypeWithAnIsTypeOfFunction()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newObjectType([\n                'name'     => 'AnotherObject',\n                'fields'   => ['f' => ['type' => stringType()]],\n                'isTypeOf' => function () {\n                    return true;\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Object type with an incorrect type for isTypeOf\n\n    public function testRejectsAnObjectTypeWithAnIncorrectTypeForIsTypeOf()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('AnotherObject must provide \"isTypeOf\" as a function.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newObjectType([\n                'name'     => 'AnotherObject',\n                'fields'   => ['f' => ['type' => stringType()]],\n                'isTypeOf' => '',\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: Union types must be array\n\n    // accepts a Union type with array types\n\n    public function testAcceptsAnUnionTypeWithArrayTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'  => 'SomeUnion',\n                'types' => [$this->objectType],\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // accepts a Union type with function returning an array of types\n\n    public function testAcceptsAnUnionTypeWithFunctionReturningAnArrayOfTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'  => 'SomeUnion',\n                'types' => function () {\n                    return [$this->objectType];\n                },\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Union type without types\n\n    public function testRejectsAnUnionWithoutTypes()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name' => 'SomeUnion',\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Union type with incorrectly typed types\n\n    public function testRejectsAUnionTypeWithIncorrectlyTypedTypes()\n    {\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'Must provide array of types or a function which returns such an array for Union SomeUnion.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->schemaWithField(\n            newUnionType([\n                'name'  => 'SomeUnion',\n                'types' => ''\n            ])\n        );\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: Input Objects must have fields\n\n    // accepts an Input Object type with fields\n\n    public function testAcceptsAnInputObjectTypeWithFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $field = $inputObjectType->getField('f');\n        $this->assertEquals(stringType(), $field->getType());\n    }\n\n    // accepts an Input Object type with a field function\n\n    public function testAcceptsAnInputObjectTypeWithAFieldFunction()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => function () {\n                return ['f' => ['type' => stringType()]];\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $field = $inputObjectType->getField('f');\n        $this->assertEquals(stringType(), $field->getType());\n    }\n\n    // rejects an Input Object type with incorrect fields\n\n    public function testRejectsAnInputObjectTypeWithIncorrectFields()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => '',\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeInputObject fields must be an associative array with field names as keys or a ' .\n            'function which returns such an array.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType->getField('f');\n    }\n\n    // rejects an Input Object type with fields function that returns incorrect type\n\n    public function testRejectsAnInputObjectTypeWithFieldsFunctionThatReturnsIncorrectType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => function () {\n                return '';\n            },\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeInputObject fields must be an associative array with field names as keys or a ' .\n            'function which returns such an array.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType->getField('f');\n    }\n\n    // Type System: Input Object fields must not have resolvers\n\n    // rejects an Input Object type with resolvers\n\n    public function testRejectsAnInputObjectTypeWithResolvers()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => [\n                'f' => [\n                    'type'    => stringType(),\n                    'resolve' => function () {\n                        return 0;\n                    }\n                ],\n            ],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeInputObject.f field type has a resolve property, ' .\n            'but Input Types cannot define resolvers.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Input Object type with resolver constant\n\n    public function testRejectsAnInputObjectTypeWithIncorrectlyTypedResolver()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType = newInputObjectType([\n            'name'   => 'SomeInputObject',\n            'fields' => [\n                'f' => [\n                    'type'    => stringType(),\n                    'resolve' => ''\n                ],\n            ],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeInputObject.f field type has a resolve property, ' .\n            'but Input Types cannot define resolvers.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $inputObjectType->getFields();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: Enum types must be well defined\n\n    // accepts a well defined Enum type with empty value definition\n\n    public function testAcceptsAWellDefinedEnumTypeWithEmptyValueDefinition()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => [\n                'FOO' => [],\n                'BAR' => [],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('FOO', $enumType->getValue('FOO')->getValue());\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals('BAR', $enumType->getValue('BAR')->getValue());\n    }\n\n    // accepts a well defined Enum type with internal value definition\n\n    public function testAcceptsAWellDefinedEnumTypeWithInternalValueDefinition()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => [\n                'FOO' => ['value' => 10],\n                'BAR' => ['value' => 20],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(10, $enumType->getValue('FOO')->getValue());\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertEquals(20, $enumType->getValue('BAR')->getValue());\n    }\n\n    // rejects an Enum type with incorrectly typed values\n\n    public function testRejectsAnEnumWithIncorrectlyTypedValues()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => [['FOO' => 10]],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage('SomeEnum values must be an associative array with value names as keys.');\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType->getValues();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Enum type with missing value definition\n\n    public function testRejectsAnEnumTypeWithMissingValueDefinition()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => ['FOO' => null],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeEnum.FOO must refer to an object with a \"value\" key representing ' .\n            'an internal value but got: null.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType->getValues();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects an Enum type with incorrectly typed value definition\n\n    public function testRejectsAnEnumTypeWithIncorrectlyTypedValueDefinition()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => ['FOO' => 10],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeEnum.FOO must refer to an object with a \"value\" key representing ' .\n            'an internal value but got: 10.'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType->getValues();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // does not allow isDeprecated without deprecationReason on enum\n\n    public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnEnum()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType = newEnumType([\n            'name'   => 'SomeEnum',\n            'values' => ['FOO' => ['isDeprecated' => true]],\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'SomeEnum.FOO should provide \"deprecationReason\" instead of \"isDeprecated\".'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $enumType->getValues();\n\n        $this->addToAssertionCount(1);\n    }\n\n    // Type System: List must accept only types\n\n    // accepts an type as item type of list\n\n    public function testAcceptsTypesAsItemOfList()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $types = [\n            stringType(),\n            $this->scalarType,\n            $this->objectType,\n            $this->unionType,\n            $this->interfaceType,\n            $this->enumType,\n            $this->inputObjectType,\n            newList(stringType()),\n            newNonNull(stringType()),\n        ];\n\n        foreach ($types as $type) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            newList($type);\n            $this->addToAssertionCount(1);\n        }\n    }\n\n    // rejects a non-type as item type of list\n\n    public function testRejectsANonTypesAsItemTypeOfList()\n    {\n        $notTypes = [\n            'Object'         => new \\stdClass(),\n            'Array'          => [],\n            'Function'       => function () {\n                return null;\n            },\n            '(empty string)' => '',\n            'null'           => null,\n            'true'           => true,\n            'false'          => false,\n            'String'         => 'String',\n        ];\n\n        foreach ($notTypes as $string => $notType) {\n            $this->expectException(InvariantException::class);\n            $this->expectExceptionMessage(\\sprintf('Expected %s to be a GraphQL type.', $string));\n\n            /** @noinspection PhpUnhandledExceptionInspection */\n            newList($notType);\n            $this->addToAssertionCount(1);\n        }\n    }\n\n    // Type System: NonNull must only accept non-nullable types\n\n    // accepts an type as nullable type of non-null\n\n    public function testAcceptsTypesAsNullableTypeOfNonNull()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $types = [\n            stringType(),\n            $this->scalarType,\n            $this->objectType,\n            $this->unionType,\n            $this->interfaceType,\n            $this->enumType,\n            $this->inputObjectType,\n            newList(stringType()),\n            newList(newNonNull(stringType())),\n        ];\n\n        foreach ($types as $type) {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            newNonNull($type);\n            $this->addToAssertionCount(1);\n        }\n    }\n\n    // rejects a non-type as nullable type of non-null\n\n    public function testRejectsNonTypesAsNullableTypeOfNonNull()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $nonTypes = [\n            'String!'        => newNonNull(stringType()),\n            'Object'         => new \\stdClass(),\n            'Array'          => [],\n            'Function'       => function () {\n                return null;\n            },\n            '(empty string)' => '',\n            'null'           => null,\n            'true'           => true,\n            'false'          => false,\n            'String'         => 'String',\n        ];\n\n        foreach ($nonTypes as $string => $nonType) {\n            $this->expectException(InvariantException::class);\n            $this->expectExceptionMessage(\\sprintf('Expected %s to be a GraphQL nullable type.', $string));\n\n            /** @noinspection PhpUnhandledExceptionInspection */\n            newNonNull($nonType);\n            $this->addToAssertionCount(1);\n        }\n    }\n\n    // Type System: A Schema must contain uniquely named types\n\n    // rejects a Schema which redefines a built-in type\n\n    public function testRejectsASchemaWhichDefinesABuiltInType()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $fakeString = newScalarType([\n            'name'      => 'String',\n            'serialize' => function () {\n                return null;\n            },\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $queryType = newObjectType([\n            'name'   => 'Query',\n            'fields' => [\n                'normal' => ['type' => stringType()],\n                'fake'   => ['type' => $fakeString],\n            ]\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'Schema must contain unique named types but contains multiple types named \"String\".'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        newSchema(['query' => $queryType]);\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Schema which defines an object type twice\n\n    public function testRejectsASchemaWhichDefinesAnObjectTypeTwice()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $a = newObjectType([\n            'name'   => 'SameName',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $b = newObjectType([\n            'name'   => 'SameName',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $queryType = newObjectType([\n            'name'   => 'Query',\n            'fields' => [\n                'a' => ['type' => $a],\n                'b' => ['type' => $b],\n            ]\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'Schema must contain unique named types but contains multiple types named \"SameName\".'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        newSchema(['query' => $queryType]);\n\n        $this->addToAssertionCount(1);\n    }\n\n    // rejects a Schema which have same named objects implementing an interface\n\n    public function testRejectsASchemaWhichHaveSameNamedObjectsImplementingAnInterface()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $anotherInterface = newInterfaceType([\n            'name'   => 'AnotherInterface',\n            'fields' => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $firstBadObject = newObjectType([\n            'name'       => 'BadObject',\n            'interfaces' => [$anotherInterface],\n            'fields'     => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $secondBadObject = newObjectType([\n            'name'       => 'BadObject',\n            'interfaces' => [$anotherInterface],\n            'fields'     => ['f' => ['type' => stringType()]],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $queryType = newObjectType([\n            'name'   => 'Query',\n            'fields' => [\n                'iface' => ['type' => $anotherInterface],\n            ]\n        ]);\n\n        $this->expectException(InvariantException::class);\n        $this->expectExceptionMessage(\n            'Schema must contain unique named types but contains multiple types named \"BadObject\".'\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        newSchema([\n            'query' => $queryType,\n            'types' => [$firstBadObject, $secondBadObject],\n        ]);\n\n        $this->addToAssertionCount(1);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Type/EnumTypeTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Type;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Schema\\Schema;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass EnumTypeTest extends TestCase\n{\n\n    /**\n     * @var EnumType\n     */\n    protected $colorType;\n\n    /**\n     * @var EnumType\n     */\n    protected $complex1;\n\n    /**\n     * @var EnumType\n     */\n    protected $complex2;\n\n    /**\n     * @var EnumType\n     */\n    protected $complexEnum;\n\n    /**\n     * @var ObjectType\n     */\n    protected $queryType;\n\n    /**\n     * @var ObjectType\n     */\n    protected $mutationType;\n\n    /**\n     * @var ObjectType\n     */\n    protected $subscriptionType;\n\n    /**\n     * @var Schema\n     */\n    protected $schema;\n\n    public function setUp()\n    {\n        $this->colorType = newEnumType([\n            'name'   => 'Color',\n            'values' => [\n                'RED'   => ['value' => 0],\n                'GREEN' => ['value' => 1],\n                'BLUE'  => ['value' => 2],\n            ]\n        ]);\n\n        $this->complex1 = [\n            'someRandomFunction' => function () {\n            },\n        ];\n\n        $this->complex2 = [\n            'someRandomValue' => 123,\n        ];\n\n        $this->complexEnum = newEnumType([\n            'name'   => 'Complex',\n            'values' => [\n                'ONE' => ['value' => $this->complex1],\n                'TWO' => ['value' => $this->complex2],\n            ],\n        ]);\n\n        $this->queryType = newObjectType([\n            'name'   => 'Query',\n            'fields' => [\n                'colorEnum'   => [\n                    'type'    => $this->colorType,\n                    'args'    => [\n                        'fromEnum'   => ['type' => $this->colorType],\n                        'fromInt'    => ['type' => intType()],\n                        'fromString' => ['type' => stringType()],\n                    ],\n                    'resolve' => function ($value, $args) {\n                        return $args['fromInt'] ?? $args['fromString'] ?? $args['fromEnum'];\n                    },\n                ],\n                'colorInt'    => [\n                    'type'    => intType(),\n                    'args'    => [\n                        'fromEnum' => ['type' => $this->colorType],\n                        'fromInt'  => ['type' => intType()],\n                    ],\n                    'resolve' => function ($value, $args) {\n                        return $args['fromInt'] ?? $args['fromEnum'];\n                    },\n                ],\n                'complexEnum' => [\n                    'type'    => $this->complexEnum,\n                    'args'    => [\n                        'fromEnum'          => [\n                            'type'         => $this->complexEnum,\n                            'defaultValue' => $this->complex1,\n                        ],\n                        'providedGoodValue' => ['type' => booleanType()],\n                        'providedBadValue'  => ['type' => booleanType()],\n                    ],\n                    'resolve' => function ($value, $args) {\n                        if ($args['providedGoodValue']) {\n                            return $this->complex2;\n                        }\n                        if ($args['providedBadValue']) {\n                            return ['someRandomValue' => 123];\n                        }\n                        return $args['fromEnum'];\n                    }\n                ],\n            ],\n        ]);\n\n        $this->mutationType = newObjectType([\n            'name'   => 'Mutation',\n            'fields' => [\n                'favoriteEnum' => [\n                    'type'    => $this->colorType,\n                    'args'    => ['color' => ['type' => $this->colorType]],\n                    'resolve' => function ($value, $args) {\n                        return $args['color'];\n                    },\n                ],\n            ],\n        ]);\n\n        $this->subscriptionType = newObjectType([\n            'name'   => 'Subscription',\n            'fields' => [\n                'subscribeToEnum' => [\n                    'type'    => $this->colorType,\n                    'args'    => ['color' => ['type' => $this->colorType]],\n                    'resolve' => function ($value, $args) {\n                        return $args['color'];\n                    },\n                ],\n            ],\n        ]);\n\n        $this->schema = newSchema([\n            'query'        => $this->queryType,\n            'mutation'     => $this->mutationType,\n            'subscription' => $this->subscriptionType,\n        ]);\n    }\n\n    // TODO: Add missing tests when possible.\n\n    public function testPresentsAGetValuesAPIForComplexEnums()\n    {\n        $values = $this->complexEnum->getValues();\n\n        $this->assertEquals(2, count($values));\n        $this->assertEquals('ONE', $values[0]->getName());\n        $this->assertEquals($this->complex1, $values[0]->getValue());\n        $this->assertEquals('TWO', $values[1]->getName());\n        $this->assertEquals($this->complex2, $values[1]->getValue());\n    }\n\n    public function testPresentsAGetValueAPIForComplexEnums()\n    {\n        $oneValue = $this->complexEnum->getValue('ONE');\n\n        $this->assertEquals('ONE', $oneValue->getName());\n        $this->assertEquals($this->complex1, $oneValue->getValue());\n    }\n\n    // TODO: Add test for 'may be internally represented with complex values'.\n\n    // TODO: Add test for 'can be introspected without error'.\n}\n"
  },
  {
    "path": "tests/Functional/Type/IntrospectionTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Type;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\graphql;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Test\\readFileContents;\n\nclass IntrospectionTest extends TestCase\n{\n    protected $introspectionQuery;\n\n    public function setUp()\n    {\n        $this->introspectionQuery = readFileContents(__DIR__ . '/introspection.graphql');\n    }\n\n    public function testExecutesAnIntrospectionQuery()\n    {\n        $emptySchema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'QueryRoot',\n                'fields' => [\n                    'onlyField' => ['type' => stringType()],\n                ],\n            ]),\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        graphql($emptySchema, $this->introspectionQuery);\n\n        $this->addToAssertionCount(1);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Type/PredicateTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Type;\n\nuse Digia\\GraphQL\\Error\\InvariantException;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse function Digia\\GraphQL\\Type\\assertType;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Util\\toString;\n\nclass PredicateTest extends TestCase\n{\n\n    /**\n     * @var ObjectType\n     */\n    protected $objectType;\n\n    /**\n     * @var InterfaceType\n     */\n    protected $interfaceType;\n\n    /**\n     * @var UnionType\n     */\n    protected $unionType;\n\n    /**\n     * @var EnumType\n     */\n    protected $enumType;\n\n    /**\n     * @var InputObjectType\n     */\n    protected $inputObjectType;\n\n    /**\n     * @var ScalarType\n     */\n    protected $scalarType;\n\n    /**\n     * @inheritdoc\n     * \n     * @throws InvariantException\n     */\n    public function setUp()\n    {\n        $this->objectType      = newObjectType(['name' => 'Object']);\n        $this->interfaceType   = newInterfaceType(['name' => 'Interface']);\n        $this->unionType       = newUnionType(['name' => 'Union', 'types' => [$this->objectType]]);\n        $this->enumType        = newEnumType(['name' => 'Enum', 'values' => ['foo' => []]]);\n        $this->inputObjectType = newInputObjectType(['name' => 'InputObject']);\n        $this->scalarType      = newScalarType([\n            'name'         => 'Scalar',\n            'serialize'    => function () {\n            },\n            'parseValue'   => function () {\n            },\n            'parseLiteral' => function () {\n            },\n        ]);\n    }\n\n    /**\n     * @throws InvariantException\n     */\n    public function testAssertType()\n    {\n        assertType(stringType());\n        assertType($this->objectType);\n\n        $this->addToAssertionCount(2);\n    }\n\n    /**\n     * @throws InvariantException\n     */\n    public function testAssertScalarTypeWithValidTypes()\n    {\n        assertScalarType(stringType());\n        assertScalarType($this->scalarType);\n\n        $this->addToAssertionCount(2);\n    }\n\n    /**\n     * @expectedException \\Exception\n     */\n    public function testAssertScalarTypeWithInvalidTypes()\n    {\n        assertScalarType(newList($this->scalarType));\n        assertScalarType($this->enumType);\n    }\n}\n\n/**\n * @param mixed $type\n * @throws InvariantException\n */\nfunction assertScalarType($type)\n{\n    if (!($type instanceof ScalarType)) {\n        throw new InvariantException(\\sprintf('Expected %s to be a GraphQL Scalar type.', toString($type)));\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Type/SerializationTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Type;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\floatType;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass SerializationTest extends TestCase\n{\n\n    /**\n     * @param mixed $value\n     * @param mixed $answer\n     * @dataProvider valuesIntCanRepresentDataProvider\n     */\n    public function testValuesIntCanRepresent($value, $answer)\n    {\n        $this->assertEquals($answer, intType()->serialize($value));\n    }\n\n    /**\n     * @return array\n     */\n    public function valuesIntCanRepresentDataProvider()\n    {\n        return [\n            [1, 1],\n            [123, 123],\n            [0, 0],\n            [-1, -1],\n            [100000, 1e5],\n        ];\n    }\n\n    /**\n     * @param mixed $value\n     * @dataProvider valuesIntCannotRepresentDataProvider\n     * @expectedException \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testValuesIntCannotRepresent($value)\n    {\n        intType()->serialize($value);\n        $this->addToAssertionCount(1);\n    }\n\n    /**\n     * @return array\n     */\n    public function valuesIntCannotRepresentDataProvider()\n    {\n        return [\n            [0.1],\n            [1.1],\n            [-1.1],\n            ['-1.1'],\n            [1e100],\n            [-1e100],\n            ['one'],\n        ];\n    }\n\n    public function testSerializeBooleanToInt()\n    {\n        $this->assertEquals(0, intType()->serialize(false));\n        $this->assertEquals(1, intType()->serialize(true));\n    }\n\n    /**\n     * @expectedException \\@expectedException \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testSerializeEmptyStringToInt()\n    {\n        intType()->serialize('');\n        $this->addToAssertionCount(1);\n    }\n\n    /**\n     * @param mixed $value\n     * @param mixed $answer\n     * @dataProvider valuesFloatCanRepresentDataProvider\n     */\n    public function testValuesFloatCanRepresent($value, $answer)\n    {\n        $this->assertEquals($answer, floatType()->serialize($value));\n    }\n\n    /**\n     * @return array\n     */\n    public function valuesFloatCanRepresentDataProvider()\n    {\n        return [\n            [1, 1.0],\n            [0, 0.0],\n            ['123.5', 123.5],\n            [-1, -1.0],\n            [0.1, 0.1],\n            [1.1, 1.1],\n            [-1.1, -1.1],\n            ['-1.1', -1.1],\n            [false, 0.0],\n            [true, 1.0],\n        ];\n    }\n\n    /**\n     * @param mixed $value\n     * @dataProvider valuesFloatCannotRepresentDataProvider\n     * @expectedException \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testValuesFloatCannotRepresent($value)\n    {\n        floatType()->serialize($value);\n        $this->addToAssertionCount(1);\n    }\n\n    /**\n     * @return array\n     */\n    public function valuesFloatCannotRepresentDataProvider()\n    {\n        return [['one'], ['']];\n    }\n\n    /**\n     * @param mixed $value\n     * @param mixed $answer\n     * @dataProvider valuesStringCanRepresentDataProvider\n     */\n    public function testValuesStringCanRepresent($value, $answer)\n    {\n        $this->assertEquals($answer, stringType()->serialize($value));\n    }\n\n    /**\n     * @return array\n     */\n    public function valuesStringCanRepresentDataProvider()\n    {\n        return [\n            ['string', 'string'],\n            [1, '1'],\n            [-1.1, '-1.1'],\n            [true, 'true'],\n            [false, 'false'],\n        ];\n    }\n\n    /**\n     * @dataProvider valuesBooleanCanRepresentDataProvider\n     */\n    public function testValuesBooleanCanRepresent($value, $answer)\n    {\n        $this->assertEquals($answer, booleanType()->serialize($value));\n    }\n\n    /**\n     * @return array\n     */\n    public function valuesBooleanCanRepresentDataProvider()\n    {\n        return [\n            ['string', true],\n            ['', false],\n            [1, true],\n            [0, false],\n            [true, true],\n            [false, false],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Type/introspection.graphql",
    "content": "query IntrospectionQuery {\n    __schema {\n        queryType { name }\n        mutationType { name }\n        subscriptionType { name }\n        types {\n            ...FullType\n        }\n        directives {\n            name\n            description\n            locations\n            args {\n                ...InputValue\n            }\n        }\n    }\n}\n\nfragment FullType on __Type {\n    kind\n    name\n    description\n    fields(includeDeprecated: true) {\n        name\n        description\n        args {\n            ...InputValue\n        }\n        type {\n            ...TypeRef\n        }\n        isDeprecated\n        deprecationReason\n    }\n    inputFields {\n        ...InputValue\n    }\n    interfaces {\n        ...TypeRef\n    }\n    enumValues(includeDeprecated: true) {\n        name\n        description\n        isDeprecated\n        deprecationReason\n    }\n    possibleTypes {\n        ...TypeRef\n    }\n}\n\nfragment InputValue on __InputValue {\n    name\n    description\n    type { ...TypeRef }\n    defaultValue\n}\n\nfragment TypeRef on __Type {\n    kind\n    name\n    ofType {\n        kind\n        name\n        ofType {\n            kind\n            name\n            ofType {\n                kind\n                name\n                ofType {\n                    kind\n                    name\n                    ofType {\n                        kind\n                        name\n                        ofType {\n                            kind\n                            name\n                            ofType {\n                                kind\n                                name\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/MessagesTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Validation\\fieldsConflictMessage;\nuse function Digia\\GraphQL\\Validation\\undefinedFieldMessage;\n\nclass MessagesTest extends TestCase\n{\n    public function testUndefinedFieldMessageWorksWithoutSuggestions()\n    {\n        $this->assertEquals(undefinedFieldMessage('f', 'T', [], []), 'Cannot query field \"f\" on type \"T\".');\n    }\n\n    public function testUndefinedFieldMessageWorksWithNoSmallNumbersOfTypeSuggestions()\n    {\n        $this->assertEquals(\n            undefinedFieldMessage('f', 'T', ['A', 'B'], []),\n            'Cannot query field \"f\" on type \"T\". Did you mean to use an inline fragment on \"A\" or \"B\"?'\n        );\n    }\n\n    public function testUndefinedFieldMessageWorksWithNoSmallNumbersOfFieldSuggestions()\n    {\n        $this->assertEquals(\n            undefinedFieldMessage('f', 'T', [], ['z', 'y']),\n            'Cannot query field \"f\" on type \"T\". Did you mean \"z\" or \"y\"?'\n        );\n    }\n\n    public function testUndefinedFieldMessageOnlyShowsOneSetOfSuggestionsAtATimePreferringTypes()\n    {\n        $this->assertEquals(\n            undefinedFieldMessage('f', 'T', ['A', 'B'], ['z', 'y']),\n            'Cannot query field \"f\" on type \"T\". Did you mean to use an inline fragment on \"A\" or \"B\"?'\n        );\n    }\n\n    public function testUndefinedFieldMessageLimitsLotsOfTypeSuggestions()\n    {\n        $this->assertEquals(\n            undefinedFieldMessage('f', 'T', ['A', 'B', 'C', 'D', 'E', 'F'], []),\n            'Cannot query field \"f\" on type \"T\". Did you mean to use an inline fragment on \"A\", \"B\", \"C\", \"D\" or \"E\"?'\n        );\n    }\n\n    public function testUndefinedFieldMessageLimitsLotsOfFieldSuggestions()\n    {\n        $this->assertEquals(\n            undefinedFieldMessage('f', 'T', [], ['z', 'y', 'x', 'w', 'v', 'u']),\n            'Cannot query field \"f\" on type \"T\". Did you mean \"z\", \"y\", \"x\", \"w\" or \"v\"?'\n        );\n    }\n\n    public function testFieldConflictMessageContainsHintForAliasConflict()\n    {\n        $this->assertEquals(\n            fieldsConflictMessage('x', 'a and b are different fields'),\n            'Fields \"x\" conflict because a and b are different fields. Use different aliases on the fields to fetch both if this was intentional.'\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/ExecutableDefinitionsRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\ExecutableDefinitionsRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\nonExecutableDefinition;\n\nclass ExecutableDefinitionsRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return ExecutableDefinitionsRule::class;\n    }\n\n    public function testWithOnlyOperation()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              dog {\n                name\n              }\n            }\n            ')\n        );\n    }\n\n    public function testWithOperationAndFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              dog {\n                name\n                ...Frag\n              }\n            }\n            \n            fragment Frag on Dog {\n              name\n            }\n            ')\n        );\n    }\n\n    public function testWithTypeDefinition()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              dog {\n                name\n              }\n            }\n            \n            type Cow {\n              name: String\n            }\n            \n            extend type Dog {\n              color: String\n            }\n            '),\n            [\n                nonExecutableDefinition('Cow', [7, 1]),\n                nonExecutableDefinition('Dog', [11, 1]),\n            ]\n        );\n    }\n\n    public function testWithSchemaDefinition()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            schema {\n              query: Query\n            }\n            \n            type Query {\n              test: String\n            }\n            \n            extend schema @directive\n            '),\n            [\n                nonExecutableDefinition('schema', [1, 1]),\n                nonExecutableDefinition('Query', [5, 1]),\n                nonExecutableDefinition('schema', [9, 1]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/FieldOnCorrectTypeRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\FieldOnCorrectTypeRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\undefinedField;\n\nclass FieldOnCorrectTypeRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return FieldOnCorrectTypeRule::class;\n    }\n\n    public function testObjectFieldSelection()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectFieldSelection on Dog {\n              __typename\n              name\n            }\n            ')\n        );\n    }\n\n    public function testAliasedObjectFieldSelection()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectFieldSelection on Dog {\n              otherName : name\n            }\n            ')\n        );\n    }\n\n\n    public function testInterfaceFieldSelection()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment interfaceFieldSelection on Pet {\n              __typename\n              name\n            }\n            ')\n        );\n    }\n\n    public function testAliasedInterfaceFieldSelection()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment interfaceFieldSelection on Pet {\n              otherName : name\n            }\n            ')\n        );\n    }\n\n    public function testLyingAliasSelection()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment lyingAliasSelection on Dog {\n              name : nickname\n            }\n            ')\n        );\n    }\n\n    public function testIgnoresFieldOnUnknownType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment unknownSelection on UnknownType {\n              unknownField\n            }\n            ')\n        );\n    }\n\n    public function testReportsErrorWhenTypeIsKnownAgain()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment typeKnownAgain on Pet {\n              unknown_pet_field {\n                ... on Cat {\n                  unknown_cat_field\n                }\n              }\n            }\n            '),\n            [\n                undefinedField('unknown_pet_field', 'Pet', [], [], [2, 3]),\n                undefinedField('unknown_cat_field', 'Cat', [], [], [4, 7]),\n            ]\n        );\n    }\n\n    public function testFieldNotDefinedOnFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fieldNotDefined on Dog {\n              meowVolume\n            }\n            '),\n            [undefinedField('meowVolume', 'Dog', [], ['barkVolume'], [2, 3])]\n        );\n    }\n\n    public function testIgnoresDeeplyUnknownField()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment deepFieldNotDefined on Dog {\n              unknown_field {\n                deeper_unknown_field\n              }\n            }\n            '),\n            [undefinedField('unknown_field', 'Dog', [], [], [2, 3])]\n        );\n    }\n\n    public function testSubFieldNotDefined()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment subFieldNotDefined on Human {\n              pets {\n                unknown_field\n              }\n            }\n            '),\n            [undefinedField('unknown_field', 'Pet', [], [], [3, 5])]\n        );\n    }\n\n    public function testFieldNotDefinedOnInlineFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fieldNotDefined on Pet {\n              ... on Dog {\n                meowVolume\n              }\n            }\n            '),\n            [undefinedField('meowVolume', 'Dog', [], ['barkVolume'], [3, 5])]\n        );\n    }\n\n    public function testAliasedFieldTargetNotDefined()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment aliasedFieldTargetNotDefined on Dog {\n              volume: mooVolume\n            }\n            '),\n            [undefinedField('mooVolume', 'Dog', [], ['barkVolume'], [2, 3])]\n        );\n    }\n\n    public function testAliasedLyingFieldTargetNotDefined()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment aliasedLyingFieldTargetNotDefined on Dog {\n              barkVolume: kawVolume\n            }\n            '),\n            [undefinedField('kawVolume', 'Dog', [], ['barkVolume'], [2, 3])]\n        );\n    }\n\n    public function testNotDefinedOnInterface()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment notDefinedOnInterface on Pet {\n              tailLength\n            }\n            '),\n            [undefinedField('tailLength', 'Pet', [], [], [2, 3])]\n        );\n    }\n\n    public function testDefinedOnImplementorsButNotOnInterface()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment definedOnImplementorsButNotInterface on Pet {\n              nickname\n            }\n            '),\n            [undefinedField('nickname', 'Pet', ['Dog', 'Cat'], ['name'], [2, 3])]\n        );\n    }\n\n    public function testMetaFieldSelectionOnUnion()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment directFieldSelectionOnUnion on CatOrDog {\n              __typename\n            }\n            ')\n        );\n    }\n\n    public function testDirectFieldSelectionOnUnion()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment directFieldSelectionOnUnion on CatOrDog {\n              directField\n            }\n            '),\n            [undefinedField('directField', 'CatOrDog', [], [], [2, 3])]\n        );\n    }\n\n    public function testDefinedOnImplementorsQueriedOnUnion()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment definedOnImplementorsQueriedOnUnion on CatOrDog {\n              name\n            }\n            '),\n            [\n                undefinedField(\n                    'name',\n                    'CatOrDog',\n                    ['Being', 'Pet', 'Canine', 'Dog', 'Cat'],\n                    [],\n                    [2, 3]\n                )\n            ]\n        );\n    }\n\n    public function testValidFieldInInlineFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectFieldSelection on Pet {\n              ... on Dog {\n                name\n              }\n              ... {\n                name\n              }\n            }\n            ')\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/FragmentsOnCompositeTypesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\FragmentsOnCompositeTypesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\fragmentOnNonComposite;\n\nclass FragmentsOnCompositeTypesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return FragmentsOnCompositeTypesRule::class;\n    }\n\n    public function testObjectIsValidFragmentType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment validFragment on Dog {\n              barks\n            }\n            ')\n        );\n    }\n\n    public function testInterfaceIsValidFragmentType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment validFragment on Pet {\n              name\n            }\n            ')\n        );\n    }\n\n    public function testObjectIsValidInlineFragmentType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment validFragment on Pet {\n              ... on Dog {\n                barks\n              }\n            }\n            ')\n        );\n    }\n\n    public function testInlineFragmentWithoutTypeIsValid()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment validFragment on Pet {\n              ... {\n                name\n              }\n            }\n            ')\n        );\n    }\n\n    public function testUnionIsValidFragmentType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment validFragment on CatOrDog {\n              __typename\n            }\n            ')\n        );\n    }\n\n    public function testScalarIsInvalidFragmentType()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment scalarFragment on Boolean {\n              bad\n            }\n            '),\n            [fragmentOnNonComposite('scalarFragment', 'Boolean', [1, 28])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/KnownArgumentNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\KnownArgumentNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unknownArgument;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unknownDirectiveArgument;\n\nclass KnownArgumentNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return KnownArgumentNamesRule::class;\n    }\n\n    public function testSingleArgumentIsKnown()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment argOnRequiredArg on Dog {\n              doesKnownCommand(dogCommand: SIT)\n            }\n            ')\n        );\n    }\n\n    public function testMultipleArgumentsAreKnown()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment multipleArgs on ComplicatedArgs {\n              multipleReqs(req1: 1, req2: 2)\n            }\n            ')\n        );\n    }\n\n    public function testIgnoresArgumentsOfUnknownFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment argOnUnknownField on Dog {\n              unknownField(unknownArg: SIT)\n            }\n            ')\n        );\n    }\n\n    public function testMultipleArgumentsInReverseOrderAreKnown()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment multipleArgsReverseOrder on ComplicatedArgs {\n              multipleReqs(req2: 2, req1: 1)\n            }\n            ')\n        );\n    }\n\n    public function testNoArgumentsOnOptionalArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment noArgOnOptionalArg on Dog {\n              isHouseTrained\n            }\n            ')\n        );\n    }\n\n    public function testArgumentsAreKnownDeeply()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              dog {\n                doesKnowCommand(dogCommand: SIT)\n              }\n              human {\n                pet {\n                  ... on Dog {\n                    doesKnowCommand(dogCommand: SIT)\n                  }\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testDirectiveArgumentsAreKnown()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              dog @skip(if: true)\n            }\n            ')\n        );\n    }\n\n    public function testUndirectArgumentsAreInvalid()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              dog @skip(unless: true)\n            }\n            '),\n            [unknownDirectiveArgument('unless', 'skip', [], [2, 13])]\n        );\n    }\n\n    public function testMisspelledDirectiveArgumentsAreReported()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              dog @skip(iff: true)\n            }\n            '),\n            [unknownDirectiveArgument('iff', 'skip', ['if'], [2, 13])]\n        );\n    }\n\n    public function testInvalidArgumentName()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidArgName on Dog {\n              doesKnowCommand(unknown: true)\n            }\n            '),\n            [unknownArgument('unknown', 'doesKnowCommand', 'Dog', [], [2, 19])]\n        );\n    }\n\n    public function testMisspelledArgumentNameIsReported()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidArgName on Dog {\n              doesKnowCommand(dogcommand: true)\n            }\n            '),\n            [unknownArgument('dogcommand', 'doesKnowCommand', 'Dog', ['dogCommand'], [2, 19])]\n        );\n    }\n\n    public function testUnknownArgumentsAmongstKnownArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment oneGoodArgOneInvalidArg on Dog {\n              doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true)\n            }\n            '),\n            [\n                unknownArgument('whoknows', 'doesKnowCommand', 'Dog', [], [2, 19]),\n                unknownArgument('unknown', 'doesKnowCommand', 'Dog', [], [2, 49]),\n            ]\n        );\n    }\n\n    public function testUnknownArgumentsDeeply()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              dog {\n                doesKnowCommand(unknown: true)\n              }\n              human {\n                pet {\n                  ... on Dog {\n                    doesKnowCommand(unknown: true)\n                  }\n                }\n              }\n            }\n            '),\n            [\n                unknownArgument('unknown', 'doesKnowCommand', 'Dog', [], [3, 21]),\n                unknownArgument('unknown', 'doesKnowCommand', 'Dog', [], [8, 25]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/KnownDirectivesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\KnownDirectivesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\misplacedDirective;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unknownDirective;\n\nclass KnownDirectivesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return KnownDirectivesRule::class;\n    }\n\n    public function testWithNoDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              name\n              ...Frag\n            }\n            fragment Frag on Dog {\n              name\n            }\n            ')\n        );\n    }\n\n    public function testWithKnownDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              dog @include(if: true) {\n                name\n              }\n              human @skip(if: false) {\n                name\n              }\n            }\n            ')\n        );\n    }\n\n    public function testWithUnknownDirective()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              dog @unknown(directive: \"value\") {\n                name\n              }\n            }\n            '),\n            [unknownDirective('unknown', [2, 7])]\n        );\n    }\n\n    public function testWithManyUnknownDirectives()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              dog @unknown(directive: \"value\") {\n                name\n              }\n              human @unknown(directive: \"value\") {\n                name\n                pets @unknown(directive: \"value\") {\n                  name\n                }\n              }\n            }\n            '),\n            [\n                unknownDirective('unknown', [2, 7]),\n                unknownDirective('unknown', [5, 9]),\n                unknownDirective('unknown', [7, 10]),\n            ]\n        );\n    }\n\n    public function testWithWellPlacedDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo @onQuery {\n              name @include(if: true)\n              ...Frag @include(if: true)\n              skippedField @skip(if: true)\n              ...SkippedFrag @skip(if: true)\n            }\n            mutation Bar @onMutation {\n              someField\n            }\n            ')\n        );\n    }\n\n    public function testWithMisplacedDirectives()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo @include(if: true) {\n              name @onQuery\n              ...Frag @onQuery\n            }\n            \n            mutation Bar @onQuery {\n              someField\n            }\n            '),\n            [\n                misplacedDirective('include', 'QUERY', [1, 11]),\n                misplacedDirective('onQuery', 'FIELD', [2, 8]),\n                misplacedDirective('onQuery', 'FRAGMENT_SPREAD', [3, 11]),\n                misplacedDirective('onQuery', 'MUTATION', [6, 14]),\n            ]\n        );\n    }\n\n    public function testWithinSchemaLanguageWithWellPlacedDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            type MyObj implements MyInterface @onObject {\n              myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition\n            }\n            \n            extend type MyObj @onObject\n            \n            scalar MyScalar @onScalar\n            \n            extend scalar MyScalar @onScalar\n            \n            interface MyInterface @onInterface {\n              myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition\n            }\n            \n            extend interface MyInterface @onInterface\n            \n            union MyUnion @onUnion = MyObj | Other\n            \n            extend union MyUnion @onUnion\n            \n            enum MyEnum @onEnum {\n              MY_VALUE @onEnumValue\n            }\n            \n            extend enum MyEnum @onEnum\n            \n            input MyInput @onInputObject {\n              myField: Int @onInputFieldDefinition\n            }\n            \n            extend input MyInput @onInputObject\n            \n            schema @onSchema {\n              query: MyQuery\n            }\n            \n            extend schema @onSchema\n            ')\n        );\n    }\n\n    public function testWithinSchemaLanguageWithMisplacedDirectives()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            type MyObj implements MyInterface @onInterface {\n              myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition\n            }\n            \n            scalar MyScalar @onEnum\n            \n            interface MyInterface @onObject {\n              myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition\n            }\n            \n            union MyUnion @onEnumValue = MyObj | Other\n            \n            enum MyEnum @onScalar {\n              MY_VALUE @onUnion\n            }\n            \n            input MyInput @onEnum {\n              myField: Int @onArgumentDefinition\n            }\n            \n            schema @onObject {\n              query: MyQuery\n            }\n            \n            extend schema @onObject\n            '),\n            [\n                misplacedDirective('onInterface', 'OBJECT', [1, 35]),\n                misplacedDirective(\n                    'onInputFieldDefinition',\n                    'ARGUMENT_DEFINITION',\n                    [2, 22]\n                ),\n                misplacedDirective(\n                    'onInputFieldDefinition',\n                    'FIELD_DEFINITION',\n                    [2, 55]\n                ),\n                misplacedDirective('onEnum', 'SCALAR', [5, 17]),\n                misplacedDirective('onObject', 'INTERFACE', [7, 23]),\n                misplacedDirective(\n                    'onInputFieldDefinition',\n                    'ARGUMENT_DEFINITION',\n                    [8, 22]\n                ),\n                misplacedDirective(\n                    'onInputFieldDefinition',\n                    'FIELD_DEFINITION',\n                    [8, 55]\n                ),\n                misplacedDirective('onEnumValue', 'UNION', [11, 15]),\n                misplacedDirective('onScalar', 'ENUM', [13, 13]),\n                misplacedDirective('onUnion', 'ENUM_VALUE', [14, 12]),\n                misplacedDirective('onEnum', 'INPUT_OBJECT', [17, 15]),\n                misplacedDirective(\n                    'onArgumentDefinition',\n                    'INPUT_FIELD_DEFINITION',\n                    [18, 16]\n                ),\n                misplacedDirective('onObject', 'SCHEMA', [21, 8]),\n                misplacedDirective('onObject', 'SCHEMA', [25, 15]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/KnownFragmentNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\KnownFragmentNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unknownFragment;\n\nclass KnownFragmentNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return KnownFragmentNamesRule::class;\n    }\n\n    public function testKnownFragmentNamesAreValid()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              human(id: 4) {\n                ...HumanFields1\n                ... on Human {\n                  ...HumanFields2\n                }\n                ... {\n                  name\n                }\n              }\n            }\n            fragment HumanFields1 on Human {\n              name\n              ...HumanFields3\n            }\n            fragment HumanFields2 on Human {\n              name\n            }\n            fragment HumanFields3 on Human {\n              name\n            }\n            ')\n        );\n    }\n\n    public function testUnknownFragmentNamesAreInvalid()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              human(id: 4) {\n                ...UnknownFragment1\n                ... on Human {\n                  ...UnknownFragment2\n                }\n              }\n            }\n            fragment HumanFields on Human {\n              name\n              ...UnknownFragment3\n            }\n            '),\n            [\n                unknownFragment('UnknownFragment1', [3, 8]),\n                unknownFragment('UnknownFragment2', [5, 10]),\n                unknownFragment('UnknownFragment3', [11, 6]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/KnownTypeNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\KnownTypeNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unknownType;\n\nclass KnownTypeNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return KnownTypeNamesRule::class;\n    }\n\n    public function testKnownTypeNamesAreValid()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($var: String, $required: [String!]!) {\n              user(id: 4) {\n                pets { ... on Pet { name }, ...PetFields, ... { name } }\n              }\n            }\n            fragment PetFields on Pet {\n              name\n            }\n            ')\n        );\n    }\n\n    public function testUnknownTypeNamesAreInvalid()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($var: JumbledUpLetters) {\n              user(id: 4) {\n                name\n                pets { ... on Badger { name }, ...PetFields }\n              }\n            }\n            fragment PetFields on Peettt {\n              name\n            }\n            '),\n            [\n                unknownType('JumbledUpLetters', [], [1, 17]),\n                unknownType('Badger', [], [4, 19]),\n                unknownType('Peettt', ['Pet'], [7, 23]),\n            ]\n        );\n    }\n\n    public function testIgnoresTypeDefinitions()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            type NotInTheSchema {\n              field: FooBar\n            }\n            interface FooBar {\n              field: NotInTheSchema\n            }\n            union U = A | B\n            input Blob {\n              field: UnknownType\n            }\n            query Foo($var: NotInTheSchema) {\n              user(id: $var) {\n                id\n              }\n            }\n            '),\n            [unknownType('NotInTheSchema', [], [11, 17])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/LoneAnonymousOperationRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\LoneAnonymousOperationRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\anonymousOperationNotAlone;\n\nclass LoneAnonymousOperationRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return LoneAnonymousOperationRule::class;\n    }\n\n    public function testNoOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Type {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testOneAnonymousOperation()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testMultipleNamedOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              field\n            }\n            \n            query Bar {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testAnonymousOperationWithFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              ...Foo\n            }\n            fragment Foo on Type {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testMultipleAnonymousOperations()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              fieldA\n            }\n            {\n              fieldB\n            }            \n            '),\n            [\n                anonymousOperationNotAlone([1, 1]),\n                anonymousOperationNotAlone([4, 1]),\n            ]\n        );\n    }\n\n    public function testAnonymousOperationWithAMutation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              fieldA\n            }\n            mutation Foo {\n              fieldB\n            }            \n            '),\n            [anonymousOperationNotAlone([1, 1])]\n        );\n    }\n\n    public function testAnonymousOperationWithASubscription()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              fieldA\n            }\n            subscription Foo {\n              fieldB\n            }            \n            '),\n            [anonymousOperationNotAlone([1, 1])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/NoFragmentCyclesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\NoFragmentCyclesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\fragmentCycle;\n\nclass NoFragmentCyclesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return NoFragmentCyclesRule::class;\n    }\n\n    public function testSingleReferenceIsValid()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB }\n            fragment fragB on Dog { name }\n            ')\n        );\n    }\n\n    public function testSpreadingTwiceIsNotCircular()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB, ...fragB }\n            fragment fragB on Dog { name }\n            ')\n        );\n    }\n\n    public function testSpreadingTwiceIndirectlyIsNotCircular()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB, ...fragC }\n            fragment fragB on Dog { ...fragC }\n            fragment fragC on Dog { name }\n            ')\n        );\n    }\n\n    public function testDoubleSpreadWithinAbstractTypes()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment nameFragment on Pet {\n              ... on Dog { name }\n              ... on Cat { name }\n            }\n            fragment spreadsInAnon on Pet {\n              ... on Dog { ...nameFragment }\n              ... on Cat { ...nameFragment }\n            }\n            ')\n        );\n    }\n\n    public function testDoesNotFalsePositiveOnUnknownFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment nameFragment on Pet {\n              ...UnknownFragment\n            }\n            ')\n        );\n    }\n\n    public function testSpreadingRecursivelyWithinFieldsFails()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Human { relatives { ...fragA } },\n            '),\n            [fragmentCycle('fragA', [], [[1, 39]])]\n        );\n    }\n\n    public function testNoSpreadingItselfDirectly()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragA }\n            '),\n            [fragmentCycle('fragA', [], [[1, 25]])]\n        );\n    }\n\n    public function testNoSpreadingItselfDirectlyWithinInlineFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Pet {\n              ... on Dog {\n                ...fragA\n              }\n            }\n            '),\n            [fragmentCycle('fragA', [], [[3, 5]])]\n        );\n    }\n\n    public function testNoSpreadingItselfIndirectly()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB }\n            fragment fragB on Dog { ...fragA }\n            '),\n            [fragmentCycle('fragA', ['fragB'], [[1, 25], [2, 25]])]\n        );\n    }\n\n    public function testNoSpreadingItselfIndirectlyInOppositeOrder()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragB on Dog { ...fragA }\n            fragment fragA on Dog { ...fragB }\n            '),\n            [fragmentCycle('fragB', ['fragA'], [[1, 25], [2, 25]])]\n        );\n    }\n\n    public function testNoSpreadingItselfIndirectlyWithinInlineFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Pet {\n              ... on Dog {\n                ...fragB\n              }\n            }\n            fragment fragB on Pet {\n              ... on Dog {\n                ...fragA\n              }\n            }\n            '),\n            [fragmentCycle('fragA', ['fragB'], [[3, 5], [8, 5]])]\n        );\n    }\n\n    public function testNoSpreadingItselfDeeply()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB }\n            fragment fragB on Dog { ...fragC }\n            fragment fragC on Dog { ...fragO }\n            fragment fragX on Dog { ...fragY }\n            fragment fragY on Dog { ...fragZ }\n            fragment fragZ on Dog { ...fragO }\n            fragment fragO on Dog { ...fragP }\n            fragment fragP on Dog { ...fragA, ...fragX }\n            '),\n            [\n                fragmentCycle(\n                    'fragA',\n                    ['fragB', 'fragC', 'fragO', 'fragP'],\n                    [[1, 25], [2, 25], [3, 25], [7, 25], [8, 25]]\n                ),\n                fragmentCycle(\n                    'fragO',\n                    ['fragP', 'fragX', 'fragY', 'fragZ'],\n                    [[7, 25], [8, 35], [4, 25], [5, 25], [6, 25]]\n                )\n            ]\n        );\n    }\n\n    public function testNoSpreadingItselfDeeplyTwoPaths()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB, ...fragC }\n            fragment fragB on Dog { ...fragA }\n            fragment fragC on Dog { ...fragA }\n            '),\n            [\n                fragmentCycle('fragA', ['fragB'], [[1, 25], [2, 25]]),\n                fragmentCycle('fragA', ['fragC'], [[1, 35], [3, 25]]),\n            ]\n        );\n    }\n\n    public function testNoSpreadingItselfDeeplyTwoPathsOppositeOrder()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragC }\n            fragment fragB on Dog { ...fragC }\n            fragment fragC on Dog { ...fragA, ...fragB }\n            '),\n            [\n                fragmentCycle('fragA', ['fragC'], [[1, 25], [3, 25]]),\n                fragmentCycle('fragC', ['fragB'], [[3, 35], [2, 25]]),\n            ]\n        );\n    }\n\n    public function testNoSpreadingItselfDeeplyAndImmediately()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Dog { ...fragB }\n            fragment fragB on Dog { ...fragB, ...fragC }\n            fragment fragC on Dog { ...fragA, ...fragB }\n            '),\n            [\n                fragmentCycle('fragB', [], [[2, 25]]),\n                fragmentCycle('fragA', ['fragB', 'fragC'], [[1, 25], [2, 35], [3, 25]]),\n                fragmentCycle('fragB', ['fragC'], [[2, 35], [3, 35]]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/NoUndefinedVariablesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\NoUndefinedVariablesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\undefinedVariable;\n\nclass NoUndefinedVariablesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return NoUndefinedVariablesRule::class;\n    }\n\n    public function testAllVariablesDefined()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              field(a: $a, b: $b, c: $c)\n            }\n            ')\n        );\n    }\n\n    public function testAllVariablesDeeplyDefined()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              field(a: $a) {\n                field(b: $b) {\n                  field(c: $c)\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testAllVariablesDeeplyInInlineFragmentsDefined()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              ... on Type {\n                field(a: $a) {\n                  field(b: $b) {\n                    ... on Type {\n                      field(c: $c)\n                    }\n                  }\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testAllVariablesInFragmentsDeeplyDefined()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragB\n              }\n            }\n            fragment FragB on Type {\n              field(b: $b) {\n                ...FragC\n              }\n            }\n            fragment FragC on Type {\n              field(c: $c)\n            }\n            ')\n        );\n    }\n\n    public function testVariablesWithinSingleFragmentDefinedInMultipleOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String) {\n              ...FragA\n            }\n            query Bar($a: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            ')\n        );\n    }\n\n    public function testVariableWithinFragmentsDefinedInOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String) {\n              ...FragA\n            }\n            query Bar($b: String) {\n              ...FragB\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            fragment FragB on Type {\n              field(b: $b)\n            }\n            ')\n        );\n    }\n\n    public function testVariableWithinRecursiveFragmentDefined()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragA\n              }\n            }\n            ')\n        );\n    }\n\n    public function testVariableNotDefined()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              field(a: $a, b: $b, c: $c, d: $d)\n            }\n            '),\n            [undefinedVariable('d', [2, 33], 'Foo', [1, 1])]\n        );\n    }\n\n    public function testVariableNotDefinedByAnonymousQuery()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field(a: $a)\n            }\n            '),\n            [undefinedVariable('a', [2, 12], '', [1, 1])]\n        );\n    }\n\n    public function testMultipleVariablesNotDefined()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              field(a: $a, b: $b, c: $c)\n            }\n            '),\n            [\n                undefinedVariable('a', [2, 12], 'Foo', [1, 1]),\n                undefinedVariable('c', [2, 26], 'Foo', [1, 1]),\n            ]\n        );\n    }\n\n    public function testVariableInFragmentNotDefinedByAnonymousQuery()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            '),\n            [undefinedVariable('a', [5, 12], '', [1, 1])]\n        );\n    }\n\n    public function testVariableInFragmentNotDefinedByOperation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragB\n              }\n            }\n            fragment FragB on Type {\n              field(b: $b) {\n                ...FragC\n              }\n            }\n            fragment FragC on Type {\n              field(c: $c)\n            }\n            '),\n            [undefinedVariable('c', [15, 12], 'Foo', [1, 1])]\n        );\n    }\n\n    public function testMultipleVariablesInFragmentsNotDefined()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragB\n              }\n            }\n            fragment FragB on Type {\n              field(b: $b) {\n                ...FragC\n              }\n            }\n            fragment FragC on Type {\n              field(c: $c)\n            }\n            '),\n            [\n                undefinedVariable('a', [5, 12], 'Foo', [1, 1]),\n                undefinedVariable('c', [15, 12], 'Foo', [1, 1]),\n            ]\n        );\n    }\n\n    public function testSingleVariableInFragmentNotDefinedByMultipleOperations()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String) {\n              ...FragAB\n            }\n            query Bar($a: String) {\n              ...FragAB\n            }\n            fragment FragAB on Type {\n              field(a: $a, b: $b)\n            }\n            '),\n            [\n                undefinedVariable('b', [8, 19], 'Foo', [1, 1]),\n                undefinedVariable('b', [8, 19], 'Bar', [4, 1]),\n            ]\n        );\n    }\n\n    public function testVariablesInFragmentNotDefinedByMultipleOperations()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              ...FragAB\n            }\n            query Bar($a: String) {\n              ...FragAB\n            }\n            fragment FragAB on Type {\n              field(a: $a, b: $b)\n            }\n            '),\n            [\n                undefinedVariable('a', [8, 12], 'Foo', [1, 1]),\n                undefinedVariable('b', [8, 19], 'Bar', [4, 1]),\n            ]\n        );\n    }\n\n    public function testVariableInFragmentUsedByOtherOperation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              ...FragA\n            }\n            query Bar($a: String) {\n              ...FragB\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            fragment FragB on Type {\n              field(b: $b)\n            }\n            '),\n            [\n                undefinedVariable('a', [8, 12], 'Foo', [1, 1]),\n                undefinedVariable('b', [11, 12], 'Bar', [4, 1]),\n            ]\n        );\n    }\n\n    public function testMultipleUndefinedVariablesProduceMultipleErrors()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              ...FragAB\n            }\n            query Bar($a: String) {\n              ...FragAB\n            }\n            fragment FragAB on Type {\n              field1(a: $a, b: $b)\n              ...FragC\n              field3(a: $a, b: $b)\n            }\n            fragment FragC on Type {\n              field2(c: $c)\n            }\n            '),\n            [\n                undefinedVariable('a', [8, 13], 'Foo', [1, 1]),\n                undefinedVariable('a', [10, 13], 'Foo', [1, 1]),\n                undefinedVariable('c', [13, 13], 'Foo', [1, 1]),\n                undefinedVariable('b', [8, 20], 'Bar', [4, 1]),\n                undefinedVariable('b', [10, 20], 'Bar', [4, 1]),\n                undefinedVariable('c', [13, 13], 'Bar', [4, 1]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/NoUnusedFragmentsRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\NoUnusedFragmentsRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unusedFragment;\n\nclass NoUnusedFragmentsRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return NoUnusedFragmentsRule::class;\n    }\n\n    public function testAllFragmentNamesAreUsed()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              human(id: 4) {\n                ...HumanFields1\n                ... on Human {\n                  ...HumanFields2\n                }\n              }\n            }\n            fragment HumanFields1 on Human {\n              name\n              ...HumanFields3\n            }\n            fragment HumanFields2 on Human {\n              name\n            }\n            fragment HumanFields3 on Human {\n              name\n            }\n            ')\n        );\n    }\n\n    public function testContainsUnknownFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              human(id: 4) {\n                ...HumanFields1\n              }\n            }\n            query Bar {\n              human(id: 4) {\n                ...HumanFields2\n              }\n            }\n            fragment HumanFields1 on Human {\n              name\n              ...HumanFields3\n            }\n            fragment HumanFields2 on Human {\n              name\n            }\n            fragment HumanFields3 on Human {\n              name\n            }\n            fragment Unused1 on Human {\n              name\n            }\n            fragment Unused2 on Human {\n              name\n            }\n            '),\n            [\n                unusedFragment('Unused1', [21, 1]),\n                unusedFragment('Unused2', [24, 1]),\n            ]\n        );\n    }\n\n    public function testContainsUnknownFragmentsWithReferenceCycle()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              human(id: 4) {\n                ...HumanFields1\n              }\n            }\n            query Bar {\n              human(id: 4) {\n                ...HumanFields2\n              }\n            }\n            fragment HumanFields1 on Human {\n              name\n              ...HumanFields3\n            }\n            fragment HumanFields2 on Human {\n              name\n            }\n            fragment HumanFields3 on Human {\n              name\n            }\n            fragment Unused1 on Human {\n              name\n              ...Unused2\n            }\n            fragment Unused2 on Human {\n              name\n              ...Unused1\n            }\n            '),\n            [\n                unusedFragment('Unused1', [21, 1]),\n                unusedFragment('Unused2', [25, 1]),\n            ]\n        );\n    }\n\n    public function testContainsUnknownAndUndefinedFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              human(id: 4) {\n                ...bar\n              }\n            }\n            fragment foo on Human {\n              name\n            }\n            '),\n            [unusedFragment('foo', [6, 1])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/NoUnusedVariablesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\NoUnusedVariablesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unusedVariable;\n\nclass NoUnusedVariablesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return NoUnusedVariablesRule::class;\n    }\n\n    public function testUsesAllVariables()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query ($a: String, $b: String, $c: String) {\n              field(a: $a, b: $b, c: $c)\n            }\n            ')\n        );\n    }\n\n    public function testUsesAllVariablesDeeply()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              field(a: $a) {\n                field(b: $b) {\n                  field(c: $c)\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testUsesAllVariablesDeeplyInInlineFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              ... on Type {\n                field(a: $a) {\n                  field(b: $b) {\n                    ... on Type {\n                      field(c: $c)\n                    }\n                  }\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testUsesAllVariablesInFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragB\n              }\n            }\n            fragment FragB on Type {\n              field(b: $b) {\n                ...FragC\n              }\n            }\n            fragment FragC on Type {\n              field(c: $c)\n            }\n            ')\n        );\n    }\n\n    public function testVariableUsedByFragmentInMultipleOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String) {\n              ...FragA\n            }\n            query Bar($b: String) {\n              ...FragB\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            fragment FragB on Type {\n              field(b: $b)\n            }\n            ')\n        );\n    }\n\n    public function testVariableUsedByRecursiveFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragA\n              }\n            }\n            ')\n        );\n    }\n\n    public function testVariableNotUsed()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query ($a: String, $b: String, $c: String) {\n              field(a: $a, b: $b)\n            }\n            '),\n            [unusedVariable('c', null, [1, 32])]\n        );\n    }\n\n    public function testMultipleVariablesNotUsed()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              field(b: $b)\n            }\n            '),\n            [\n                unusedVariable('a', 'Foo', [1, 11]),\n                unusedVariable('c', 'Foo', [1, 35]),\n            ]\n        );\n    }\n\n    public function testVariableNotUsedInFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a) {\n                ...FragB\n              }\n            }\n            fragment FragB on Type {\n              field(b: $b) {\n                ...FragC\n              }\n            }\n            fragment FragC on Type {\n              field\n            }\n            '),\n            [unusedVariable('c', 'Foo', [1, 35])]\n        );\n    }\n\n    public function testMultipleVariablesNotUsedInFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: String, $c: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field {\n                ...FragB\n              }\n            }\n            fragment FragB on Type {\n              field(b: $b) {\n                ...FragC\n              }\n            }\n            fragment FragC on Type {\n              field\n            }\n            '),\n            [\n                unusedVariable('a', 'Foo', [1, 11]),\n                unusedVariable('c', 'Foo', [1, 35]),\n            ]\n        );\n    }\n\n    public function testVariableNotUsedByUnreferencedFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              ...FragA\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            fragment FragB on Type {\n              field(b: $b)\n            }\n            '),\n            [unusedVariable('b', 'Foo', [1, 11])]\n        );\n    }\n\n    public function testVariableNotUsedByFragmentUsedByOtherOperation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($b: String) {\n              ...FragA\n            }\n            query Bar($a: String) {\n              ...FragB\n            }\n            fragment FragA on Type {\n              field(a: $a)\n            }\n            fragment FragB on Type {\n              field(b: $b)\n            }\n            '),\n            [\n                unusedVariable('b', 'Foo', [1, 11]),\n                unusedVariable('a', 'Bar', [4, 11]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/OverlappingFieldsCanBeMergedRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\OverlappingFieldsCanBeMergedRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\fieldConflict;\nuse function Digia\\GraphQL\\Type\\idType;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass OverlappingFieldsCanBeMergedRuleTest extends RuleTestCase\n{\n    protected $someBox;\n    protected $stringBox;\n    protected $intBox;\n    protected $nonNullStringBox1;\n    protected $nonNullStringBox1Impl;\n    protected $nonNullStringBox2;\n    protected $nonNullStringBox2Impl;\n    protected $connection;\n    protected $schema;\n\n    protected function getRuleClassName(): string\n    {\n        return OverlappingFieldsCanBeMergedRule::class;\n    }\n\n    public function setUp()\n    {\n        parent::setUp();\n\n        $this->someBox = newInterfaceType([\n            'name'   => 'SomeBox',\n            'fields' => function () {\n                return [\n                    'deepBox'        => ['type' => $this->someBox],\n                    'unrelatedField' => ['type' => stringType()],\n                ];\n            },\n        ]);\n\n        $this->stringBox = newObjectType([\n            'name'       => 'StringBox',\n            'interfaces' => [$this->someBox],\n            'fields'     => function () {\n                return [\n                    'scalar'         => ['type' => stringType()],\n                    'deepBox'        => ['type' => $this->stringBox],\n                    'unrelatedField' => ['type' => stringType()],\n                    'listStringBox'  => ['type' => newList($this->stringBox)],\n                    'stringBox'      => ['type' => $this->stringBox],\n                    'intBox'         => ['type' => $this->intBox],\n                ];\n            },\n        ]);\n\n        $this->intBox = newObjectType([\n            'name'       => 'IntBox',\n            'interfaces' => [$this->someBox],\n            'fields'     => function () {\n                return [\n                    'scalar'         => ['type' => intType()],\n                    'deepBox'        => ['type' => $this->intBox],\n                    'unrelatedField' => ['type' => stringType()],\n                    'listStringBox'  => ['type' => newList($this->stringBox)],\n                    'stringBox'      => ['type' => $this->stringBox],\n                    'intBox'         => ['type' => $this->intBox],\n                ];\n            },\n        ]);\n\n        $this->nonNullStringBox1 = newInterfaceType([\n            'name'   => 'NonNullStringBox1',\n            'fields' => [\n                'scalar' => ['type' => newNonNull(stringType())],\n            ],\n        ]);\n\n        $this->nonNullStringBox1Impl = newObjectType([\n            'name'       => 'NonNullStringBox1Impl',\n            'interfaces' => [$this->someBox, $this->nonNullStringBox1],\n            'fields'     => [\n                'scalar'         => ['type' => newNonNull(stringType())],\n                'unrelatedField' => ['type' => stringType()],\n                'deepBox'        => ['type' => $this->someBox],\n            ],\n        ]);\n\n        $this->nonNullStringBox2 = newInterfaceType([\n            'name'   => 'NonNullStringBox2',\n            'fields' => [\n                'scalar' => ['type' => newNonNull(stringType())],\n            ],\n        ]);\n\n        $this->nonNullStringBox2Impl = newObjectType([\n            'name'       => 'NonNullStringBox2Impl',\n            'interfaces' => [$this->someBox, $this->nonNullStringBox2],\n            'fields'     => [\n                'scalar'         => ['type' => newNonNull(stringType())],\n                'unrelatedField' => ['type' => stringType()],\n                'deepBox'        => ['type' => $this->someBox],\n            ],\n        ]);\n\n        $this->connection = newObjectType([\n            'name'   => 'Connection',\n            'fields' => function () {\n                return [\n                    'edges' => [\n                        'type' => newList(\n                            newObjectType([\n                                'name'   => 'Edge',\n                                'fields' => [\n                                    'node' => [\n                                        'type' => newObjectType([\n                                            'name'   => 'Node',\n                                            'fields' => [\n                                                'id'   => ['type' => idType()],\n                                                'name' => ['type' => stringType()],\n                                            ],\n                                        ])\n                                    ],\n                                ],\n                            ])\n                        ),\n                    ],\n                ];\n            },\n        ]);\n\n        $this->schema = newSchema([\n            'query' => newObjectType([\n                'name'   => 'QueryRoot',\n                'fields' => function () {\n                    return [\n                        'someBox'    => ['type' => $this->someBox],\n                        'connection' => ['type' => $this->connection],\n                    ];\n                },\n            ]),\n            'types' => [$this->intBox, $this->stringBox, $this->nonNullStringBox1Impl, $this->nonNullStringBox2Impl],\n        ]);\n    }\n\n    public function testUniqueFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment uniqueFields on Dog {\n              name\n              nickname\n            }\n            ')\n        );\n    }\n\n    public function testIdenticalFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment mergeIdenticalFields on Dog {\n              name\n              name\n            }\n            ')\n        );\n    }\n\n    public function testIdenticalFieldsWithIdenticalArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment mergeIdenticalFieldsWithIdenticalArgs on Dog {\n              doesKnowCommand(dogCommand: SIT)\n              doesKnowCommand(dogCommand: SIT)\n            }\n            ')\n        );\n    }\n\n    public function testIdenticalFieldsWithIdenticalDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment mergeSameFieldsWithSameDirectives on Dog {\n            name @include(if: true)\n            name @include(if: true)\n            }\n            ')\n        );\n    }\n\n    public function testDifferentArgumentsWithDifferentAliases()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment differentArgsWithDifferentAliases on Dog {\n              knowsSit: doesKnowCommand(dogCommand: SIT)\n              knowsDown: doesKnowCommand(dogCommand: DOWN)\n            }\n            ')\n        );\n    }\n\n    public function testDifferentDirectivesWithDifferentAliases()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment differentDirectivesWithDifferentAliases on Dog {\n              nameIfTrue: name @include(if: true)\n              nameIfFalse: name @include(if: false)\n            }\n            ')\n        );\n    }\n\n    public function testDifferentSkipIncludeDirectivesAccepted()\n    {\n        // Note: Differing skip/include directives don't create an ambiguous return\n        // value and are acceptable in conditions where differing runtime values\n        // may have the same desired effect of including or skipping a field.\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment differentDirectivesWithDifferentAliases on Dog {\n              name @include(if: true)\n              name @include(if: false)\n            }\n            ')\n        );\n    }\n\n    public function testSameAliasesWithDifferentFieldTargets()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment sameAliasesWithDifferentFieldTargets on Dog {\n              fido: name\n              fido: nickname\n            }\n            '),\n            [fieldConflict('fido', 'name and nickname are different fields', [[2, 3], [3, 3]])]\n        );\n    }\n\n    public function testSameAliasesAllowedOnNonOverlappingFields()\n    {\n        // This is valid since no object can be both a \"Dog\" and a \"Cat\", thus\n        // these fields can never overlap.\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment sameAliasesWithDifferentFieldTargets on Pet {\n              ... on Dog {\n                name\n              }\n              ... on Cat {\n                name: nickname\n              }\n            }\n            ')\n        );\n    }\n\n    public function testAliasMaskingDirectFieldAccess()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment aliasMaskingDirectFieldAccess on Dog {\n              name: nickname\n              name\n            }\n            '),\n            [fieldConflict('name', 'nickname and name are different fields', [[2, 3], [3, 3]])]\n        );\n    }\n\n    public function testDifferentArgumentsSecondAddsAnArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment conflictingArgs on Dog {\n              doesKnowCommand\n              doesKnowCommand(dogCommand: HEEL)\n            }\n            '),\n            [fieldConflict('doesKnowCommand', 'they have differing arguments', [[2, 3], [3, 3]])]\n        );\n    }\n\n    public function testDifferentArgsSecondMissingAnArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment conflictingArgs on Dog {\n              doesKnowCommand(dogCommand: SIT)\n              doesKnowCommand\n            }\n            '),\n            [fieldConflict('doesKnowCommand', 'they have differing arguments', [[2, 3], [3, 3]])]\n        );\n    }\n\n    public function testConflictingArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment conflictingArgs on Dog {\n              doesKnowCommand(dogCommand: SIT)\n              doesKnowCommand(dogCommand: HEEL)\n            }\n            '),\n            [fieldConflict('doesKnowCommand', 'they have differing arguments', [[2, 3], [3, 3]])]\n        );\n    }\n\n    public function testAllowsDifferentArgumentsWhereNoConflictIsPossible()\n    {\n        // This is valid since no object can be both a \"Dog\" and a \"Cat\", thus\n        // these fields can never overlap.\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment conflictingArgs on Pet {\n              ... on Dog {\n                name(surname: true)\n              }\n              ... on Cat {\n                name\n              }\n            }\n            ')\n        );\n    }\n\n    public function testEncountersConflictInFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              ...A\n              ...B\n            }\n            fragment A on Type {\n              x: a\n            }\n            fragment B on Type {\n              x: b\n            }\n            '),\n            [fieldConflict('x', 'a and b are different fields', [[6, 3], [9, 3]])]\n        );\n    }\n\n    public function testReportsEachConlictOnce()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              f1 {\n                ...A\n                ...B\n              }\n              f2 {\n                ...B\n                ...A\n              }\n              f3 {\n                ...A\n                ...B\n                x: c\n              }\n            }\n            fragment A on Type {\n              x: a\n            }\n            fragment B on Type {\n              x: b\n            }\n            '),\n            [\n                fieldConflict('x', 'a and b are different fields', [[17, 3], [20, 3]]),\n                fieldConflict('x', 'c and a are different fields', [[13, 5], [17, 3]]),\n                fieldConflict('x', 'c and b are different fields', [[13, 5], [20, 3]]),\n            ]\n        );\n    }\n\n    public function testDeepConflict()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field {\n                x: a\n              },\n              field {\n                x: b\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'field',\n                    [['x', 'a and b are different fields']],\n                    [[2, 3], [3, 5], [5, 3], [6, 5]]\n                )\n            ]\n        );\n    }\n\n    public function testDeepConflictWithMultipleIssues()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field {\n                x: a\n                y: c\n              },\n              field {\n                x: b\n                y: d\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'field',\n                    [\n                        ['x', 'a and b are different fields'],\n                        ['y', 'c and d are different fields'],\n                    ],\n                    [[2, 3], [3, 5], [4, 5], [6, 3], [7, 5], [8, 5]]\n                )\n            ]\n        );\n    }\n\n    public function testVeryDeepConflict()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field {\n                deepField {\n                  x: a\n                }\n              },\n              field {\n                deepField {\n                  x: b\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'field',\n                    ['deepField', [['x', 'a and b are different fields']]],\n                    [[2, 3], [3, 5], [4, 7], [7, 3], [8, 5], [9, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testReportsDeepConflictToNearestCommonAncestor()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field {\n                deepField {\n                  x: a\n                }\n                deepField {\n                  x: b\n                }\n              },\n              field {\n                deepField {\n                  y\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'deepField',\n                    ['x', 'a and b are different fields'],\n                    [[3, 5], [4, 7], [6, 5], [7, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testReportsDeepConflictToNearestCommonAncestorInFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field {\n                ...F\n              }\n              field {\n                ...F\n              }\n            }\n            fragment F on T {\n              deepField {\n                deeperField {\n                  x: a\n                }\n                deeperField {\n                  x: b\n                }\n              },\n              deepField {\n                deeperField {\n                  y\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'deeperField',\n                    ['x', 'a and b are different fields'],\n                    [[11, 5], [12, 7], [14, 5], [15, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testReportsDeepConflictsInNestedFragments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field {\n                ...F\n              }\n              field {\n                ...I\n              }\n            }\n            fragment F on T {\n              x: a\n              ...G\n            }\n            fragment G on T {\n              y: c\n            }\n            fragment I on T {\n              y: d\n              ...J\n            }\n            fragment J on T {\n              x: b\n            }\n            '),\n            [\n                fieldConflict(\n                    'field',\n                    [\n                        ['x', 'a and b are different fields'],\n                        ['y', 'c and d are different fields'],\n                    ],\n                    [[2, 3], [10, 3], [14, 3], [5, 3], [21, 3], [17, 3]]\n                )\n            ]\n        );\n    }\n\n    public function testIgnoresUnknownFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field\n              ...Unknown\n              ...Known\n            }\n            fragment Known on T {\n              field\n              ...OtherUnknown\n            }\n            ')\n        );\n    }\n\n    public function testConflictingReturnTypesWhichPotentiallyOverlap()\n    {\n        // This is invalid since an object could potentially be both the Object\n        // type IntBox and the interface type NonNullStringBox1. While that\n        // condition does not exist in the current schema, the schema could\n        // expand in the future to allow this. Thus it is invalid.\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ...on IntBox {\n                  scalar\n                }\n                ...on NonNullStringBox1 {\n                  scalar\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'scalar',\n                    'they return conflicting types Int and String!',\n                    [[4, 7], [7, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testCompatibleReturnShapesOnDifferentReturnTypes()\n    {\n        // In this case `deepBox` returns `SomeBox` in the first usage, and\n        // `StringBox` in the second usage. These return types are not the same!\n        // however this is valid because the return *shapes* are compatible.\n        $this->expectPassesRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on SomeBox {\n                  deepBox {\n                    unrelatedField\n                  }\n                }\n                ... on StringBox {\n                  deepBox {\n                    unrelatedField\n                  }\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testDisallowsDifferingReturnTypesDespiteNoOverlap()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  scalar\n                }\n                ... on StringBox {\n                  scalar\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'scalar',\n                    'they return conflicting types Int and String',\n                    [[4, 7], [7, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testReportsCorrectlyWhenANonExclusiveFollowsAnExclusive()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  deepBox {\n                    ...X\n                  }\n                }\n              }\n              someBox {\n                ... on StringBox {\n                  deepBox {\n                    ...Y\n                  }\n                }\n              }\n              memoed: someBox {\n                ... on IntBox {\n                  deepBox {\n                    ...X\n                  }\n                }\n              }\n              memoed: someBox {\n                ... on StringBox {\n                  deepBox {\n                    ...Y\n                  }\n                }\n              }\n              other: someBox {\n                ...X\n              }\n              other: someBox {\n                ...Y\n              }\n            }\n            fragment X on SomeBox {\n              scalar\n            }\n            fragment Y on SomeBox {\n              scalar: unrelatedField\n            }\n            '),\n            [\n                fieldConflict(\n                    'other',\n                    ['scalar', 'scalar and unrelatedField are different fields'],\n                    [[30, 3], [38, 3], [33, 3], [41, 3]]\n                )\n            ]\n        );\n    }\n\n    public function testDisallowsDifferingReturnTypeNullabilityDespiteNoOverlap()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            '\n{\n  someBox {\n    ... on NonNullStringBox1 {\n      scalar\n    }\n    ... on StringBox {\n      scalar\n    }\n  }\n}\n',\n            [\n                fieldConflict(\n                    'scalar',\n                    'they return conflicting types String! and String',\n                    [[4, 7], [7, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testDisallowsDifferingReturnTypeListDespiteNoOverlap()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  box: listStringBox {\n                    scalar\n                  }\n                }\n                ... on StringBox {\n                  box: stringBox {\n                    scalar\n                  }\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'box',\n                    'they return conflicting types [StringBox] and StringBox',\n                    [[4, 7], [9, 7]]\n                )\n            ]\n        );\n\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  box: stringBox {\n                    scalar\n                  }\n                }\n                ... on StringBox {\n                  box: listStringBox {\n                    scalar\n                  }\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'box',\n                    'they return conflicting types StringBox and [StringBox]',\n                    [[4, 7], [9, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testDisallowsDifferingSubfields()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  box: stringBox {\n                    val: scalar\n                    val: unrelatedField\n                  }\n                }\n                ... on StringBox {\n                  box: stringBox {\n                    val: scalar\n                  }\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'val',\n                    'scalar and unrelatedField are different fields',\n                    [[5, 9], [6, 9]]\n                )\n            ]\n        );\n    }\n\n    public function testDisallowsDifferingDeepReturnTypesDespiteNoOverlap()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  box: stringBox {\n                    scalar\n                  }\n                }\n                ... on StringBox {\n                  box: intBox {\n                    scalar\n                  }\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'box',\n                    ['scalar', 'they return conflicting types String and Int'],\n                    [[4, 7], [5, 9], [9, 7], [10, 9]]\n                )\n            ]\n        );\n    }\n\n    public function testAllowsNonConflictingOverlappingTypes()\n    {\n        $this->expectPassesRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ... on IntBox {\n                  scalar: unrelatedField\n                }\n                ... on StringBox {\n                  scalar\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testSameWrappedScalarReturnTypes()\n    {\n        $this->expectPassesRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ...on NonNullStringBox1 {\n                  scalar\n                }\n                ...on NonNullStringBox2 {\n                  scalar\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testAllowsInlineTypelessFragments()\n    {\n        $this->expectPassesRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              a\n              ... {\n                a\n              }\n            }\n            ')\n        );\n    }\n\n    public function testComparesDeepTypesIncludingList()\n    {\n        $this->expectFailsRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              connection {\n                ...edgeID\n                edges {\n                  node {\n                    id: name\n                  }\n                }\n              }\n            }\n            \n            fragment edgeID on Connection {\n              edges {\n                node {\n                  id\n                }\n              }\n            }\n            '),\n            [\n                fieldConflict(\n                    'edges',\n                    ['node', [['id', 'name and id are different fields']]],\n                    [[4, 5], [5, 7], [6, 9], [13, 3], [14, 5], [15, 7]]\n                )\n            ]\n        );\n    }\n\n    public function testIgnoresUnknownTypes()\n    {\n        $this->expectPassesRuleWithSchema(\n            $this->schema,\n            $this->rule,\n            dedent('\n            {\n              someBox {\n                ...on UnknownType {\n                  scalar\n                }\n                ...on NonNullStringBox2 {\n                  scalar\n                }\n              }\n            }\n            ')\n        );\n    }\n\n    public function testDoesNotInfiniteLoopOnRecursiveFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Human { name, relatives { name, ...fragA } }\n            ')\n        );\n    }\n\n    public function testDoesNotInfiniteLoopOnImmediatelyRecursiveFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Human { name, ...fragA }\n            ')\n        );\n    }\n\n    public function testDoesNotInfiniteLoopOnTransitivelyRecursiveFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Human { name, ...fragB }\n            fragment fragB on Human { name, ...fragC }\n            fragment fragC on Human { name, ...fragA }\n            ')\n        );\n    }\n\n    public function testFindsInvalidCaseEvenWithImmediatelyRecursiveFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment sameAliasesWithDifferentFieldTargets on Dog {\n              ...sameAliasesWithDifferentFieldTargets\n              fido: name\n              fido: nickname\n            }\n            '),\n            [\n                fieldConflict(\n                    'fido',\n                    'name and nickname are different fields',\n                    [[3, 3], [4, 3]]\n                )\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/PossibleFragmentSpreadsRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\PossibleFragmentSpreadsRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\typeIncompatibleAnonymousSpread;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\typeIncompatibleSpread;\n\nclass PossibleFragmentSpreadsRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return PossibleFragmentSpreadsRule::class;\n    }\n\n    public function testOfTheSameObject()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectWithinObject on Dog { ...dogFragment }\n            fragment dogFragment on Dog { barkVolume }\n            ')\n        );\n    }\n\n    public function testOfTheSameObjectWithInlineFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } }\n            ')\n        );\n    }\n\n    public function testObjectIntoAnImplementedInterface()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectWithinInterface on Pet { ...dogFragment }\n            fragment dogFragment on Dog { barkVolume }\n            ')\n        );\n    }\n\n    public function testObjectIntoContainingUnion()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment objectWithinUnion on CatOrDog { ...dogFragment }\n            fragment dogFragment on Dog { barkVolume }\n            ')\n        );\n    }\n\n    public function testUnionIntoContainedObject()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment unionWithinObject on Dog { ...catOrDogFragment }\n            fragment catOrDogFragment on CatOrDog { __typename }\n            ')\n        );\n    }\n\n    public function testUnionIntoOverlappingInterface()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment unionWithinInterface on Pet { ...catOrDogFragment }\n            fragment catOrDogFragment on CatOrDog { __typename }\n            ')\n        );\n    }\n\n    public function testUnionIntoOverlappingUnion()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment }\n            fragment catOrDogFragment on CatOrDog { __typename }\n            ')\n        );\n    }\n\n    public function testInterfaceIntoImplementedObject()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment interfaceWithinObject on Dog { ...petFragment }\n            fragment petFragment on Pet { name }\n            ')\n        );\n    }\n\n    public function testInterfaceIntoOverlappingInterface()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment interfaceWithinInterface on Pet { ...beingFragment }\n            fragment beingFragment on Being { name }\n            ')\n        );\n    }\n\n    public function testInterfaceIntoOverlappingInterfaceInInlineFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment interfaceWithinInterface on Pet { ... on Being { name } }\n            ')\n        );\n    }\n\n    public function testInterfaceIntoOverlappingUnion()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment interfaceWithinUnion on CatOrDog { ...petFragment }\n            fragment petFragment on Pet { name }\n            ')\n        );\n    }\n\n    public function testIgnoresIncorrectType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment petFragment on Pet { ...badInADifferentWay }\n            fragment badInADifferentWay on String { name }\n            ')\n        );\n    }\n\n    public function testDifferentObjectIntoObject()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidObjectWithinObject on Cat { ...dogFragment }\n            fragment dogFragment on Dog { barkVolume }\n            '),\n            [typeIncompatibleSpread('dogFragment', 'Cat', 'Dog', [1, 45])]\n        );\n    }\n\n    public function testDifferentObjectIntoObjectInInlineFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidObjectWithinObjectAnon on Cat {\n              ... on Dog { barkVolume }\n            }\n            '),\n            [typeIncompatibleAnonymousSpread('Cat', 'Dog', [2, 3])]\n        );\n    }\n\n    public function testObjectIntoNotImplementingInterface()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidObjectWithinInterface on Pet { ...humanFragment }\n            fragment humanFragment on Human { pets { name } }\n            '),\n            [typeIncompatibleSpread('humanFragment', 'Pet', 'Human', [1, 48])]\n        );\n    }\n\n    public function testObjectIntoNotContainingUnion()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment }\n            fragment humanFragment on Human { pets { name } }\n            '),\n            [typeIncompatibleSpread('humanFragment', 'CatOrDog', 'Human', [1, 49])]\n        );\n    }\n\n    public function testUnionIntoNotContainedObject()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidUnionWithinObject on Human { ...catOrDogFragment }\n            fragment catOrDogFragment on CatOrDog { __typename }\n            '),\n            [typeIncompatibleSpread('catOrDogFragment', 'Human', 'CatOrDog', [1, 46])]\n        );\n    }\n\n    public function testUnionIntoNonOverlappingInterface()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment }\n            fragment humanOrAlienFragment on HumanOrAlien { __typename }\n            '),\n            [typeIncompatibleSpread('humanOrAlienFragment', 'Pet', 'HumanOrAlien', [1, 47])]\n        );\n    }\n\n    public function testUnionIntoNonOverlappingUnion()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment }\n            fragment humanOrAlienFragment on HumanOrAlien { __typename }\n            '),\n            [typeIncompatibleSpread('humanOrAlienFragment', 'CatOrDog', 'HumanOrAlien', [1, 48])]\n        );\n    }\n\n    public function testInterfaceIntoNonImplementingObject()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment }\n            fragment intelligentFragment on Intelligent { iq }\n            '),\n            [typeIncompatibleSpread('intelligentFragment', 'Cat', 'Intelligent', [1, 48])]\n        );\n    }\n\n    public function testInterfaceIntoNonOverlappingInterface()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidInterfaceWithinInterface on Pet {\n              ...intelligentFragment\n            }\n            fragment intelligentFragment on Intelligent { iq }\n            '),\n            [typeIncompatibleSpread('intelligentFragment', 'Pet', 'Intelligent', [2, 3])]\n        );\n    }\n\n    public function testInterfaceIntoNonOverlappingInterfaceInInlineFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidInterfaceWithinInterfaceAnon on Pet {\n              ...on Intelligent { iq }\n            }\n            '),\n            [typeIncompatibleAnonymousSpread('Pet', 'Intelligent', [2, 3])]\n        );\n    }\n\n    public function testInterfaceIntoNonOverlappingUnion()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment }\n            fragment petFragment on Pet { name }\n            '),\n            [typeIncompatibleSpread('petFragment', 'HumanOrAlien', 'Pet', [1, 56])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/ProvidedRequiredArgumentsRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\ProvidedRequiredArgumentsRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\missingDirectiveArgument;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\missingFieldArgument;\n\nclass ProvidedRequiredArgumentsRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return ProvidedRequiredArgumentsRule::class;\n    }\n\n    public function testIgnoresUnknownArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog {\n                isHouseTrained(unknownArgument: true)\n              }\n            }\n            '\n        );\n    }\n\n    public function testValidNonNullableValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog {\n                isHouseTrained(atOtherHomes: true)\n              }\n            }\n            '\n        );\n    }\n\n    public function testNoArgumentOnOptionalArgument()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog {\n                isHouseTrained\n              }\n            }\n            '\n        );\n    }\n\n    public function testNoArgumentOnNonNullFieldWithDefaultValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                nonNullFieldWithDefault\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req1: 1, req2: 2)\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleArgumentsInReverseOrder()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req2: 2, req1: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testNoArgumentsOnMultipleOptional()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOpts\n              }\n            }\n            '\n        );\n    }\n\n    public function testOneArgumentOnMultipleOptional()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOpts(opt1: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testSecondArgumentOnMultipleOptional()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOpts(opt2: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleRequiredOnMixedList()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOptAndReq(req1: 3, req2: 4)\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleRequiredAndOneOptionalOnMixedList()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOptAndReq(req1: 3, req2: 4, opt1: 5)\n              }\n            }\n            '\n        );\n    }\n\n    public function testAllRequiredAndOptinalOnMixedList()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6)\n              }\n            }\n            '\n        );\n    }\n\n    public function testMissingOneNonNullableArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req2: 2)\n              }\n            }\n            ',\n            [missingFieldArgument('multipleReqs', 'req1', 'Int!', [3, 5])]\n        );\n    }\n\n    public function testMultipleNonNullableArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs\n              }\n            }\n            ',\n            [\n                missingFieldArgument('multipleReqs', 'req1', 'Int!', [3, 5]),\n                missingFieldArgument('multipleReqs', 'req2', 'Int!', [3, 5]),\n            ]\n        );\n    }\n\n    public function testIncorrectValueAndMissingArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req1: \"one\")\n              }\n            }\n            ',\n            [missingFieldArgument('multipleReqs', 'req2', 'Int!', [3, 5])]\n        );\n    }\n\n    public function testIgnoresUnknownDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog @unknown\n            }\n            '\n        );\n    }\n\n    public function testDirectivesOfValidTypes()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog @include(if: true) {\n                name\n              }\n              human @skip(if: false) {\n                name\n              }\n            }\n            '\n        );\n    }\n\n    public function testDirectiveWithMissingTypes()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog @include {\n                name @skip\n              }\n            }\n            ',\n            [\n                missingDirectiveArgument('include', 'if', 'Boolean!', [2, 7]),\n                missingDirectiveArgument('skip', 'if', 'Boolean!', [3, 10]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/RuleTestCase.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\GraphQLError;\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Validation\\Rule\\RuleInterface;\nuse Digia\\GraphQL\\Validation\\ValidatorInterface;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\testSchema;\n\nabstract class RuleTestCase extends TestCase\n{\n    /**\n     * @var ValidatorInterface\n     */\n    protected $validator;\n\n    /**\n     * @var RuleInterface\n     */\n    protected $rule;\n\n    abstract protected function getRuleClassName(): string;\n\n    public function setUp()\n    {\n        $this->validator = GraphQL::make(ValidatorInterface::class);\n        $this->rule      = GraphQL::make($this->getRuleClassName());\n    }\n\n    protected function expectPassesRule($rule, $query)\n    {\n        return $this->expectPassesRuleWithSchema(testSchema(), $rule, $query);\n    }\n\n    protected function expectPassesRuleWithSchema($schema, $rule, $query)\n    {\n        return $this->expectValid($schema, [$rule], $query);\n    }\n\n    protected function expectFailsRule($rule, $query, $expectedErrors = [])\n    {\n        return $this->expectFailsRuleWithSchema(testSchema(), $rule, $query, $expectedErrors);\n    }\n\n    protected function expectFailsRuleWithSchema($schema, $rule, $query, $expectedErrors = [])\n    {\n        return $this->expectInvalid($schema, [$rule], $query, $expectedErrors);\n    }\n\n    protected function expectValid($schema, $rules, $query)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $errors = $this->validator->validate($schema, parse(dedent($query)), $rules);\n        $this->assertEmpty($errors, 'Should validate');\n    }\n\n    protected function expectInvalid($schema, $rules, $query, $expectedErrors): array\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $errors = $this->validator->validate($schema, parse(dedent($query)), $rules);\n        $this->assertTrue(count($errors) >= 1, 'Should not validate');\n        $this->assertEquals($expectedErrors, array_map('Digia\\GraphQL\\Error\\formatError', $errors));\n        return $errors;\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/ScalarLeafsRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\ScalarLeafsRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\noSubselectionAllowed;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\requiredSubselection;\n\nclass ScalarLeafsRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return ScalarLeafsRule::class;\n    }\n\n    public function testValidScalarSelection()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelection on Dog {\n              barks\n            }\n            ')\n        );\n    }\n\n    public function testObjectTypeMissingSelection()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query directQueryOnObjectWithoutSubFields {\n              human\n            }\n            '),\n            [requiredSubselection('human', 'Human', [2, 3])]\n        );\n    }\n\n    public function testInterfaceTypeMissingSelection()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              human { pets }\n            }\n            '),\n            [requiredSubselection('pets', '[Pet]', [2, 11])]\n        );\n    }\n\n    public function testValidScalarSelectionWithArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelectionWithArgs on Dog {\n              doesKnowCommand(dogCommand: SIT)\n            }\n            ')\n        );\n    }\n\n    public function testScalarSelectionNotAllowedOnBoolean()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelectionsNotAllowedOnBoolean on Dog {\n              barks { sinceWhen }\n            }\n            '),\n            [noSubselectionAllowed('barks', 'Boolean', [2, 9])]\n        );\n    }\n\n    public function testScalarSelectionNotAllowedOnEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelectionsNotAllowedOnEnum on Cat {\n              furColor { inHexdec }\n            }\n            '),\n            [noSubselectionAllowed('furColor', 'FurColor', [2, 12])]\n        );\n    }\n\n    public function testScalarSelectionNotAllowedWithArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelectionsNotAllowedWithArgs on Dog {\n              doesKnowCommand(dogCommand: SIT) { sinceWhen }\n            }\n            '),\n            [noSubselectionAllowed('doesKnowCommand', 'Boolean', [2, 36])]\n        );\n    }\n\n    public function testScalarSelectionNotAllowedWithDirectives()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelectionsNotAllowedWithDirectives on Dog {\n              name @include(if: true) { isAlsoHumanName }\n            }\n            '),\n            [noSubselectionAllowed('name', 'String', [2, 27])]\n        );\n    }\n\n    public function testScalarSelectionNotAllowedWithDirectivesAndArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog {\n              doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen }\n            }\n            '),\n            [noSubselectionAllowed('doesKnowCommand', 'Boolean', [2, 55])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/SingleFieldSubscriptionsRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\SingleFieldSubscriptionsRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\singleFieldOnly;\n\nclass SingleFieldSubscriptionsRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return SingleFieldSubscriptionsRule::class;\n    }\n\n    public function testValidSubscription()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            subscription ImportantEmails {\n              importantEmails\n            }\n            ')\n        );\n    }\n\n    public function testFailsWithMoreThanOneRootField()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            subscription ImportantEmails {\n              importantEmails\n              notImportantEmails\n            }\n            '),\n            [singleFieldOnly('ImportantEmails', [[3, 3]])]\n        );\n    }\n\n    public function testFailsWithMoreThanOneRootFieldIncludingIntrospection()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            subscription ImportantEmails {\n              importantEmails\n              __typename\n            }\n            '),\n            [singleFieldOnly('ImportantEmails', [[3, 3]])]\n        );\n    }\n\n    public function testFailsWithManyMoreThanOneRootField()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            subscription ImportantEmails {\n              importantEmails\n              notImportantEmails\n              spamEmails\n            }\n            '),\n            [singleFieldOnly('ImportantEmails', [[3, 3], [4, 3]])]\n        );\n    }\n\n    public function testFailsWithMoreThanOneRootFieldInAnonymousSubscription()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            subscription {\n              importantEmails\n              notImportantEmails\n            }\n            '),\n            [singleFieldOnly(null, [[3, 3]])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/UniqueArgumentNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueArgumentNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\duplicateArgument;\n\nclass UniqueArgumentNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return UniqueArgumentNamesRule::class;\n    }\n\n    public function testNoArgumentsOnField()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testNoArgumentsOnDirective()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field @directive\n            }\n            ')\n        );\n    }\n\n    public function testArgumentOnField()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: \"value\")\n            }\n            ')\n        );\n    }\n\n    public function testArgumentOnDirective()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field @directive(arg: \"value\")\n            }\n            ')\n        );\n    }\n\n    public function testSameArgumentOnTwoFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              one: field(arg: \"value\")\n              two: field(arg: \"value\")\n            }\n            ')\n        );\n    }\n\n    public function testSameArgumentOnFieldAndDirective()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: \"value\") @directive(arg: \"value\")\n            }\n            ')\n        );\n    }\n\n    public function testSameArgumentOnTwoDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field @directive1(arg: \"value\") @directive2(arg: \"value\")\n            }\n            ')\n        );\n    }\n\n    public function testMultipleFieldArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field @directive(arg1: \"value\", arg2: \"value\", arg3: \"value\")\n            }\n            ')\n        );\n    }\n\n    public function testDuplicateFieldArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg1: \"value\", arg1: \"value\")\n            }\n            '),\n            [duplicateArgument('arg1', [[2, 9], [2, 24]])]\n        );\n    }\n\n    public function testManyDuplicateFieldArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg1: \"value\", arg1: \"value\", arg1: \"value\")\n            }\n            '),\n            [\n                duplicateArgument('arg1', [[2, 9], [2, 24]]),\n                duplicateArgument('arg1', [[2, 9], [2, 39]]),\n            ]\n        );\n    }\n\n    public function testDuplicateDirectiveArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field @directive(arg1: \"value\", arg1: \"value\")\n            }\n            '),\n            [duplicateArgument('arg1', [[2, 20], [2, 35]])]\n        );\n    }\n\n    public function testManyDuplicateDirectiveArguments()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field @directive(arg1: \"value\", arg1: \"value\", arg1: \"value\")\n            }\n            '),\n            [\n                duplicateArgument('arg1', [[2, 20], [2, 35]]),\n                duplicateArgument('arg1', [[2, 20], [2, 50]]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/UniqueDirectivesPerLocationRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueDirectivesPerLocationRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\duplicateDirective;\n\nclass UniqueDirectivesPerLocationRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return UniqueDirectivesPerLocationRule::class;\n    }\n\n    public function testNoDirectives()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testUniqueDirectivesInDifferentLocations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type @directiveA {\n              field @directiveB\n            }\n            ')\n        );\n    }\n\n    public function testUniqueDirectivesInSameLocations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type @directiveA @directiveB {\n              field @directiveA @directiveB\n            }\n            ')\n        );\n    }\n\n    public function testSameDirectivesInDifferentLocations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type @directiveA {\n              field @directiveA\n            }\n            ')\n        );\n    }\n\n    public function testSameDirectivesInSimilarLocations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type {\n              field @directive\n              field @directive\n            }\n            ')\n        );\n    }\n\n    public function testDuplicateDirectivesInOneLocation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type {\n              field @directive @directive\n            }\n            '),\n            [duplicateDirective('directive', [[2, 9], [2, 20]])]\n        );\n    }\n\n    public function testManyDuplicateDirectivesInOneLocation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type {\n              field @directive @directive @directive\n            }\n            '),\n            [\n                duplicateDirective('directive', [[2, 9], [2, 20]]),\n                duplicateDirective('directive', [[2, 9], [2, 31]]),\n            ]\n        );\n    }\n\n    public function testDifferentDuplicateDirectivesInOneLocations()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type {\n              field @directiveA @directiveB @directiveA @directiveB\n            }\n            '),\n            [\n                duplicateDirective('directiveA', [[2, 9], [2, 33]]),\n                duplicateDirective('directiveB', [[2, 21], [2, 45]]),\n            ]\n        );\n    }\n\n    public function testDuplicateDirectivesInManyLocations()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment Test on Type @directive @directive {\n              field @directive @directive\n            }\n            '),\n            [\n                duplicateDirective('directive', [[1, 23], [1, 34]]),\n                duplicateDirective('directive', [[2, 9], [2, 20]]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/UniqueFragmentNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueFragmentNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\duplicateFragment;\n\nclass UniqueFragmentNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return UniqueFragmentNamesRule::class;\n    }\n\n    public function testNoFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testOneFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              ...fragA\n            }\n            fragment fragA on Type {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testManyFragments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              ...fragA\n              ...fragB\n              ...fragC\n            }\n            fragment fragA on Type {\n              fieldA\n            }\n            fragment fragB on Type {\n              fieldB\n            }\n            fragment fragC on Type {\n              fieldC\n            }\n            ')\n        );\n    }\n\n    public function testInlineFragmentsAreAlwaysUnique()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              ...on Type {\n                fieldA\n              }\n              ...on Type {\n                fieldB\n              }\n            }\n            ')\n        );\n    }\n\n    public function testFragmentsNamedTheSame()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              ...fragA\n            }\n            fragment fragA on Type {\n              fieldA\n            }\n            fragment fragA on Type {\n              fieldB\n            }\n            '),\n            [duplicateFragment('fragA', [[4, 10], [7, 10]])]\n        );\n    }\n\n    public function testFragmentsNamedTheSameWithoutBeingReferenced()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Type {\n              fieldA\n            }\n            fragment fragA on Type {\n              fieldB\n            }\n            '),\n            [duplicateFragment('fragA', [[1, 10], [4, 10]])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/UniqueInputFieldNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueInputFieldNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\duplicateInputField;\n\nclass UniqueInputFieldNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return UniqueInputFieldNamesRule::class;\n    }\n\n    public function testInputObjectWithFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: { f: true })\n            }\n            ')\n        );\n    }\n\n    public function testSameInputObjectWithTwoArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg1: { f: true }, arg2: { f: true })\n            }\n            ')\n        );\n    }\n\n    public function testMultipleInputObjectFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: { f1: \"value\", f2: \"value\", f3: \"value\" })\n            }\n            ')\n        );\n    }\n\n    public function testAllowsForNestedInputObjectsWithSimilarFields()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: {\n                deep: {\n                  deep: {\n                    id: 1\n                  }\n                  id: 1\n                }\n                id: 1\n              })\n            }\n            ')\n        );\n    }\n\n    public function testDuplicateInputObjectFields()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: { f1: \"value\", f1: \"value\" })\n            }\n            '),\n            [duplicateInputField('f1', [[2, 16], [2, 29]])]\n        );\n    }\n\n    public function testManyDuplicateInputObjectFields()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            {\n              field(arg: { f1: \"value\", f1: \"value\", f1: \"value\" })\n            }\n            '),\n            [\n                duplicateInputField('f1', [[2, 16], [2, 29]]),\n                duplicateInputField('f1', [[2, 16], [2, 42]]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/UniqueOperationNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueOperationNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\duplicateOperation;\n\nclass UniqueOperationNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return UniqueOperationNamesRule::class;\n    }\n\n    public function testNoOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment fragA on Type {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testOneAnonymousOperation()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testOneNamedOperation()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testMultipleOperations()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              field\n            }\n            \n            query Bar {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testMultipleOperationsOfDifferentTypes()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              field\n            }\n            \n            mutation Bar {\n              field\n            }\n            \n            subscription Baz {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testFragmentAndOperationWithTheSameName()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              ...Foo\n            }\n            \n            fragment Foo on Type {\n              field\n            }\n            ')\n        );\n    }\n\n    public function testMultipleOperationWithTheSameName()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              fieldA\n            }\n            \n            query Foo {\n              fieldB\n            }\n            '),\n            [duplicateOperation('Foo', [[1, 7], [5, 7]])]\n        );\n    }\n\n    public function testMultipleOperationsWithTheSameNameOfDifferentTypesMutation()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              fieldA\n            }\n            \n            mutation Foo {\n              fieldB\n            }\n            '),\n            [duplicateOperation('Foo', [[1, 7], [5, 10]])]\n        );\n    }\n\n    public function testMultipleOperationsWithTheSameNameOfDifferentTypesSubscription()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo {\n              fieldA\n            }\n            \n            subscription Foo {\n              fieldB\n            }\n            '),\n            [duplicateOperation('Foo', [[1, 7], [5, 14]])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/UniqueVariableNamesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\UniqueVariableNamesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\duplicateVariable;\n\nclass UniqueVariableNamesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return UniqueVariableNamesRule::class;\n    }\n\n    public function testUniqueVariableNames()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query A($x: Int, $y: String) { __typename }\n            query B($x: String, $y: Int) { __typename }\n            ')\n        );\n    }\n\n    public function testDuplicateVariableNames()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query A($x: Int, $x: Int, $x: String) { __typename }\n            query B($x: String, $x: Int) { __typename }\n            query C($x: Int, $x: Int) { __typename }\n            '),\n            [\n                duplicateVariable('x', [[1, 10], [1, 19]]),\n                duplicateVariable('x', [[1, 10], [1, 28]]),\n                duplicateVariable('x', [[2, 10], [2, 22]]),\n                duplicateVariable('x', [[3, 10], [3, 19]]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/ValuesOfCorrectTypeRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Validation\\Rule\\ValuesOfCorrectTypeRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\badValue;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\requiredField;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\unknownField;\n\nclass ValuesOfCorrectTypeRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return ValuesOfCorrectTypeRule::class;\n    }\n\n    public function testGoodIntValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: 2)\n              }\n            }\n            '\n        );\n    }\n\n    public function testGoodNegativeIntValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: -2)\n              }\n            }\n            '\n        );\n    }\n\n    public function testGoodBooleanValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                booleanArgField(booleanArg: true)\n              }\n            }\n            '\n        );\n    }\n\n    public function testGoodStringValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringArgField(stringArg: \"foo\")\n              }\n            }\n            '\n        );\n    }\n\n    public function testGoodFloatValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                floatArgField(floatArg: 1.1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testGoodNegativeFloatValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                floatArgField(floatArg: -1.1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testIntIntoFloat()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                floatArgField(floatArg: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testStringIntoID()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                idArgField(idArg: \"someIdString\")\n              }\n            }\n            '\n        );\n    }\n\n    public function testGoodEnumValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: SIT)\n              }\n            }\n            '\n        );\n    }\n\n    public function testEnumWithUndefinedValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                enumArgField(enumArg: UNKNOWN)\n              }\n            }\n            '\n        );\n    }\n\n    public function testEnumWithNullValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                enumArgField(enumArg: NO_FUR)\n              }\n            }\n            '\n        );\n    }\n\n    public function testNullIntoNullableType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: null)\n              }\n            }\n            '\n        );\n\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog(a: null, b: null, c:{ requiredField: true, intField: null }) {\n                name\n              }\n            }\n            '\n        );\n    }\n\n    public function testIntIntoString()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringArgField(stringArg: 1)\n              }\n            }\n            ',\n            [badValue('String', '1', [3, 31])]\n        );\n    }\n\n    public function testFloatIntoString()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringArgField(stringArg: 1.0)\n              }\n            }\n            ',\n            [badValue('String', '1.0', [3, 31])]\n        );\n    }\n\n    public function testBooleanIntoString()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringArgField(stringArg: true)\n              }\n            }\n            ',\n            [badValue('String', 'true', [3, 31])]\n        );\n    }\n\n    public function testUnquotedStringIntoString()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringArgField(stringArg: BAR)\n              }\n            }\n            ',\n            [badValue('String', 'BAR', [3, 31])]\n        );\n    }\n\n    public function testStringIntoInt()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: \"3\")\n\n              }\n            }\n            ',\n            [badValue('Int', '\"3\"', [3, 25])]\n        );\n    }\n\n    public function testBigIntIntoInt()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: 829384293849283498239482938)\n              }\n            }\n            ',\n            [badValue('Int', '829384293849283498239482938', [3, 25])]\n        );\n    }\n\n    public function testUnquotedStringIntoInt()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: FOO)\n              }\n            }\n            ',\n            [badValue('Int', 'FOO', [3, 25])]\n        );\n    }\n\n    public function testSimpleFloatIntoInt()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: 3.0)\n              }\n            }\n            ',\n            [badValue('Int', '3.0', [3, 25])]\n        );\n    }\n\n    public function testFloatIntoInt()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                intArgField(intArg: 3.333)\n              }\n            }\n            ',\n            [badValue('Int', '3.333', [3, 25])]\n        );\n    }\n\n    public function testStringIntoFloat()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                floatArgField(floatArg: \"3.333\")\n              }\n            }\n            ',\n            [badValue('Float', '\"3.333\"', [3, 29])]\n        );\n    }\n\n    public function testBooleanIntoFloat()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                floatArgField(floatArg: true)\n              }\n            }\n            ',\n            [badValue('Float', 'true', [3, 29])]\n        );\n    }\n\n    public function testUnquotedStringIntoFloat()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                floatArgField(floatArg: FOO)\n              }\n            }\n            ',\n            [badValue('Float', 'FOO', [3, 29])]\n        );\n    }\n\n    public function testIntIntoBoolean()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                booleanArgField(booleanArg: 2)\n              }\n            }\n            ',\n            [badValue('Boolean', '2', [3, 33])]\n        );\n    }\n\n    public function testFloatIntoBoolean()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                booleanArgField(booleanArg: 1.0)\n              }\n            }\n            ',\n            [badValue('Boolean', '1.0', [3, 33])]\n        );\n    }\n\n    public function testStringIntoBoolean()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                booleanArgField(booleanArg: \"true\")\n              }\n            }\n            ',\n            [badValue('Boolean', '\"true\"', [3, 33])]\n        );\n    }\n\n    public function testUnquotedStringIntoBoolean()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                booleanArgField(booleanArg: TRUE)\n              }\n            }\n            ',\n            [badValue('Boolean', 'TRUE', [3, 33])]\n        );\n    }\n\n    public function testFloatIntoID()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                idArgField(idArg: 1.0)\n              }\n            }\n            ',\n            [badValue('ID', '1.0', [3, 23])]\n        );\n    }\n\n    public function testBooleanIntoID()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                idArgField(idArg: true)\n              }\n            }\n            ',\n            [badValue('ID', 'true', [3, 23])]\n        );\n    }\n\n    public function testUnquotedStringIntoID()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                idArgField(idArg: SOMETHING)\n              }\n            }\n            ',\n            [badValue('ID', 'SOMETHING', [3, 23])]\n        );\n    }\n\n    public function testIntIntoEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: 2)\n              }\n            }\n            ',\n            [badValue('DogCommand', '2', [3, 33])]\n        );\n    }\n\n    public function testFloatIntoEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: 1.0)\n              }\n            }\n            ',\n            [badValue('DogCommand', '1.0', [3, 33])]\n        );\n    }\n\n    public function testStringIntoEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: \"SIT\")\n              }\n            }\n            ',\n            [badValue('DogCommand', '\"SIT\"', [3, 33], 'Did you mean the enum value SIT?')]\n        );\n    }\n\n    public function testBooleanIntoEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: true)\n              }\n            }\n            ',\n            [badValue('DogCommand', 'true', [3, 33])]\n        );\n    }\n\n    public function testEnumValueIntoEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: JUGGLE)\n              }\n            }\n            ',\n            [badValue('DogCommand', 'JUGGLE', [3, 33])]\n        );\n    }\n\n    public function testDifferentCaseEnumValueIntoEnum()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog {\n                doesKnowCommand(dogCommand: sit)\n              }\n            }\n            ',\n            [badValue('DogCommand', 'sit', [3, 33], 'Did you mean the enum value SIT?')]\n        );\n    }\n\n    public function testGoodListValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringListArgField(stringListArg: [\"one\", null, \"two\"])\n              }\n            }\n            '\n        );\n    }\n\n    public function testEmptyListValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringListArgField(stringListArg: [])\n              }\n            }\n            '\n        );\n    }\n\n    public function testNullValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringListArgField(stringListArg: null)\n              }\n            }\n            '\n        );\n    }\n\n    public function testSingleValueIntoList()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringListArgField(stringListArg: \"one\")\n              }\n            }\n            '\n        );\n    }\n\n    public function testInvalidListValueWithIncorrectItemType()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringListArgField(stringListArg: [\"one\", 2])\n              }\n            }\n            ',\n            [badValue('String', '2', [3, 47])]\n        );\n    }\n\n    public function testIntValueIntoListOfStrings()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                stringListArgField(stringListArg: 1)\n              }\n            }\n            ',\n            [badValue('[String]', '1', [3, 39])]\n        );\n    }\n\n    public function testValidNonNullableValueOnOptionalArgument()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog {\n                isHouseTrained(atOtherHomes: true)\n              }\n            }\n            '\n        );\n    }\n\n    public function testNoValueOnOptionalArgument()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog {\n                isHouseTrained\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req1: 1, req2: 2)\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleArgumentsInReverseOrder()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req2: 2, req1: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testNoArgumentsOnMultipleOptionalArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs\n              }\n            }\n            '\n        );\n    }\n\n    public function testNoArgumentOnMultipleOptionalArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOpts\n              }\n            }\n            '\n        );\n    }\n\n    public function testOneArgumentOnMultipleOptionalArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOpts(opt1: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testSecondArgumentOnMultipleOptionalArguments()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOpts(opt2: 1)\n              }\n            }\n            '\n        );\n    }\n\n    public function testMultipleRequiredArgumentsOnMixedList()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOptAndReq(req1: 3, req2: 4)\n              }\n            }\n            '\n        );\n    }\n\n    public function testAllRequiredAndOptionalArgumentsOnMixedList()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6)\n              }\n            }\n            '\n        );\n    }\n\n    public function testInvalidNonNullableValueWithIncorrectValueType()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req2: \"two\", req1: \"one\")\n              }\n            }\n            ',\n            [\n                badValue('Int!', '\"two\"', [3, 24]),\n                badValue('Int!', '\"one\"', [3, 37]),\n            ]\n        );\n    }\n\n    public function testIncorrectValueAndMissingArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req1: \"one\")\n              }\n            }\n            ',\n            [badValue('Int!', '\"one\"', [3, 24])]\n        );\n    }\n\n    public function testInvalidNonNullableValueWithNullValue()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                multipleReqs(req1: null)\n              }\n            }\n            ',\n            [badValue('Int!', 'null', [3, 24])]\n        );\n    }\n\n    public function testOptionalArgumentsDespiteRequiredFieldInType()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField\n              }\n            }\n            '\n        );\n    }\n\n    public function testPartialObjectOnlyRequired()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: { requiredField: true })\n              }\n            }\n            '\n        );\n    }\n\n    public function testParitalObjectRequiredFieldCanBeFalsey()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: { requiredField: false })\n              }\n            }\n            '\n        );\n    }\n\n    public function testPartialObjectIncludingRequired()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: { requiredField: true, intField: 4 })\n              }\n            }\n            '\n        );\n    }\n\n    public function testFullObject()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: {\n                  requiredField: true,\n                  intField: 4,\n                  stringField: \"foo\",\n                  booleanField: false,\n                  stringListField: [\"one\", \"two\"]\n                })\n              }\n            }\n            '\n        );\n    }\n\n    public function testFullObjectWithFieldsInDifferentOrder()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: {\n                  stringListField: [\"one\", \"two\"],\n                  booleanField: false,\n                  requiredField: true,\n                  stringField: \"foo\",\n                  intField: 4,\n                })\n              }\n            }\n            '\n        );\n    }\n\n    public function testPartialObjectWithMissingRequiredArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: { intField: 4 })\n              }\n            }\n            ',\n            [requiredField('ComplexInput', 'requiredField', 'Boolean!', [3, 33])]\n        );\n    }\n\n    public function testParitalObjectWithInvalidFieldType()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: {\n                  stringListField: [\"one\", 2],\n                  requiredField: true,\n                })\n              }\n            }\n            ',\n            [badValue('String', '2', [4, 32])]\n        );\n    }\n\n    public function testPartialObjectWithNullToNonNullField()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: {\n                  requiredField: true,\n                  nonNullField: null,\n                })\n              }\n            }\n            ',\n            [badValue('Boolean!', 'null', [5, 21])]\n        );\n    }\n\n    public function testPartialObjectUnknownFieldArgument()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              complicatedArgs {\n                complexArgField(complexArg: {\n                  requiredField: true,\n                  unknownField: \"value\"\n                })\n              }\n            }\n            ',\n            [unknownField(\n                'ComplexInput',\n                'unknownField',\n                [5, 7],\n                'Did you mean nonNullField, intField or booleanField?'\n            )]\n        );\n    }\n\n    public function testReportsOriginalErrorForCustomScalarWhichThrows()\n    {\n        /** @var GraphQLException[] $errors */\n        $errors = $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              invalidArg(arg: 123)\n            }\n            ',\n            [badValue('Invalid', '123', [2, 19], 'Invalid scalar is always invalid: 123')]\n        );\n        $this->assertEquals($errors[0]->getOriginalErrorMessage(), 'Invalid scalar is always invalid: 123');\n    }\n\n    public function testAllowsCustomScalarToAcceptComplexLiterals()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              test1: anyArg(arg: 123)\n              test2: anyArg(arg: \"abc\")\n              test3: anyArg(arg: [123, \"abc\"])\n              test4: anyArg(arg: {deep: [123, \"abc\"]})\n            }\n            '\n        );\n    }\n\n    public function testDirectiveArgumentsWithDirectivesOfValidTypes()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            {\n              dog @include(if: true) {\n                name\n              }\n              human @skip(if: false) {\n                name\n              }\n            }\n            '\n        );\n    }\n\n    public function testDirectiveArgumentsWithDirectiveWithIncorrectTypes()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            {\n              dog @include(if: \"yes\") {\n                name @skip(if: ENUM)\n              }\n            }\n            ',\n            [\n                badValue('Boolean!', '\"yes\"', [2, 20]),\n                badValue('Boolean!', 'ENUM', [3, 20]),\n            ]\n        );\n    }\n\n    public function testVariablesWithValidDefaultValues()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            query WithDefaultValues(\n              $a: Int = 1,\n              $b: String = \"ok\",\n              $c: ComplexInput = { requiredField: true, intField: 3 }\n            ) {\n              dog { name }\n            }\n            '\n        );\n    }\n\n    public function testVariablesWithValidDefaultNullValues()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            '\n            query WithDefaultValues(\n              $a: Int = null,\n              $b: String = null,\n              $c: ComplexInput = { requiredField: true, intField: null }\n            ) {\n              dog { name }\n            }\n            '\n        );\n    }\n\n    public function testVariablesWithInvalidDefaultNullValues()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            query WithDefaultValues(\n              $a: Int! = null,\n              $b: String! = null,\n              $c: ComplexInput = { requiredField: null, intField: null }\n            ) {\n              dog { name }\n            }\n            ',\n            [\n                badValue('Int!', 'null', [2, 14]),\n                badValue('String!', 'null', [3, 17]),\n                badValue('Boolean!', 'null', [4, 39]),\n            ]\n        );\n    }\n\n    public function testVariablesWithInvalidDefaultValues()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            query InvalidDefaultValues(\n              $a: Int = \"one\",\n              $b: String = 4,\n              $c: ComplexInput = \"notverycomplex\"\n            ) {\n              dog { name }\n            }\n            ',\n            [\n                badValue('Int', '\"one\"', [2, 13]),\n                badValue('String', '4', [3, 16]),\n                badValue('ComplexInput', '\"notverycomplex\"', [4, 22]),\n            ]\n        );\n    }\n\n    public function testVariablesWithComplexInvalidDefaultValues()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            query WithDefaultValues(\n              $a: ComplexInput = { requiredField: 123, intField: \"abc\" }\n            ) {\n              dog { name }\n            }\n            ',\n            [\n                badValue('Boolean!', '123', [2, 39]),\n                badValue('Int', '\"abc\"', [2, 54]),\n            ]\n        );\n    }\n\n    public function testComplexVariablesMissingRequiredField()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            query MissingRequiredField($a: ComplexInput = {intField: 3}) {\n              dog { name }\n            }\n            ',\n            [requiredField('ComplexInput', 'requiredField', 'Boolean!', [1, 47])]\n        );\n    }\n\n    public function testListVariablesWithInvalidItem()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            '\n            query InvalidItem($a: [String] = [\"one\", 2]) {\n              dog { name }\n            }\n            ',\n            [badValue('String', '2', [1, 42])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/VariablesAreInputTypesRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\VariablesAreInputTypesRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\nonInputTypeOnVariable;\n\nclass VariablesAreInputTypesRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return VariablesAreInputTypesRule::class;\n    }\n\n    public function testInputTypesAreValid()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) {\n              field(a: $a, b: $b, c: $c)\n            }\n            ')\n        );\n    }\n\n    public function testOutputTypesAreInvalid()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) {\n              field(a: $a, b: $b, c: $c)\n            }\n            '),\n            [\n                nonInputTypeOnVariable('a', 'Dog', [1, 15]),\n                nonInputTypeOnVariable('b', '[[CatOrDog!]]!', [1, 24]),\n                nonInputTypeOnVariable('c', 'Pet', [1, 44]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/VariablesDefaultValueAllowedRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\VariablesDefaultValueAllowedRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\variableDefaultValueNotAllowed;\n\nclass VariablesDefaultValueAllowedRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return VariablesDefaultValueAllowedRule::class;\n    }\n\n    public function testVariablesWithNoDefaultValues()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query NullableValues($a: Int, $b: String, $c: ComplexInput) {\n              dog { name }\n            }\n            ')\n        );\n    }\n\n    public function testRequiredVariablesWithoutDefaultValues()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query RequiredValues($a: Int!, $b: String!) {\n              dog { name }\n            }\n            ')\n        );\n    }\n\n    public function testVariablesWithValidDefaultValues()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query WithDefaultValues(\n              $a: Int = 1,\n              $b: String = \"ok\",\n              $c: ComplexInput = { requiredField: true, intField: 3 }\n            ) {\n              dog { name }\n            }\n            ')\n        );\n    }\n\n    public function testVariablesWithValidNullDefaultValues()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query WithDefaultValues(\n              $a: Int = null,\n              $b: String = null,\n              $c: ComplexInput = { requiredField: true, intField: null }\n            ) {\n              dog { name }\n            }\n            ')\n        );\n    }\n\n    public function testNoRequiredVariablesWithDefaultValues()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query UnreachableDefaultValues($a: Int! = 3, $b: String! = \"default\") {\n              dog { name }\n            }\n            '),\n            [\n                variableDefaultValueNotAllowed('a', 'Int!', 'Int', [1, 43]),\n                variableDefaultValueNotAllowed('b', 'String!', 'String', [1, 60]),\n            ]\n        );\n    }\n\n    public function testVariablesWithInvalidDefaultNullValues()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query WithDefaultValues($a: Int! = null, $b: String! = null) {\n              dog { name }\n            }\n            '),\n            [\n                variableDefaultValueNotAllowed('a', 'Int!', 'Int', [1, 36]),\n                variableDefaultValueNotAllowed('b', 'String!', 'String', [1, 56]),\n            ]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/Rule/VariablesInAllowedPositionRuleTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation\\Rule;\n\nuse Digia\\GraphQL\\Validation\\Rule\\VariablesInAllowedPositionRule;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\Test\\Functional\\Validation\\badVariablePosition;\n\nclass VariablesInAllowedPositionRuleTest extends RuleTestCase\n{\n    protected function getRuleClassName(): string\n    {\n        return VariablesInAllowedPositionRule::class;\n    }\n\n    public function testBooleanAllowsBoolean()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($booleanArg: Boolean)\n            {\n              complicatedArgs {\n                booleanArgField(booleanArg: $booleanArg)\n              }\n            }\n            ')\n        );\n    }\n\n    public function testBooleanAllowsBooleanWithinFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment booleanArgFrag on ComplicatedArgs {\n              booleanArgField(booleanArg: $booleanArg)\n            }\n            query Query($booleanArg: Boolean) {\n              complicatedArgs {\n                ...booleanArgFrag\n              }\n            }\n            ')\n        );\n\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($booleanArg: Boolean) {\n              complicatedArgs {\n                ...booleanArgFrag\n              }\n            }\n            fragment booleanArgFrag on ComplicatedArgs {\n              booleanArgField(booleanArg: $booleanArg)\n            }\n            ')\n        );\n    }\n\n    public function testBooleanAllowsNonNullBoolean()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($nonNullBooleanArg: Boolean!) {\n              complicatedArgs {\n                booleanArgField(booleanArg: $nonNullBooleanArg)\n              }\n            }\n            ')\n        );\n    }\n\n    public function testNonNullBooleanAllowsBooleanWithinFragment()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            fragment booleanArgFrag on ComplicatedArgs {\n              booleanArgField(booleanArg: $nonNullBooleanArg)\n            }\n            \n            query Query($nonNullBooleanArg: Boolean!) {\n              complicatedArgs {\n                ...booleanArgFrag\n              }\n            }\n            ')\n        );\n    }\n\n    public function testNonNullIntAllowsIntWithDefaultValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($intArg: Int = 1) {\n              complicatedArgs {\n                nonNullIntArgField(nonNullIntArg: $intArg)\n              }\n            }\n            ')\n        );\n    }\n\n    public function testListOfStringsAllowsListOfStrings()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($stringListVar: [String]) {\n              complicatedArgs {\n                stringListArgField(stringListArg: $stringListVar)\n              }\n            }\n            ')\n        );\n    }\n\n    public function testListOfNonNullStringsAllowsListOfStrings()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($stringListVar: [String!]) {\n              complicatedArgs {\n                stringListArgField(stringListArg: $stringListVar)\n              }\n            }\n            ')\n        );\n    }\n\n    public function testStringAllowsListOfStrings()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($stringVar: String) {\n              complicatedArgs {\n                stringListArgField(stringListArg: [$stringVar])\n              }\n            }\n            ')\n        );\n    }\n\n    public function testNonNullStringAllowsListOfStrings()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($stringVar: String!) {\n              complicatedArgs {\n                stringListArgField(stringListArg: [$stringVar])\n              }\n            }\n            ')\n        );\n    }\n\n    public function testComplexInputAllowsComplexInput()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($complexVar: ComplexInput) {\n              complicatedArgs {\n                complexArgField(complexArg: $complexVar)\n              }\n            }\n            ')\n        );\n    }\n\n    public function testComplexInputAllowsComplexInputInField()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($boolVar: Boolean = false) {\n              complicatedArgs {\n                complexArgField(complexArg: {requiredArg: $boolVar})\n              }\n            }\n            ')\n        );\n    }\n\n    public function testNonNullBooleanAllowsNonNullBooleanInDirective()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($boolVar: Boolean!) {\n              dog @include(if: $boolVar)\n            }\n            ')\n        );\n    }\n\n    public function testBooleanAllowsNonNullBooleanInDirectiveWithDefaultValue()\n    {\n        $this->expectPassesRule(\n            $this->rule,\n            dedent('\n            query Query($boolVar: Boolean = false) {\n              dog @include(if: $boolVar)\n            }\n            ')\n        );\n    }\n\n    public function testIntDisallowsNonNullInt()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Query($intArg: Int) {\n              complicatedArgs {\n                nonNullIntArgField(nonNullIntArg: $intArg)\n              }\n            }\n            '),\n            [badVariablePosition('intArg', 'Int', 'Int!', [[1, 13], [3, 39]])]\n        );\n    }\n\n    public function testIntDisallowsNonNullIntWithinFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment nonNullIntArgFieldFrag on ComplicatedArgs {\n              nonNullIntArgField(nonNullIntArg: $intArg)\n            }\n            \n            query Query($intArg: Int) {\n              complicatedArgs {\n                ...nonNullIntArgFieldFrag\n              }\n            }\n            '),\n            [badVariablePosition('intArg', 'Int', 'Int!', [[5, 13], [2, 37]])]\n        );\n    }\n\n    public function testIntDisallowsNonNullIntWithinNestedFragment()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            fragment outerFrag on ComplicatedArgs {\n              ...nonNullIntArgFieldFrag\n            }\n            \n            fragment nonNullIntArgFieldFrag on ComplicatedArgs {\n              nonNullIntArgField(nonNullIntArg: $intArg)\n            }\n            \n            query Query($intArg: Int) {\n              complicatedArgs {\n                ...outerFrag\n              }\n            }\n            '),\n            [badVariablePosition('intArg', 'Int', 'Int!', [[9, 13], [6, 37]])]\n        );\n    }\n\n    public function testBooleanDisallowsString()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Query($stringVar: String) {\n              complicatedArgs {\n                booleanArgField(booleanArg: $stringVar)\n              }\n            }\n            '),\n            [badVariablePosition('stringVar', 'String', 'Boolean', [[1, 13], [3, 33]])]\n        );\n    }\n\n    public function testStringDisallowsListOfStrings()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Query($stringVar: String) {\n              complicatedArgs {\n                stringListArgField(stringListArg: $stringVar)\n              }\n            }\n            '),\n            [badVariablePosition('stringVar', 'String', '[String]', [[1, 13], [3, 39]])]\n        );\n    }\n\n    public function testBooleanDisallowsNonNullBooleanInDirective()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Query($boolVar: Boolean) {\n              dog @include(if: $boolVar)\n            }\n            '),\n            [badVariablePosition('boolVar', 'Boolean', 'Boolean!', [[1, 13], [2, 20]])]\n        );\n    }\n\n    public function testStringDisallowsNonNullBooleanInDirective()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Query($stringVar: String) {\n              dog @include(if: $stringVar)\n            }\n            '),\n            [badVariablePosition('stringVar', 'String', 'Boolean!', [[1, 13], [2, 20]])]\n        );\n    }\n\n    public function testStringDisallowsListOfNonNullStrings()\n    {\n        $this->expectFailsRule(\n            $this->rule,\n            dedent('\n            query Query($stringListVar: [String]) {\n              complicatedArgs {\n                stringListNonNullArgField(stringListNonNullArg: $stringListVar)\n              }\n            }\n            '),\n            [badVariablePosition('stringListVar', '[String]', '[String!]', [[1, 13], [3, 53]])]\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/ValidationTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Validation\\ValidationException;\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\TypeInfo;\nuse Digia\\GraphQL\\Validation\\Rule\\SupportedRules;\nuse Digia\\GraphQL\\Validation\\ValidatorInterface;\nuse function Digia\\GraphQL\\Error\\formatError;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\n\nclass ValidationTest extends TestCase\n{\n    /**\n     * @var ValidatorInterface\n     */\n    protected $validator;\n\n    public function setUp()\n    {\n        $this->validator = GraphQL::make(ValidatorInterface::class);\n    }\n\n    public function testValidatesQueries()\n    {\n        $errors = $this->validateQuery(\n            testSchema(),\n            dedent('\n            query {\n              catOrDog {\n                ... on Cat {\n                  furColor\n                }\n                ... on Dog {\n                  isHouseTrained\n                }\n              }\n            }\n            ')\n        );\n\n        $this->assertEquals([], $errors, 'Should validate');\n    }\n\n    public function testDetectsBadScalarParse()\n    {\n        $errors = $this->validateQuery(\n            testSchema(),\n            dedent('\n            query {\n              invalidArg(arg: \"bad value\")\n            }\n            ')\n        );\n\n        $this->assertEquals([\n            'locations' => [['line' => 2, 'column' => 19]],\n            'message'   =>\n                'Expected type Invalid, found \"bad value\"; Invalid scalar is always invalid: bad value',\n            'path'      => null,\n        ], formatError($errors[0]));\n    }\n\n    public function testValidatesUsingACustomTypeInfo()\n    {\n        $typeInfo = new TypeInfo(testSchema(), function () {\n            return null;\n        });\n\n        $errors = $this->validateQuery(\n            testSchema(),\n            dedent('\n            query {\n              catOrDog {\n                ... on Cat {\n                  furColor\n                }\n                ... on Dog {\n                  isHouseTrained\n                }\n              }\n            }\n            '),\n            SupportedRules::build(),\n            $typeInfo\n        );\n\n        $errorMessages = \\array_map(function (ValidationException $ex) {\n            return $ex->getMessage();\n        }, $errors);\n\n        $this->assertEquals([\n            'Cannot query field \"catOrDog\" on type \"QueryRoot\". Did you mean \"catOrDog\"?',\n            'Cannot query field \"furColor\" on type \"Cat\". Did you mean \"furColor\"?',\n            'Cannot query field \"isHouseTrained\" on type \"Dog\". Did you mean \"isHouseTrained\"?'\n        ], $errorMessages);\n    }\n\n    /**\n     * @return GraphQLException[]\n     */\n    protected function validateQuery($schema, $query, $rules = null, $typeInfo = null)\n    {\n        return $this->validator->validate($schema, parse($query), $rules, $typeInfo);\n    }\n}\n"
  },
  {
    "path": "tests/Functional/Validation/errors.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation;\n\n\nuse function Digia\\GraphQL\\Language\\locationShorthandToArray;\nuse function Digia\\GraphQL\\Language\\locationsShorthandToArray;\nuse function Digia\\GraphQL\\Validation\\anonymousOperationNotAloneMessage;\nuse function Digia\\GraphQL\\Validation\\badValueMessage;\nuse function Digia\\GraphQL\\Validation\\badVariablePositionMessage;\nuse function Digia\\GraphQL\\Validation\\duplicateArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\duplicateDirectiveMessage;\nuse function Digia\\GraphQL\\Validation\\duplicateFragmentMessage;\nuse function Digia\\GraphQL\\Validation\\duplicateInputFieldMessage;\nuse function Digia\\GraphQL\\Validation\\duplicateOperationMessage;\nuse function Digia\\GraphQL\\Validation\\duplicateVariableMessage;\nuse function Digia\\GraphQL\\Validation\\fieldsConflictMessage;\nuse function Digia\\GraphQL\\Validation\\fragmentCycleMessage;\nuse function Digia\\GraphQL\\Validation\\fragmentOnNonCompositeMessage;\nuse function Digia\\GraphQL\\Validation\\misplacedDirectiveMessage;\nuse function Digia\\GraphQL\\Validation\\missingDirectiveArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\missingFieldArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\nonExecutableDefinitionMessage;\nuse function Digia\\GraphQL\\Validation\\nonInputTypeOnVariableMessage;\nuse function Digia\\GraphQL\\Validation\\noSubselectionAllowedMessage;\nuse function Digia\\GraphQL\\Validation\\requiredFieldMessage;\nuse function Digia\\GraphQL\\Validation\\requiresSubselectionMessage;\nuse function Digia\\GraphQL\\Validation\\singleFieldOnlyMessage;\nuse function Digia\\GraphQL\\Validation\\typeIncompatibleAnonymousSpreadMessage;\nuse function Digia\\GraphQL\\Validation\\typeIncompatibleSpreadMessage;\nuse function Digia\\GraphQL\\Validation\\undefinedFieldMessage;\nuse function Digia\\GraphQL\\Validation\\undefinedVariableMessage;\nuse function Digia\\GraphQL\\Validation\\unknownArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\unknownDirectiveArgumentMessage;\nuse function Digia\\GraphQL\\Validation\\unknownDirectiveMessage;\nuse function Digia\\GraphQL\\Validation\\unknownFieldMessage;\nuse function Digia\\GraphQL\\Validation\\unknownFragmentMessage;\nuse function Digia\\GraphQL\\Validation\\unknownTypeMessage;\nuse function Digia\\GraphQL\\Validation\\unusedFragmentMessage;\nuse function Digia\\GraphQL\\Validation\\unusedVariableMessage;\nuse function Digia\\GraphQL\\Validation\\variableDefaultValueNotAllowedMessage;\n\nfunction nonExecutableDefinition($definitionName, $location)\n{\n    return [\n        'message'   => nonExecutableDefinitionMessage($definitionName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction undefinedField($field, $type, $suggestedTypes, $suggestsFields, $location)\n{\n    return [\n        'message'   => undefinedFieldMessage($field, $type, $suggestedTypes, $suggestsFields),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction fragmentOnNonComposite($fragmentName, $typeName, $location)\n{\n    return [\n        'message'   => fragmentOnNonCompositeMessage($fragmentName, $typeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unknownArgument($argumentName, $fieldName, $typeName, $suggestedArguments, $location)\n{\n    return [\n        'message'   => unknownArgumentMessage($argumentName, $fieldName, $typeName, $suggestedArguments),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unknownDirectiveArgument($argumentName, $directiveName, $suggestedArguments, $location)\n{\n    return [\n        'message'   => unknownDirectiveArgumentMessage($argumentName, $directiveName, $suggestedArguments),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unknownDirective($directiveName, $location)\n{\n    return [\n        'message'   => unknownDirectiveMessage($directiveName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction misplacedDirective($directiveName, $directiveLocation, $location)\n{\n    return [\n        'message'   => misplacedDirectiveMessage($directiveName, $directiveLocation),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unknownFragment($fragmentName, $location)\n{\n    return [\n        'message'   => unknownFragmentMessage($fragmentName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unknownType($typeName, $suggestedTypes, $location)\n{\n    return [\n        'message'   => unknownTypeMessage($typeName, $suggestedTypes),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction anonymousOperationNotAlone($location)\n{\n    return [\n        'message'   => anonymousOperationNotAloneMessage(),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction fragmentCycle($fragmentName, $spreadNames, array $locations)\n{\n    return [\n        'message'   => fragmentCycleMessage($fragmentName, $spreadNames),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction undefinedVariable($variableName, $variableLocation, $operationName, $operationLocation)\n{\n    return [\n        'message'   => undefinedVariableMessage($variableName, $operationName),\n        'locations' => [\n            locationShorthandToArray($variableLocation),\n            locationShorthandToArray($operationLocation),\n        ],\n        'path'      => null,\n    ];\n}\n\nfunction unusedFragment($fragmentName, $location)\n{\n    return [\n        'message'   => unusedFragmentMessage($fragmentName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unusedVariable($variableName, $operationName, $location)\n{\n    return [\n        'message'   => unusedVariableMessage($variableName, $operationName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction fieldConflict($responseName, $reason, $locations)\n{\n    return [\n        'message'   => fieldsConflictMessage($responseName, $reason),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction typeIncompatibleSpread($fragmentName, $parentType, $fragmentType, $location)\n{\n    return [\n        'message'   => typeIncompatibleSpreadMessage($fragmentName, $parentType, $fragmentType),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction typeIncompatibleAnonymousSpread($parentType, $fragmentType, $location)\n{\n    return [\n        'message'   => typeIncompatibleAnonymousSpreadMessage($parentType, $fragmentType),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction missingFieldArgument($fieldName, $argumentName, $typeName, $location)\n{\n    return [\n        'message'   => missingFieldArgumentMessage($fieldName, $argumentName, $typeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction missingDirectiveArgument($directiveName, $argumentName, $typeName, $location)\n{\n    return [\n        'message'   => missingDirectiveArgumentMessage($directiveName, $argumentName, $typeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction noSubselectionAllowed($fieldName, $typeName, $location)\n{\n    return [\n        'message'   => noSubselectionAllowedMessage($fieldName, $typeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction requiredSubselection($fieldName, $typeName, $location)\n{\n    return [\n        'message'   => requiresSubselectionMessage($fieldName, $typeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction singleFieldOnly($name, $locations)\n{\n    return [\n        'message'   => singleFieldOnlyMessage($name),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction duplicateArgument($argumentName, $locations)\n{\n    return [\n        'message'   => duplicateArgumentMessage($argumentName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction duplicateDirective($directiveName, $locations)\n{\n    return [\n        'message'   => duplicateDirectiveMessage($directiveName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction duplicateFragment($fragmentName, $locations)\n{\n    return [\n        'message'   => duplicateFragmentMessage($fragmentName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction duplicateInputField($fieldName, $locations)\n{\n    return [\n        'message'   => duplicateInputFieldMessage($fieldName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction duplicateOperation($operationName, $locations)\n{\n    return [\n        'message'   => duplicateOperationMessage($operationName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction duplicateVariable($variableName, $locations)\n{\n    return [\n        'message'   => duplicateVariableMessage($variableName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction nonInputTypeOnVariable($variableName, $typeName, $location)\n{\n    return [\n        'message'   => nonInputTypeOnVariableMessage($variableName, $typeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction variableDefaultValueNotAllowed($variableName, $typeName, $guessedTypeName, $location)\n{\n    return [\n        'message'   => variableDefaultValueNotAllowedMessage($variableName, $typeName, $guessedTypeName),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction badVariablePosition($variableName, $typeName, $expectedTypeName, $locations)\n{\n    return [\n        'message'   => badVariablePositionMessage($variableName, $typeName, $expectedTypeName),\n        'locations' => locationsShorthandToArray($locations),\n        'path'      => null,\n    ];\n}\n\nfunction badValue($typeName, $value, $location, $message = null)\n{\n    return [\n        'message'   => badValueMessage($typeName, $value, $message),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction requiredField($typeName, $fieldName, $fieldNameType, $location)\n{\n    return [\n        'message'   => requiredFieldMessage($typeName, $fieldName, $fieldNameType),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n\nfunction unknownField($typeName, $fieldName, $location, $message = null)\n{\n    return [\n        'message'   => unknownFieldMessage($typeName, $fieldName, $message),\n        'locations' => [locationShorthandToArray($location)],\n        'path'      => null,\n    ];\n}\n"
  },
  {
    "path": "tests/Functional/Validation/harness.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional\\Validation;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse Digia\\GraphQL\\Type\\Definition\\EnumType;\nuse Digia\\GraphQL\\Type\\Definition\\InputObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\InterfaceType;\nuse Digia\\GraphQL\\Type\\Definition\\ObjectType;\nuse Digia\\GraphQL\\Type\\Definition\\ScalarType;\nuse Digia\\GraphQL\\Type\\Definition\\UnionType;\nuse function Digia\\GraphQL\\Type\\booleanType;\nuse function Digia\\GraphQL\\Type\\newDirective;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\floatType;\nuse function Digia\\GraphQL\\Type\\idType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newInterfaceType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\newObjectType;\nuse function Digia\\GraphQL\\Type\\newScalarType;\nuse function Digia\\GraphQL\\Type\\newSchema;\nuse function Digia\\GraphQL\\Type\\stringType;\nuse function Digia\\GraphQL\\Type\\newUnionType;\n\nfunction Being(): InterfaceType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newInterfaceType([\n            'name'   => 'Being',\n            'fields' => function () {\n                return [\n                    'name' => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                ];\n            },\n        ]);\n}\n\nfunction Pet(): InterfaceType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newInterfaceType([\n            'name'   => 'Pet',\n            'fields' => function () {\n                return [\n                    'name' => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                ];\n            },\n        ]);\n}\n\nfunction Canine(): InterfaceType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newInterfaceType([\n            'name'   => 'Canine',\n            'fields' => function () {\n                return [\n                    'name' => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                ];\n            },\n        ]);\n}\n\nfunction DogCommand(): EnumType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newEnumType([\n            'name'   => 'DogCommand',\n            'values' => [\n                'SIT'  => ['value' => 0],\n                'HEEL' => ['value' => 1],\n                'DOWN' => ['value' => 2],\n            ],\n        ]);\n}\n\nfunction Dog(): ObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newObjectType([\n            'name'       => 'Dog',\n            'fields'     => function () {\n                return [\n                    'name'            => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                    'nickname'        => ['type' => stringType()],\n                    'barkVolume'      => ['type' => intType()],\n                    'barks'           => ['type' => booleanType()],\n                    'doesKnowCommand' => [\n                        'type' => booleanType(),\n                        'args' => [\n                            'dogCommand' => ['type' => DogCommand()],\n                        ],\n                    ],\n                    'isHouseTrained'  => [\n                        'type' => booleanType(),\n                        'args' => [\n                            'atOtherHomes' => [\n                                'type'         => booleanType(),\n                                'defaultValue' => true,\n                            ],\n                        ],\n                    ],\n                    'isAtLocation'    => [\n                        'type' => booleanType(),\n                        'args' => ['x' => ['type' => intType()], 'y' => ['type' => intType()]],\n                    ],\n                ];\n            },\n            'interfaces' => [Being(), Pet(), Canine()],\n        ]);\n}\n\nfunction Cat(): ObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newObjectType([\n            'name'       => 'Cat',\n            'fields'     => function () {\n                return [\n                    'name'       => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                    'nickname'   => ['type' => stringType()],\n                    'meows'      => ['type' => booleanType()],\n                    'meowVolume' => ['type' => intType()],\n                    'furColor'   => ['type' => FurColor()],\n                ];\n            },\n            'interfaces' => [Being(), Pet()],\n        ]);\n}\n\nfunction CatOrDog(): UnionType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newUnionType([\n            'name'  => 'CatOrDog',\n            'types' => [Dog(), Cat()],\n        ]);\n}\n\nfunction Intelligent(): InterfaceType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newInterfaceType([\n            'name'   => 'Intelligent',\n            'fields' => [\n                'iq' => ['type' => intType()],\n            ],\n        ]);\n}\n\nfunction Human(): ObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newObjectType([\n            'name'       => 'Human',\n            'interfaces' => [Being(), Intelligent()],\n            'fields'     => function () {\n                return [\n                    'name'      => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                    'pets'      => ['type' => newList(Pet())],\n                    'relatives' => ['type' => newList(Human())],\n                    'iq'        => ['type' => intType()],\n                ];\n            },\n        ]);\n}\n\nfunction Alien(): ObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newObjectType([\n            'name'       => 'Alien',\n            'interfaces' => [Being(), Intelligent()],\n            'fields'     => function () {\n                return [\n                    'iq'      => ['type' => intType()],\n                    'name'    => [\n                        'type' => stringType(),\n                        'args' => ['surname' => ['type' => booleanType()]],\n                    ],\n                    'numEyes' => ['type' => intType()],\n                ];\n            },\n        ]);\n}\n\nfunction DogOrHuman(): UnionType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newUnionType([\n            'name'  => 'DogOrHuman',\n            'types' => [Dog(), Human()],\n        ]);\n}\n\nfunction HumanOrAlien(): UnionType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newUnionType([\n            'name'  => 'HumanOrAlien',\n            'types' => [Human(), Alien()],\n        ]);\n}\n\nfunction FurColor(): EnumType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newEnumType([\n            'name'   => 'FurColor',\n            'values' => [\n                'BROWN'   => ['value' => 0],\n                'BLACK'   => ['value' => 1],\n                'TAN'     => ['value' => 2],\n                'SPOTTED' => ['value' => 3],\n                'NO_FUR'  => ['value' => 4],\n                'UNKNOWN' => ['value' => 5],\n            ],\n        ]);\n}\n\nfunction ComplexInput(): InputObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newInputObjectType([\n            'name'   => 'ComplexInput',\n            'fields' => [\n                'requiredField'   => ['type' => newNonNull(booleanType())],\n                'nonNullField'    => ['type' => newNonNull(booleanType()), 'defaultValue' => false],\n                'intField'        => ['type' => intType()],\n                'stringField'     => ['type' => stringType()],\n                'booleanField'    => ['type' => booleanType()],\n                'stringListField' => ['type' => newList(stringType())],\n            ],\n        ]);\n}\n\nfunction ComplicatedArgs(): ObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newObjectType([\n            'name'   => 'ComplicatedArgs',\n            // TODO List\n            // TODO Coercion\n            // TODO NotNulls\n            'fields' => function () {\n                return [\n                    'intArgField'               => [\n                        'type' => stringType(),\n                        'args' => ['intArg' => ['type' => intType()]],\n                    ],\n                    'nonNullIntArgField'        => [\n                        'type' => stringType(),\n                        'args' => ['nonNullIntArg' => ['type' => newNonNull(intType())]],\n                    ],\n                    'stringArgField'            => [\n                        'type' => stringType(),\n                        'args' => ['stringArg' => ['type' => stringType()]],\n                    ],\n                    'booleanArgField'           => [\n                        'type' => stringType(),\n                        'args' => ['booleanArg' => ['type' => booleanType()]],\n                    ],\n                    'enumArgField'              => [\n                        'type' => stringType(),\n                        'args' => ['enumArg' => ['type' => FurColor()]],\n                    ],\n                    'floatArgField'             => [\n                        'type' => stringType(),\n                        'args' => ['floatArg' => ['type' => floatType()]],\n                    ],\n                    'idArgField'                => [\n                        'type' => stringType(),\n                        'args' => ['idArg' => ['type' => idType()]],\n                    ],\n                    'stringListArgField'        => [\n                        'type' => stringType(),\n                        'args' => ['stringListArg' => ['type' => newList(stringType())]],\n                    ],\n                    'stringListNonNullArgField' => [\n                        'type' => stringType(),\n                        'args' => ['stringListNonNullArg' => ['type' => newList(newNonNull(stringType()))]],\n                    ],\n                    'complexArgField'           => [\n                        'type' => stringType(),\n                        'args' => ['complexArg' => ['type' => ComplexInput()]],\n                    ],\n                    'multipleReqs'              => [\n                        'type' => stringType(),\n                        'args' => [\n                            'req1' => ['type' => newNonNull(intType())],\n                            'req2' => ['type' => newNonNull(intType())],\n                        ],\n                    ],\n                    'nonNullFieldWithDefault'   => [\n                        'type' => stringType(),\n                        'args' => [\n                            'arg' => ['type' => newNonNull(intType()), 'defaultValue' => 0],\n                        ],\n                    ],\n                    'multipleOpts'              => [\n                        'type' => stringType(),\n                        'args' => [\n                            'opt1' => ['type' => intType(), 'defaultValue' => 0],\n                            'opt2' => ['type' => intType(), 'defaultValue' => 0],\n                        ],\n                    ],\n                    'multipleOptsAndReq'        => [\n                        'type' => stringType(),\n                        'args' => [\n                            'req1' => ['type' => newNonNull(intType())],\n                            'req2' => ['type' => newNonNull(intType())],\n                            'opt1' => ['type' => intType(), 'defaultValue' => 0],\n                            'opt2' => ['type' => intType(), 'defaultValue' => 0],\n                        ],\n                    ],\n                ];\n            },\n        ]);\n}\n\nfunction InvalidScalar(): ScalarType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newScalarType([\n            'name'         => 'Invalid',\n            'serialize'    => function ($value) {\n                return $value;\n            },\n            'parseLiteral' => function ($node) {\n                throw new \\Exception(sprintf('Invalid scalar is always invalid: %s', $node->getValue()));\n            },\n            'parseValue'   => function ($value) {\n                throw new \\Exception(sprintf('Invalid scalar is always invalid: %s', $value));\n            },\n        ]);\n}\n\nfunction AnyScalar(): ScalarType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newScalarType([\n            'name'         => 'Any',\n            'serialize'    => function ($value) {\n                return $value;\n            },\n            'parseLiteral' => function ($node) {\n                return $node;\n            },\n            'parseValue'   => function ($value) {\n                return $value;\n            },\n        ]);\n}\n\nfunction QueryRoot(): ObjectType\n{\n    static $instance = null;\n    return $instance ??\n        $instance = newObjectType([\n            'name'   => 'QueryRoot',\n            'fields' => function () {\n                return [\n                    'human'           => [\n                        'args' => ['id' => ['type' => idType()]],\n                        'type' => Human(),\n                    ],\n                    'alien'           => ['type' => Alien()],\n                    'dog'             => ['type' => Dog()],\n                    'cat'             => ['type' => Cat()],\n                    'pet'             => ['type' => Pet()],\n                    'catOrDog'        => ['type' => CatOrDog()],\n                    'dogOrHuman'      => ['type' => DogOrHuman()],\n                    'humanOrAlien'    => ['type' => HumanOrAlien()],\n                    'complicatedArgs' => ['type' => ComplicatedArgs()],\n                    'invalidArg'      => [\n                        'args' => ['arg' => ['type' => InvalidScalar()]],\n                        'type' => stringType(),\n                    ],\n                    'anyArg'          => [\n                        'args' => ['arg' => ['type' => AnyScalar()]],\n                        'type' => stringType(),\n                    ],\n                ];\n            },\n        ]);\n}\n\n/**\n * @return Schema\n */\nfunction testSchema(): Schema\n{\n    return newSchema([\n        'query'      => QueryRoot(),\n        'types'      => [Cat(), Dog(), Human(), Alien()],\n        'directives' => [\n            IncludeDirective(),\n            SkipDirective(),\n            newDirective([\n                'name'      => 'onQuery',\n                'locations' => ['QUERY'],\n            ]),\n            newDirective([\n                'name'      => 'onMutation',\n                'locations' => ['MUTATION'],\n            ]),\n            newDirective([\n                'name'      => 'onSubscription',\n                'locations' => ['SUBSCRIPTION'],\n            ]),\n            newDirective([\n                'name'      => 'onField',\n                'locations' => ['FIELD'],\n            ]),\n            newDirective([\n                'name'      => 'onFragmentDefinition',\n                'locations' => ['FRAGMENT_DEFINITION'],\n            ]),\n            newDirective([\n                'name'      => 'onFragmentSpread',\n                'locations' => ['FRAGMENT_SPREAD'],\n            ]),\n            newDirective([\n                'name'      => 'onInlineFragment',\n                'locations' => ['INLINE_FRAGMENT'],\n            ]),\n            newDirective([\n                'name'      => 'onSchema',\n                'locations' => ['SCHEMA'],\n            ]),\n            newDirective([\n                'name'      => 'onScalar',\n                'locations' => ['SCALAR'],\n            ]),\n            newDirective([\n                'name'      => 'onObject',\n                'locations' => ['OBJECT'],\n            ]),\n            newDirective([\n                'name'      => 'onFieldDefinition',\n                'locations' => ['FIELD_DEFINITION'],\n            ]),\n            newDirective([\n                'name'      => 'onArgumentDefinition',\n                'locations' => ['ARGUMENT_DEFINITION'],\n            ]),\n            newDirective([\n                'name'      => 'onInterface',\n                'locations' => ['INTERFACE'],\n            ]),\n            newDirective([\n                'name'      => 'onUnion',\n                'locations' => ['UNION'],\n            ]),\n            newDirective([\n                'name'      => 'onEnum',\n                'locations' => ['ENUM'],\n            ]),\n            newDirective([\n                'name'      => 'onEnumValue',\n                'locations' => ['ENUM_VALUE'],\n            ]),\n            newDirective([\n                'name'      => 'onInputObject',\n                'locations' => ['INPUT_OBJECT'],\n            ]),\n            newDirective([\n                'name'      => 'onInputFieldDefinition',\n                'locations' => ['INPUT_FIELD_DEFINITION'],\n            ]),\n        ],\n    ]);\n}\n"
  },
  {
    "path": "tests/Functional/ValidationTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional;\n\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\parse;\nuse function Digia\\GraphQL\\validate;\n\nclass ValidationTest extends TestCase\n{\n    // Star Wars Validation Tests\n\n    // Basic Queries\n\n    // Validates a complex but valid query\n\n    public function testValidatesAComplexButValidQuery()\n    {\n        $query = '\n        query NestedQueryWithFragment {\n          hero {\n            ...NameAndAppearances\n            friends {\n              ...NameAndAppearances\n              friends {\n                ...NameAndAppearances\n              }\n            }\n          }\n        }\n        \n        fragment NameAndAppearances on Character {\n          name\n          appearsIn\n        }\n        ';\n\n        $this->assertEmpty($this->validateQuery($query));\n    }\n\n    // Notes that non-existent fields are invalid\n\n    public function testNodesThatNonExistentFieldsAreInvalid()\n    {\n        $query = '\n        query HeroSpaceshipQuery {\n          hero {\n            favoriteSpaceship\n          }\n        }\n        ';\n\n        $this->assertNotEmpty($this->validateQuery($query));\n    }\n\n    // Requires fields on objects\n\n    public function testRequiresFieldsOnObjects()\n    {\n        $query = '\n        query HeroNoFieldsQuery {\n          hero\n        }\n        ';\n\n        $this->assertNotEmpty($this->validateQuery($query));\n    }\n\n    // Disallows fields on scalars\n\n    public function testDisallowsFieldsOnScalars()\n    {\n        $query = '\n        query HeroNoFieldsQuery {\n          hero {\n            name {\n              firstCharacterOfName\n            }\n          }\n        }\n        ';\n\n        $this->assertNotEmpty($this->validateQuery($query));\n    }\n\n    // Disallows object fields on interfaces\n\n    public function testDisallowsObjectFieldsOnInterfaces()\n    {\n        $query = '\n        query DroidFieldOnCharacter {\n          hero {\n            name\n            primaryFunction\n          }\n        }\n        ';\n\n        $this->assertNotEmpty($this->validateQuery($query));\n    }\n\n    // Allows object fields in fragments\n\n    public function testAllowsObjectFieldsInFragments()\n    {\n        $query = '\n        query DroidFieldInFragment {\n          hero {\n            name\n            ...DroidFields\n          }\n        }\n        \n        fragment DroidFields on Droid {\n          primaryFunction\n        }\n        ';\n\n        $this->assertEmpty($this->validateQuery($query));\n    }\n\n    // Allows object fields in inline fragments\n\n    public function testAllowsObjectFieldsInInlineFragments()\n    {\n        $query = '\n        query DroidFieldInFragment {\n          hero {\n            name\n            ... on Droid {\n              primaryFunction\n            }\n          }\n        }\n        ';\n\n        $this->assertEmpty($this->validateQuery($query));\n    }\n\n    protected function validateQuery($query)\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $source = new Source($query, 'StarWars.graphql');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return validate(starWarsSchema(), parse($source));\n    }\n}\n"
  },
  {
    "path": "tests/Functional/starWars.graphqls",
    "content": "schema {\n    query: Query\n}\n\ntype Query {\n    hero(\n        \"If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.\"\n        episode: Episode\n    ): Character\n    human(\n        \"id of the human\"\n        id: String!\n    ): Human\n    droid(\n        \"id of the droid\"\n        id: String!\n    ): Droid\n}\n\n\"A character in the Star Wars Trilogy\"\ninterface Character {\n    \"The id of the character.\"\n    id: String!\n    \"The name of the character.\"\n    name: String\n    \"The friends of the character, or an empty list if they have none.\"\n    friends: [Character]\n    \"Which movies they appear in.\"\n    appearsIn: [Episode]\n    \"All secrets about their past.\"\n    secretBackstory: String\n}\n\n\"A humanoid creature in the Star Wars universe.\"\ntype Human implements Character {\n    \"The id of the human.\"\n    id: String!\n    \"The name of the human.\"\n    name: String\n    \"The friends of the human, or an empty list if they have none.\"\n    friends: [Character]\n    \"Which movies they appear in.\"\n    appearsIn: [Episode]\n    \"The home planet of the human, or null if unknown.\"\n    homePlanet: String\n    \"Where are they from and how they came to be who they are.\"\n    secretBackstory: String\n}\n\n\"A mechanical creature in the Star Wars universe.\"\ntype Droid implements Character {\n    \"The id of the droid.\"\n    id: String!\n    \"The name of the droid.\"\n    name: String\n    \"The friends of the droid, or an empty list if they have none.\"\n    friends: [Character]\n    \"Which movies they appear in.\"\n    appearsIn: [Episode]\n    \"Construction date and the name of the designer.\"\n    secretBackstory: String\n    \"The primary function of the droid.\"\n    primaryFunction: String\n}\n\nenum Episode {\n    \"Released in 1977.\"\n    NEWHOPE,\n    \"Released in 1980.\"\n    EMPIRE,\n    \"Released in 1983.\"\n    JEDI\n}\n"
  },
  {
    "path": "tests/Functional/starWarsData.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional;\n\nfunction luke()\n{\n    return [\n        'type'       => 'Human',\n        'id'         => '1000',\n        'name'       => 'Luke Skywalker',\n        'friends'    => ['1002', '1003', '2000', '2001'],\n        'appearsIn'  => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n        'homePlanet' => 'Tatooine',\n    ];\n}\n\nfunction vader()\n{\n    return [\n        'type'       => 'Human',\n        'id'         => '1001',\n        'name'       => 'Darth Vader',\n        'friends'    => ['1004'],\n        'appearsIn'  => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n        'homePlanet' => 'Tatooine',\n    ];\n}\n\nfunction han()\n{\n    return [\n        'type'      => 'Human',\n        'id'        => '1002',\n        'name'      => 'Han Solo',\n        'friends'   => ['1000', '1003', '2001'],\n        'appearsIn' => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n    ];\n}\n\nfunction leia()\n{\n    return [\n        'type'       => 'Human',\n        'id'         => '1003',\n        'name'       => 'Leia Organa',\n        'friends'    => ['1000', '1002', '2000', '2001'],\n        'appearsIn'  => ['NEWHOPE', 'EMPIRE', 'JEDI'],\n        'homePlanet' => 'Alderaan',\n    ];\n}\n\nfunction tarkin()\n{\n    return [\n        'type'      => 'Human',\n        'id'        => '1004',\n        'name'      => 'Wilhuff Tarkin',\n        'friends'   => ['1001'],\n        'appearsIn' => ['NEWHOPE'],\n    ];\n}\n\nfunction humanData()\n{\n    return [\n        '1000' => luke(),\n        '1001' => vader(),\n        '1002' => han(),\n        '1003' => leia(),\n        '1004' => tarkin(),\n    ];\n}\n\nfunction threepio()\n{\n    return [\n        'type'            => 'Droid',\n        'id'              => '2000',\n        'name'            => 'C-3PO',\n        'friends'         => ['1000', '1002', '1003', '2001'],\n        'appearsIn'       => [4, 5, 6],\n        'primaryFunction' => 'Protocol',\n    ];\n}\n\nfunction artoo()\n{\n    return [\n        'type'            => 'Droid',\n        'id'              => '2001',\n        'name'            => 'R2-D2',\n        'friends'         => ['1000', '1002', '1003'],\n        'appearsIn'       => [4, 5, 6],\n        'primaryFunction' => 'Astromech',\n    ];\n}\n\nfunction droidData()\n{\n    return [\n        '2000' => threepio(),\n        '2001' => artoo(),\n    ];\n}\n\nfunction getCharacter($id)\n{\n    return getHuman($id) ?? getDroid($id) ?? null;\n}\n\nfunction getFriends($character)\n{\n    return array_map(function ($id) {\n        return getCharacter($id);\n    }, $character['friends']);\n}\n\nfunction getHero($episode)\n{\n    if ($episode === 'EMPIRE') {\n        return luke();\n    }\n\n    return artoo();\n}\n\nfunction getHuman($id)\n{\n    return humanData()[$id] ?? null;\n}\n\nfunction getDroid($id)\n{\n    return droidData()[$id] ?? null;\n}\n"
  },
  {
    "path": "tests/Functional/starWarsSchema.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Functional;\n\nuse function Digia\\GraphQL\\buildSchema;\nuse function Digia\\GraphQL\\Test\\readFileContents;\n\nfunction starWarsSchema()\n{\n    $source = readFileContents(__DIR__ . '/starWars.graphqls');\n\n    /** @noinspection PhpUnhandledExceptionInspection */\n    return buildSchema($source, [\n        'Query'     => [\n            'hero'  => function ($value, $arguments) {\n                return getHero($arguments['episode'] ?? null);\n            },\n            'human' => function ($value, $arguments) {\n                return getHuman($arguments['id']);\n            },\n            'droid' => function ($value, $arguments) {\n                return getDroid($arguments['id']);\n            },\n        ],\n        'Human'     => [\n            'friends'         => function ($human) {\n                return getFriends($human);\n            },\n            'secretBackstory' => function () {\n                throw new \\Exception('secretBackstory is secret.');\n            },\n        ],\n        'Droid'     => [\n            'friends'         => function ($droid) {\n                return getFriends($droid);\n            },\n            'secretBackstory' => function () {\n                throw new \\Exception('secretBackstory is secret.');\n            },\n        ],\n        'Character' => [\n            '__resolveType' => function ($character) {\n                return $character['type'];\n            },\n        ],\n    ]);\n}\n"
  },
  {
    "path": "tests/TestCase.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test;\n\nuse Digia\\GraphQL\\Schema\\Schema;\nuse PHPUnit\\Framework\\TestCase as BaseTestCase;\nuse function Digia\\GraphQL\\execute;\nuse function Digia\\GraphQL\\Language\\dedent;\nuse function Digia\\GraphQL\\parse;\n\nclass TestCase extends BaseTestCase\n{\n    /**\n     * @noinspection PhpDocMissingThrowsInspection\n     *\n     * @param Schema      $schema\n     * @param string      $query\n     * @param array       $expected\n     * @param mixed       $rootValue\n     * @param mixed       $contextValue\n     * @param array       $variableValues\n     * @param string|null $operationName\n     */\n    protected function assertQueryResultWithSchema(\n        Schema $schema,\n        string $query,\n        array $expected,\n        $rootValue = null,\n        $contextValue = null,\n        array $variableValues = [],\n        ?string $operationName = null\n    ) {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $result = execute($schema, parse(dedent($query)), $rootValue, $contextValue, $variableValues, $operationName);\n\n        $this->assertEquals($expected, $result->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Error/GraphQLExceptionTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Error;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Test\\TestCase;\n\nclass GraphQLExceptionTest extends TestCase\n{\n    public function testHasLocations()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $exception = new GraphQLException(\n            'This is an exception.',\n            null,\n            new Source('qeury { hello }'),\n            [0, 5],\n            ['some', 'path']\n        );\n\n        $this->assertTrue($exception->hasLocations());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $exception = new GraphQLException(\n            'This is an exception.',\n            null,\n            null,\n            null,\n            ['some', 'path']\n        );\n\n        $this->assertFalse($exception->hasLocations());\n    }\n\n    public function testToArray()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $exception = new GraphQLException(\n            'This is an exception.',\n            null,\n            new Source('qeury { hello }'),\n            [0, 5],\n            ['some', 'path']\n        );\n\n        $this->assertEquals([\n            'message'   => 'This is an exception.',\n            'locations' => [\n                ['line' => 1, 'column' => 1],\n                ['line' => 1, 'column' => 6],\n            ],\n            'path'      => ['some', 'path'],\n        ], $exception->toArray());\n    }\n\n    public function testToArrayWithExtensions()\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $exception = new GraphQLException(\n            'This is an exception.',\n            null,\n            new Source('qeury { hello }'),\n            [0, 5],\n            ['some', 'path'],\n            ['code' => 'SOME_ERROR_CODE']\n        );\n\n        $this->assertEquals([\n            'message'    => 'This is an exception.',\n            'locations'  => [\n                ['line' => 1, 'column' => 1],\n                ['line' => 1, 'column' => 6],\n            ],\n            'path'       => ['some', 'path'],\n            'extensions' => ['code' => 'SOME_ERROR_CODE'],\n        ], $exception->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Error/Handler/ErrorHandlerTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Error\\Handler;\n\nuse Digia\\GraphQL\\Error\\Handler\\AbstractErrorMiddleware;\nuse Digia\\GraphQL\\Error\\Handler\\ErrorHandler;\nuse Digia\\GraphQL\\Execution\\ExecutionContext;\nuse Digia\\GraphQL\\Execution\\ExecutionException;\nuse Digia\\GraphQL\\Test\\TestCase;\n\nclass ErrorHandlerTest extends TestCase\n{\n    public function testHandle()\n    {\n        $middleware   = new WasInvokedMiddleware();\n        $errorHandler = new ErrorHandler([$middleware]);\n        $exception    = new ExecutionException('This is an exception.');\n        $context      = $this->mockContext();\n\n        $errorHandler->handleExecutionError($exception, $context);\n\n        $this->assertTrue($middleware->wasInvoked());\n    }\n\n    public function testMiddleware()\n    {\n        $result = [];\n\n        $middlewareA    = new LoggerMiddleware(function () use (&$result) {\n            $result[] = 'Middleware A invoked';\n        });\n        $middlewareB    = new LoggerMiddleware(function () use (&$result) {\n            $result[] = 'Middleware B invoked';\n        });\n        $middlewareC    = new LoggerMiddleware(function () use (&$result) {\n            $result[] = 'Middleware C invoked';\n        });\n        $noopMiddleware = new NoopMiddleware();\n        $errorHandler   = new ErrorHandler([$middlewareA, $middlewareB, $noopMiddleware, $middlewareC]);\n        $exception      = new ExecutionException('This is an exception.');\n        $context        = $this->mockContext();\n\n        $errorHandler->handleExecutionError($exception, $context);\n\n        $this->assertSame([\n            'Middleware A invoked',\n            'Middleware B invoked',\n        ], $result);\n    }\n\n    /**\n     * @return ExecutionContext|\\PHPUnit_Framework_MockObject_MockObject\n     */\n    private function mockContext()\n    {\n        return $this->getMockBuilder(ExecutionContext::class)\n            ->disableOriginalConstructor()\n            ->getMock();\n    }\n}\n\nclass WasInvokedMiddleware extends AbstractErrorMiddleware\n{\n    private $wasInvoked = false;\n\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context, callable $next)\n    {\n        $this->wasInvoked = true;\n\n        return $next($exception, $context);\n    }\n\n    public function wasInvoked(): bool\n    {\n        return $this->wasInvoked;\n    }\n}\n\nclass LoggerMiddleware extends AbstractErrorMiddleware\n{\n    private $logCallback;\n\n    public function __construct($logCallback)\n    {\n        $this->logCallback = $logCallback;\n    }\n\n    public function handleExecutionError(ExecutionException $exception, ExecutionContext $context, callable $next)\n    {\n        \\call_user_func($this->logCallback, $exception, $context);\n\n        return $next($exception, $context);\n    }\n}\n\nclass NoopMiddleware extends AbstractErrorMiddleware\n{\n}\n"
  },
  {
    "path": "tests/Unit/Execution/ExecutionResultTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Execution;\n\nuse Digia\\GraphQL\\Error\\GraphQLException;\nuse Digia\\GraphQL\\Execution\\ExecutionResult;\nuse Digia\\GraphQL\\Test\\TestCase;\n\nclass ExecutionResultTest extends TestCase\n{\n\n    public function testBasics(): void\n    {\n        // Start with null data and no errors\n        $executionResult = new ExecutionResult(null, []);\n\n        $this->assertNull($executionResult->getData());\n        $this->assertEmpty($executionResult->getErrors());\n        $this->assertSame(['data' => null], $executionResult->toArray());\n\n        // Start with data and no errors\n        $executionResult = new ExecutionResult(['foo' => 'bar'], []);\n\n        $this->assertEquals(['foo' => 'bar'], $executionResult->getData());\n        $this->assertEmpty($executionResult->getErrors());\n        $this->assertSame(['data' => ['foo' => 'bar']], $executionResult->toArray());\n\n        // Start with data and an error\n        $executionResult = new ExecutionResult(['foo' => 'bar'], [new GraphQLException('Error')]);\n\n        $this->assertEquals(['foo' => 'bar'], $executionResult->getData());\n        $this->assertCount(1, $executionResult->getErrors());\n        $this->assertSame([\n            'errors' => [\n                [\n                    'message'   => 'Error',\n                    'locations' => null,\n                ]\n            ],\n            'data'   => ['foo' => 'bar'],\n        ], $executionResult->toArray());\n\n        // Add another error\n        $executionResult->addError(new GraphQLException('Another error'));\n        $this->assertCount(2, $executionResult->getErrors());\n        $this->assertSame([\n            'errors' => [\n                [\n                    'message'   => 'Error',\n                    'locations' => null\n                ],\n                [\n                    'message'   => 'Another error',\n                    'locations' => null\n                ]\n            ],\n            'data'   => ['foo' => 'bar'],\n        ], $executionResult->toArray());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Language/BlockStringValueTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Language;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Language\\blockStringValue;\n\n/**\n * Class BlockStringValueTest\n * @package Digia\\GraphQL\\Test\\Unit\\Language\n */\nclass BlockStringValueTest extends TestCase\n{\n\n    public function testRemovesUniformIndentation(): void\n    {\n        $rawStringLines = [\n            '',\n            '    Hello',\n            '      World!',\n            '',\n            '    Yours,',\n            '      GraphQL.'\n        ];\n\n        $expectedBlockStringLines = [\n            'Hello',\n            '  World!',\n            '',\n            'Yours,',\n            '  GraphQL.'\n        ];\n\n        $this->assertBlockStringEquals($expectedBlockStringLines, $rawStringLines);\n    }\n\n    public function testRemovesEmptyLeadingAndTrailingLines(): void\n    {\n        $rawStringLines = [\n            '',\n            '',\n            '    Hello',\n            '      World!',\n            '',\n            '    Yours,',\n            '      GraphQL.',\n            '',\n            '',\n        ];\n\n        $expectedBlockStringLines = [\n            'Hello',\n            '  World!',\n            '',\n            'Yours,',\n            '  GraphQL.'\n        ];\n\n        $this->assertBlockStringEquals($expectedBlockStringLines, $rawStringLines);\n    }\n\n    public function testRemovesBlankLeadingAndTrailingLines(): void\n    {\n        $rawStringLines = [\n            '  ',\n            '        ',\n            '    Hello',\n            '      World!',\n            '',\n            '    Yours,',\n            '      GraphQL.',\n            '        ',\n            '  ',\n        ];\n\n        $expectedBlockStringLines = [\n            'Hello',\n            '  World!',\n            '',\n            'Yours,',\n            '  GraphQL.'\n        ];\n\n        $this->assertBlockStringEquals($expectedBlockStringLines, $rawStringLines);\n    }\n\n    public function testRetainsIndentationFromFirstLine(): void\n    {\n        $rawStringLines = [\n            '    Hello',\n            '      World!',\n            '',\n            '    Yours,',\n            '      GraphQL.',\n            '        ',\n            '  ',\n        ];\n\n        $expectedBlockStringLines = [\n            '    Hello',\n            '  World!',\n            '',\n            'Yours,',\n            '  GraphQL.'\n        ];\n\n        $this->assertBlockStringEquals($expectedBlockStringLines, $rawStringLines);\n    }\n\n    public function testDoesNotAlterTrailingSpaces(): void\n    {\n        $rawStringLines = [\n            '               ',\n            '    Hello,     ',\n            '      World!   ',\n            '               ',\n            '    Yours,     ',\n            '      GraphQL. ',\n            '               ',\n        ];\n\n        $expectedBlockStringLines = [\n            'Hello,     ',\n            '  World!   ',\n            '           ',\n            'Yours,     ',\n            '  GraphQL. ',\n        ];\n\n        $this->assertBlockStringEquals($expectedBlockStringLines, $rawStringLines);\n    }\n\n    /**\n     * @param array $expectedBlockStringLines\n     * @param array $rawStringLines\n     */\n    private function assertBlockStringEquals(array $expectedBlockStringLines, array $rawStringLines): void\n    {\n        $actualBlockString = blockStringValue(implode(\"\\n\", $rawStringLines));\n\n        $this->assertSame(implode(\"\\n\", $expectedBlockStringLines), $actualBlockString);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Language/LexerTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Language;\n\nuse Digia\\GraphQL\\Language\\SyntaxErrorException;\nuse Digia\\GraphQL\\Language\\Lexer;\nuse Digia\\GraphQL\\Language\\LexerInterface;\nuse Digia\\GraphQL\\Language\\Source;\nuse Digia\\GraphQL\\Language\\SourceLocation;\nuse Digia\\GraphQL\\Language\\Token;\nuse Digia\\GraphQL\\Language\\TokenKindEnum;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Language\\dedent;\n\n/**\n * Class LexerTest\n * @package Digia\\GraphQL\\Test\\Unit\\Language\n */\nclass LexerTest extends TestCase\n{\n    // disallows uncommon control characters\n\n    public function testDisallowsUncommonControlCharacters(): void\n    {\n        $this->assertSyntaxError(\"\\u{0007}\", 'Cannot contain the invalid character \"\\u0007\".', [1, 1]);\n    }\n\n    // accepts BOM header\n\n    public function testAcceptsBomCharacter(): void\n    {\n        $this->assertLexerTokenPropertiesEqual(\"\\u{FEFF} foo\", TokenKindEnum::NAME, [2, 5], 'foo');\n    }\n\n    // records line and column\n\n    public function testRecordsLineAndNumber(): void\n    {\n        $token = $this->getLexer(\"\\n \\r\\n \\r  foo\\n\")->advance();\n\n        $this->assertEquals(TokenKindEnum::NAME, $token->getKind());\n        $this->assertEquals(8, $token->getStart());\n        $this->assertEquals(11, $token->getEnd());\n        $this->assertEquals(4, $token->getLine());\n        $this->assertEquals(3, $token->getColumn());\n        $this->assertEquals('foo', $token->getValue());\n    }\n\n    // can be JSON.stringified or util.inspected\n\n    public function testCanBeJsonSerialized(): void\n    {\n        $token = $this->getLexer('foo')->advance();\n\n        $this->assertJsonStringEqualsJsonString(\\json_encode([\n            'kind'   => 'Name',\n            'value'  => 'foo',\n            'line'   => 1,\n            'column' => 1,\n        ]), $token->toJSON());\n    }\n\n    // skips whitespace and comments\n\n    public function testSkipsWhitespaceAndComments(): void\n    {\n        $whitespaceString = <<<EOD\n\n    foo\n    \n    \n    \nEOD;\n\n        $commentedString = <<<EOD\n#comment\nfoo#comment\nEOD;\n\n        $this->assertLexerTokenPropertiesEqual($whitespaceString, TokenKindEnum::NAME, [5, 8], 'foo');\n\n        $this->assertLexerTokenPropertiesEqual($commentedString, TokenKindEnum::NAME, [9, 12], 'foo');\n\n        $this->assertLexerTokenPropertiesEqual(',,,foo,,,', TokenKindEnum::NAME, [3, 6], 'foo');\n    }\n\n    // errors respect whitespace\n\n    public function testErrorsRespectWhitespace(): void\n    {\n        $whitespaceErrorString = <<<EOD\n\n\n    ?\n\nEOD;\n\n        try {\n            $this->getLexer($whitespaceErrorString)->advance();\n        } catch (SyntaxErrorException $e) {\n            $this->assertEquals([['line' => 3, 'column' => 5]], $e->getLocationsAsArray());\n        }\n    }\n\n    // updates line numbers in error for file context\n\n    public function testUpdatesLineNumbersInErrorForFileContext()\n    {\n        $caughtError = null;\n\n        try {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $source = new Source(\"\\n\\n     ?\\n\\n\", 'foo.php', new SourceLocation(11, 12));\n            $this->getLexer($source)->advance();\n        } catch (SyntaxErrorException $e) {\n            $caughtError = $e;\n        }\n\n        $this->assertEquals(\n            \"Syntax Error: Cannot parse the unexpected character \\\"?\\\".\\n\" .\n            \"\\n\" .\n            \"foo.php (13:6)\\n\" .\n            \"12: \\n\" .\n            \"13:      ?\\n\" .\n            \"         ^\\n\" .\n            \"14: \\n\",\n            (string)$caughtError\n        );\n    }\n\n    // updates column numbers in error for file context\n\n    public function testUpdatesColumnNumbersInErrorForFileContext()\n    {\n        $caughtError = null;\n\n        try {\n            /** @noinspection PhpUnhandledExceptionInspection */\n            $source = new Source('?', 'foo.php', new SourceLocation(1, 5));\n            $this->getLexer($source)->advance();\n        } catch (SyntaxErrorException $e) {\n            $caughtError = $e;\n        }\n\n        $this->assertEquals(\n            \"Syntax Error: Cannot parse the unexpected character \\\"?\\\".\\n\" .\n            \"\\n\" .\n            \"foo.php (1:5)\\n\" .\n            \"1:     ?\\n\" .\n            \"       ^\\n\",\n            (string)$caughtError\n        );\n    }\n\n    // lexes strings\n\n    public function testLexesStrings(): void\n    {\n        $this->assertLexerTokenPropertiesEqual('\"simple\"', TokenKindEnum::STRING, [0, 8], 'simple');\n\n        $this->assertLexerTokenPropertiesEqual('\" white space \"', TokenKindEnum::STRING, [0, 15], ' white space ');\n\n        $this->assertLexerTokenPropertiesEqual('\"quote \\\\\"\"', TokenKindEnum::STRING, [0, 10], 'quote \"');\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"escaped \\\\n\\\\r\\\\b\\\\t\\\\f\"',\n            TokenKindEnum::STRING,\n            [0, 20],\n            'escaped \\n\\r\\b\\t\\f'\n        );\n\n        $this->assertLexerTokenPropertiesEqual('\"slashes \\\\\\\\ \\\\/\"', TokenKindEnum::STRING, [0, 15], 'slashes \\\\ /');\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"unicode \\\\u1234\\\\u5678\\\\u90AB\\\\uCDEF\"',\n            TokenKindEnum::STRING,\n            [0, 34],\n            'unicode \\u1234\\u5678\\u90AB\\uCDEF'\n        );\n    }\n\n    // lex reports useful string errors\n\n    public function testLexReportsUsefulStringErrors()\n    {\n        $this->assertSyntaxError('\"', 'Unterminated string.', [1, 2]);\n\n        $this->assertSyntaxError('\"no end quote', 'Unterminated string.', [1, 14]);\n\n        $this->assertSyntaxError(\n            \"'single quotes'\",\n            'Unexpected single quote character (\\'), did you mean to use a double quote (\")?',\n            [1, 1]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"contains unescaped \\u{0007} control char\\\"\",\n            'Invalid character within String: \"\\\\u0007\".',\n            [1, 21]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"null-byte is not \\u{0000} end of file\\\"\",\n            'Invalid character within String: <EOF>.',\n            [1, 19]\n        );\n\n        $this->assertSyntaxError(\"\\\"multi\\nline\\\"\", 'Unterminated string.', [1, 7]);\n\n        $this->assertSyntaxError(\"\\\"multi\\rline\\\"\", 'Unterminated string.', [1, 7]);\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\z esc\\\"\",\n            'Invalid character escape sequence: \\\\z.',\n            [1, 7]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\x esc\\\"\",\n            'Invalid character escape sequence: \\\\x.',\n            [1, 7]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\u1 esc\\\"\",\n            'Invalid character escape sequence: \\\\u1 es.',\n            [1, 7]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\u0XX1 esc\\\"\",\n            'Invalid character escape sequence: \\\\u0XX1.',\n            [1, 7]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\uXXXX esc\\\"\",\n            'Invalid character escape sequence: \\\\uXXXX.',\n            [1, 7]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\uFXXX esc\\\"\",\n            'Invalid character escape sequence: \\\\uFXXX.',\n            [1, 7]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"bad \\\\uXXXF esc\\\"\",\n            'Invalid character escape sequence: \\\\uXXXF.',\n            [1, 7]\n        );\n    }\n\n    // lexes block strings\n\n    public function testLexesBlockStrings(): void\n    {\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"simple\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 12],\n            'simple'\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\" white space \"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 19],\n            ' white space '\n        );\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"contains \" quote\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 22],\n            'contains \" quote'\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"contains \\\\\"\"\" triplequote\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 31],\n            'contains \"\"\" triplequote'\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"' . \"multi\\nline\" . '\"\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 16],\n            \"multi\\nline\"\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"' . \"multi\\rline\\r\\nnormalized\" . '\"\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 28],\n            \"multi\\nline\\nnormalized\"\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"' . \"unescaped \\\\n\\\\r\\\\b\\\\t\\\\f\\\\u1234\" . '\"\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 32],\n            'unescaped \\\\n\\\\r\\\\b\\\\t\\\\f\\\\u1234'\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            '\"\"\"' . \"slashes \\\\\\\\ \\\\/\" . '\"\"\"\"',\n            TokenKindEnum::BLOCK_STRING,\n            [0, 19],\n            \"slashes \\\\\\\\ \\\\/\"\n        );\n\n        $this->assertLexerTokenPropertiesEqual(\n            dedent('\n            \"\"\"\n            \n            spans\n              multiple\n                lines\n                \n            \"\"\"\n            '),\n            TokenKindEnum::BLOCK_STRING,\n            [0, 40],\n            \"spans\\n  multiple\\n    lines\"\n        );\n    }\n\n    // lex reports useful block string errors\n\n    public function testLexReportsUsefulBlockStringErrors()\n    {\n        $this->assertSyntaxError('\"\"\"', 'Unterminated string.', [1, 4]);\n\n        $this->assertSyntaxError('\"\"\"no end quote', 'Unterminated string.', [1, 16]);\n\n        $this->assertSyntaxError(\n            \"\\\"\\\"\\\"contains unescaped \\u{0007} control char\\\"\\\"\\\"\",\n            'Invalid character within String: \"\\\\u0007\".',\n            [1, 23]\n        );\n\n        $this->assertSyntaxError(\n            \"\\\"\\\"\\\"null-byte is not \\u{0000} end of file\\\"\\\"\\\"\",\n            'Invalid character within String: <EOF>.',\n            [1, 21]\n        );\n    }\n\n    // lexes numbers\n\n    public function testLexesNumbers()\n    {\n        $this->assertLexerTokenPropertiesEqual('4', TokenKindEnum::INT, [0, 1], '4');\n\n        $this->assertLexerTokenPropertiesEqual('4.123', TokenKindEnum::FLOAT, [0, 5], '4.123');\n\n        $this->assertLexerTokenPropertiesEqual('-4', TokenKindEnum::INT, [0, 2], '-4');\n\n        $this->assertLexerTokenPropertiesEqual('9', TokenKindEnum::INT, [0, 1], '9');\n\n        $this->assertLexerTokenPropertiesEqual('0', TokenKindEnum::INT, [0, 1], '0');\n\n        $this->assertLexerTokenPropertiesEqual('-4.123', TokenKindEnum::FLOAT, [0, 6], '-4.123');\n\n        $this->assertLexerTokenPropertiesEqual('0.123', TokenKindEnum::FLOAT, [0, 5], '0.123');\n\n        $this->assertLexerTokenPropertiesEqual('123e4', TokenKindEnum::FLOAT, [0, 5], '123e4');\n\n        $this->assertLexerTokenPropertiesEqual('123E4', TokenKindEnum::FLOAT, [0, 5], '123E4');\n\n        $this->assertLexerTokenPropertiesEqual('123e-4', TokenKindEnum::FLOAT, [0, 6], '123e-4');\n\n        $this->assertLexerTokenPropertiesEqual('123E-4', TokenKindEnum::FLOAT, [0, 6], '123E-4');\n\n        $this->assertLexerTokenPropertiesEqual('123e+4', TokenKindEnum::FLOAT, [0, 6], '123e+4');\n\n        $this->assertLexerTokenPropertiesEqual('-1.123e4', TokenKindEnum::FLOAT, [0, 8], '-1.123e4');\n\n        $this->assertLexerTokenPropertiesEqual('-1.123E4', TokenKindEnum::FLOAT, [0, 8], '-1.123E4');\n\n        $this->assertLexerTokenPropertiesEqual('-1.123e+4', TokenKindEnum::FLOAT, [0, 9], '-1.123e+4');\n\n        $this->assertLexerTokenPropertiesEqual('-1.123e4567', TokenKindEnum::FLOAT, [0, 11], '-1.123e4567');\n    }\n\n    // lex reports useful number errors\n\n    public function testLexReportsUsefulNumberErrors()\n    {\n        $this->assertSyntaxError('00', 'Invalid number, unexpected digit after 0: \"0\".', [1, 2]);\n\n        $this->assertSyntaxError('+1', 'Cannot parse the unexpected character \"+\".', [1, 1]);\n\n        $this->assertSyntaxError('1.', 'Invalid number, expected digit but got: <EOF>.', [1, 3]);\n\n        $this->assertSyntaxError('1.e1', 'Invalid number, expected digit but got: \"e\".', [1, 3]);\n\n        $this->assertSyntaxError('.123', 'Cannot parse the unexpected character \".\".', [1, 1]);\n\n        $this->assertSyntaxError('1.A', 'Invalid number, expected digit but got: \"A\".', [1, 3]);\n\n        $this->assertSyntaxError('-A', 'Invalid number, expected digit but got: \"A\".', [1, 2]);\n\n        $this->assertSyntaxError('1.0e', 'Invalid number, expected digit but got: <EOF>.', [1, 5]);\n\n        $this->assertSyntaxError('1.0eA', 'Invalid number, expected digit but got: \"A\".', [1, 5]);\n    }\n\n    // lexes punctuation\n\n    public function testLexesPunctuation()\n    {\n        $this->assertLexerTokenPropertiesEqual('!', TokenKindEnum::BANG, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('$', TokenKindEnum::DOLLAR, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('(', TokenKindEnum::PAREN_L, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual(')', TokenKindEnum::PAREN_R, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('...', TokenKindEnum::SPREAD, [0, 3], null);\n        $this->assertLexerTokenPropertiesEqual(':', TokenKindEnum::COLON, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('=', TokenKindEnum::EQUALS, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('@', TokenKindEnum::AT, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('[', TokenKindEnum::BRACKET_L, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual(']', TokenKindEnum::BRACKET_R, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('{', TokenKindEnum::BRACE_L, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('|', TokenKindEnum::PIPE, [0, 1], null);\n        $this->assertLexerTokenPropertiesEqual('}', TokenKindEnum::BRACE_R, [0, 1], null);\n    }\n\n    // lex reports useful unknown character error\n\n    public function testLexReportsUsefulUnknownCharacterError()\n    {\n        $this->assertSyntaxError('..', 'Cannot parse the unexpected character \".\".', [1, 1]);\n\n        $this->assertSyntaxError('?', 'Cannot parse the unexpected character \"?\".', [1, 1]);\n\n        $this->assertSyntaxError(\"\\u{203B}\", 'Cannot parse the unexpected character \"\\\\u203b\".', [1, 1]);\n\n        $this->assertSyntaxError(\"\\u{200b}\", 'Cannot parse the unexpected character \"\\\\u200b\".', [1, 1]);\n    }\n\n    // lex reports useful information for dashes in names\n\n    public function testLexReportsUsefulInformationForDashesInNames()\n    {\n        $lexer      = $this->getLexer('a-b');\n        $firstToken = $lexer->advance();\n\n        $this->assertTokenPropertiesEqual($firstToken, TokenKindEnum::NAME, [0, 1], 'a');\n\n        $caughtError = null;\n\n        try {\n            $lexer->advance();\n        } catch (SyntaxErrorException $e) {\n            $caughtError = $e;\n        }\n\n        $this->assertEquals('Syntax Error: Invalid number, expected digit but got: \"b\".', $caughtError->getMessage());\n        $this->assertEquals([['line' => 1, 'column' => 3]], $caughtError->getLocationsAsArray());\n    }\n\n    // produces double linked list of tokens, including comments\n\n    public function testProducesDoubleLinkedListOfTokensIncludingComments()\n    {\n        $lexer = $this->getLexer(dedent('\n        {\n          #comment\n          field\n        }\n        '));\n\n        $startToken = $lexer->getToken();\n        $endToken   = null;\n\n        do {\n            $endToken = $lexer->advance();\n            // Lexer advances over ignored comment tokens to make writing parsers\n            // easier, but will include them in the linked list result.\n            $this->assertNotEquals(TokenKindEnum::COMMENT, $endToken->getKind());\n        } while ($endToken->getKind() !== TokenKindEnum::EOF);\n\n        $this->assertNull($startToken->getPrev());\n        $this->assertNull($endToken->getNext());\n\n        $tokens = [];\n\n        for ($token = $startToken; null !== $token; $token = $token->getNext()) {\n            if (!empty($tokens)) {\n                // Tokens are double-linked, prev should point to last seen token.\n                $this->assertEquals($tokens[\\count($tokens) - 1], $token->getPrev());\n            }\n\n            $tokens[] = $token;\n        }\n\n        $this->assertEquals([\n            '<SOF>',\n            '{',\n            'Comment',\n            'Name',\n            '}',\n            '<EOF>',\n        ], \\array_map(function (Token $token) {\n            return $token->getKind();\n        }, $tokens));\n    }\n\n    /**\n     * @param string $source\n     * @param string $expectedExceptionMessage\n     * @param array  $position\n     */\n    private function assertSyntaxError(string $source, string $expectedExceptionMessage, array $position): void\n    {\n        try {\n            $this->getLexer($source)->advance();\n\n            $this->fail('Expected an exception to be thrown');\n        } catch (SyntaxErrorException $e) {\n            $this->assertEquals('Syntax Error: ' . $expectedExceptionMessage, $e->getMessage());\n            $this->assertEquals([['line' => $position[0], 'column' => $position[1]]], $e->getLocationsAsArray());\n        }\n    }\n\n    /**\n     * @param string $source\n     * @param string $kind\n     * @param array  $location\n     * @param mixed  $value\n     */\n    private function assertLexerTokenPropertiesEqual(string $source, string $kind, array $location, $value): void\n    {\n        $token = $this->getLexer($source)->advance();\n\n        $this->assertTokenPropertiesEqual($token, $kind, $location, $value);\n    }\n\n    /**\n     * @param Token  $token\n     * @param string $kind\n     * @param array  $location\n     * @param mixed  $value\n     */\n    private function assertTokenPropertiesEqual(Token $token, string $kind, array $location, $value): void\n    {\n        $this->assertEquals($kind, $token->getKind());\n        $this->assertEquals($location[0], $token->getStart());\n        $this->assertEquals($location[1], $token->getEnd());\n        $this->assertEquals($value, $token->getValue());\n    }\n\n    /**\n     * @param string|Source $source\n     * @param array         $options\n     * @return LexerInterface\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     */\n    private function getLexer($source, array $options = []): LexerInterface\n    {\n        /** @noinspection PhpUnhandledExceptionInspection */\n        return new Lexer($source instanceof Source ? $source : new Source($source), $options);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Language/NodeBuilderTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Language;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\Location;\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\BooleanValueNode;\nuse Digia\\GraphQL\\Language\\Node\\DirectiveNode;\nuse Digia\\GraphQL\\Language\\Node\\DocumentNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FieldNode;\nuse Digia\\GraphQL\\Language\\Node\\FloatValueNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\FragmentSpreadNode;\nuse Digia\\GraphQL\\Language\\Node\\InlineFragmentNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\InputValueDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\InterfaceTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NamedTypeNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\OperationTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\ScalarTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\SchemaDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\SelectionSetNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\UnionTypeExtensionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableDefinitionNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Language\\NodeBuilderInterface;\nuse Digia\\GraphQL\\Test\\TestCase;\n\nclass NodeBuilderTest extends TestCase\n{\n    /**\n     * @var NodeBuilderInterface\n     */\n    private $builder;\n\n    protected function setUp()\n    {\n        $this->builder = GraphQL::make(NodeBuilderInterface::class);\n    }\n\n    public function testBuildArgumentNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::ARGUMENT,\n            'name'  => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someArgument',\n            ],\n            'value' => [\n                'kind'  => NodeKindEnum::STRING,\n                'value' => 'someValue',\n            ],\n        ]);\n\n        $this->assertInstanceOf(ArgumentNode::class, $node);\n    }\n\n    public function testBuildBooleanValueNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::BOOLEAN,\n            'value' => true,\n        ]);\n\n        $this->assertInstanceOf(BooleanValueNode::class, $node);\n    }\n\n    public function testBuildDirectiveNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::DIRECTIVE,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someDirective',\n            ],\n        ]);\n\n        $this->assertInstanceOf(DirectiveNode::class, $node);\n    }\n\n    public function testBuildDocumentNode()\n    {\n        $node = $this->builder->build([\n            'kind'        => NodeKindEnum::DOCUMENT,\n            'definitions' => [\n                'query' => [\n                    'kind'   => NodeKindEnum::OBJECT,\n                    'name'   => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'value' => 'Query',\n                    ],\n                    'fields' => [\n                        [\n                            'kind' => NodeKindEnum::FIELD,\n                            'name' => [\n                                'kind'  => NodeKindEnum::NAME,\n                                'value' => 'queryField',\n                            ],\n                            'type' => [\n                                'kind' => NodeKindEnum::NAMED_TYPE,\n                                'name' => [\n                                    'kind'  => NodeKindEnum::NAME,\n                                    'value' => 'String',\n                                ],\n                            ],\n                        ],\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(DocumentNode::class, $node);\n    }\n\n    public function testBuildEnumValueNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::ENUM,\n            'value' => [\n                'kind'  => NodeKindEnum::STRING,\n                'value' => 'someValue',\n            ],\n        ]);\n\n        $this->assertInstanceOf(EnumValueNode::class, $node);\n    }\n\n    public function testBuildEnumTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind'   => NodeKindEnum::ENUM_TYPE_DEFINITION,\n            'name'   => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someEnum',\n            ],\n            'values' => [\n                [\n                    'kind'  => NodeKindEnum::ENUM,\n                    'value' => [\n                        'kind'  => NodeKindEnum::STRING,\n                        'value' => 'someValue',\n                    ],\n                ],\n                [\n                    'kind'  => NodeKindEnum::ENUM,\n                    'value' => [\n                        'kind'  => NodeKindEnum::STRING,\n                        'value' => 'someOtherValue',\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(EnumTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildEnumTypeExtensionNode()\n    {\n        $node = $this->builder->build([\n            'kind'   => NodeKindEnum::ENUM_TYPE_EXTENSION,\n            'name'   => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someEnum',\n            ],\n            'values' => [\n                [\n                    'kind'  => NodeKindEnum::ENUM,\n                    'value' => [\n                        'kind'  => NodeKindEnum::STRING,\n                        'value' => 'someOtherValue',\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(EnumTypeExtensionNode::class, $node);\n    }\n\n    public function testBuildFieldDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::FIELD_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someField',\n            ],\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'String',\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(FieldDefinitionNode::class, $node);\n    }\n\n    public function testBuildFieldNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::FIELD,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someField',\n            ],\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'String',\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(FieldNode::class, $node);\n    }\n\n    public function testBuildFloatValueNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::FLOAT,\n            'value' => 0.42,\n        ]);\n\n        $this->assertInstanceOf(FloatValueNode::class, $node);\n    }\n\n    public function testBuildFragmentDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::FRAGMENT_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someFragment',\n            ],\n        ]);\n\n        $this->assertInstanceOf(FragmentDefinitionNode::class, $node);\n    }\n\n    public function testBuildFragmentSpreadNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::FRAGMENT_SPREAD,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someFragment',\n            ],\n        ]);\n\n        $this->assertInstanceOf(FragmentSpreadNode::class, $node);\n    }\n\n    public function testBuildInlineFragmentNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::INLINE_FRAGMENT,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someFragment',\n            ],\n        ]);\n\n        $this->assertInstanceOf(InlineFragmentNode::class, $node);\n    }\n\n    public function testBuildInputObjectTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::INPUT_OBJECT_TYPE_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someInputObject',\n            ],\n        ]);\n\n        $this->assertInstanceOf(InputObjectTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildInputObjectTypeExtensionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::INPUT_OBJECT_TYPE_EXTENSION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someOtherInputObject',\n            ],\n        ]);\n\n        $this->assertInstanceOf(InputObjectTypeExtensionNode::class, $node);\n    }\n\n    public function testBuildInputValueDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::INPUT_VALUE_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someInputValue',\n            ],\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'String',\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(InputValueDefinitionNode::class, $node);\n    }\n\n    public function testBuildInterfaceTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::INTERFACE_TYPE_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someInterface',\n            ],\n        ]);\n\n        $this->assertInstanceOf(InterfaceTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildInterfaceTypeExtensionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::INTERFACE_TYPE_EXTENSION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someOtherInterface',\n            ],\n        ]);\n\n        $this->assertInstanceOf(InterfaceTypeExtensionNode::class, $node);\n    }\n\n    public function testBuildIntValueNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::INT,\n            'value' => 42,\n        ]);\n\n        $this->assertInstanceOf(IntValueNode::class, $node);\n    }\n\n    public function testBuildListTypeNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::LIST_TYPE,\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'String',\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(ListTypeNode::class, $node);\n    }\n\n    public function testBuildNamedTypeNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::NAMED_TYPE,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'String',\n            ],\n        ]);\n\n        $this->assertInstanceOf(NamedTypeNode::class, $node);\n    }\n\n    public function testBuildNameNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::NAME,\n            'value' => 'SomeName',\n        ]);\n\n        $this->assertInstanceOf(NameNode::class, $node);\n    }\n\n    public function testBuildNullValueNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::NULL,\n        ]);\n\n        $this->assertInstanceOf(NullValueNode::class, $node);\n    }\n\n    public function testBuildObjectFieldNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::OBJECT_FIELD,\n            'name'  => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someObjectField',\n            ],\n            'value' => [\n                'kind'  => NodeKindEnum::STRING,\n                'value' => 'someValue',\n            ],\n        ]);\n\n        $this->assertInstanceOf(ObjectFieldNode::class, $node);\n    }\n\n    public function testBuildObjectTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::OBJECT_TYPE_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someObject',\n            ],\n        ]);\n\n        $this->assertInstanceOf(ObjectTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildObjectTypeExtensionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::OBJECT_TYPE_EXTENSION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someOtherObject',\n            ],\n        ]);\n\n        $this->assertInstanceOf(ObjectTypeExtensionNode::class, $node);\n    }\n\n    public function testBuildObjectValueNode()\n    {\n        $node = $this->builder->build([\n            'kind'   => NodeKindEnum::OBJECT,\n            'fields' => [\n                [\n                    'kind' => NodeKindEnum::FIELD,\n                    'name' => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'value' => 'someField',\n                    ],\n                    'type' => [\n                        'kind' => NodeKindEnum::NAMED_TYPE,\n                        'name' => [\n                            'kind'  => NodeKindEnum::NAME,\n                            'value' => 'String',\n                        ],\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(ObjectValueNode::class, $node);\n    }\n\n    public function testBuildOperationDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind'      => NodeKindEnum::OPERATION_DEFINITION,\n            'operation' => 'query',\n            'name'      => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'Query',\n            ],\n        ]);\n\n        $this->assertInstanceOf(OperationDefinitionNode::class, $node);\n    }\n\n    public function testBuildOperationTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind'      => NodeKindEnum::OPERATION_TYPE_DEFINITION,\n            'operation' => 'query',\n            'type'      => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'String',\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(OperationTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildScalarTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::SCALAR_TYPE_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'SomeScalar',\n            ],\n        ]);\n\n        $this->assertInstanceOf(ScalarTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildScalarTypeExtensionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::SCALAR_TYPE_EXTENSION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'SomeOtherScalar',\n            ],\n        ]);\n\n        $this->assertInstanceOf(ScalarTypeExtensionNode::class, $node);\n    }\n\n    public function testBuildSchemaDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind'           => NodeKindEnum::SCHEMA_DEFINITION,\n            'operationTypes' => [\n                [\n                    'kind'      => NodeKindEnum::OPERATION_TYPE_DEFINITION,\n                    'operation' => 'query',\n                    'type'      => [\n                        'kind' => NodeKindEnum::NAMED_TYPE,\n                        'name' => [\n                            'kind'  => NodeKindEnum::NAME,\n                            'value' => 'String',\n                        ],\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(SchemaDefinitionNode::class, $node);\n    }\n\n    public function testBuildSelectionSetNode()\n    {\n        $node = $this->builder->build([\n            'kind'       => NodeKindEnum::SELECTION_SET,\n            'selections' => [\n                [\n                    'kind' => NodeKindEnum::FIELD,\n                    'name' => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'value' => 'someField',\n                    ],\n                    'type' => [\n                        'kind' => NodeKindEnum::NAMED_TYPE,\n                        'name' => [\n                            'kind'  => NodeKindEnum::NAME,\n                            'value' => 'String',\n                        ],\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(SelectionSetNode::class, $node);\n    }\n\n    public function testBuildStringValueNode()\n    {\n        $node = $this->builder->build([\n            'kind'  => NodeKindEnum::STRING,\n            'value' => 'someValue',\n        ]);\n\n        $this->assertInstanceOf(StringValueNode::class, $node);\n    }\n\n    public function testBuildUnionTypeDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::UNION_TYPE_DEFINITION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'SomeUnion',\n            ],\n            'types' => [\n                [\n                    'kind' => NodeKindEnum::NAMED_TYPE,\n                    'name' => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'value' => 'SomeType',\n                    ],\n                ],\n                [\n                    'kind' => NodeKindEnum::NAMED_TYPE,\n                    'name' => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'value' => 'SomeOtherType',\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(UnionTypeDefinitionNode::class, $node);\n    }\n\n    public function testBuildUnionTypeExtensionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::UNION_TYPE_EXTENSION,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'SomeOtherUnion',\n            ],\n            'types' => [\n                [\n                    'kind' => NodeKindEnum::NAMED_TYPE,\n                    'name' => [\n                        'kind'  => NodeKindEnum::NAME,\n                        'value' => 'SomeOtherType',\n                    ],\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(UnionTypeExtensionNode::class, $node);\n    }\n\n    public function testBuildVariableDefinitionNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::VARIABLE_DEFINITION,\n            'variable' => [\n                'kind' => NodeKindEnum::VARIABLE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'someVariable',\n                ],\n            ],\n            'type' => [\n                'kind' => NodeKindEnum::NAMED_TYPE,\n                'name' => [\n                    'kind'  => NodeKindEnum::NAME,\n                    'value' => 'String',\n                ],\n            ],\n        ]);\n\n        $this->assertInstanceOf(VariableDefinitionNode::class, $node);\n    }\n\n    public function testBuildVariableNode()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::VARIABLE,\n            'name' => [\n                'kind'  => NodeKindEnum::NAME,\n                'value' => 'someVariable',\n            ],\n        ]);\n\n        $this->assertInstanceOf(VariableNode::class, $node);\n    }\n\n    public function testCreateLocation()\n    {\n        $node = $this->builder->build([\n            'kind' => NodeKindEnum::NAME,\n            'value' => 'SomeType',\n            'loc' => ['start' => 0, 'end' => 8],\n        ]);\n\n        $this->assertInstanceOf(Location::class, $node->getLocation());\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Schema/Resolver/ResolverRegistryTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Schema\\Resolver;\n\nuse Digia\\GraphQL\\Execution\\ResolveInfo;\nuse Digia\\GraphQL\\Schema\\Resolver\\AbstractTypeResolver;\nuse Digia\\GraphQL\\Schema\\Resolver\\AbstractFieldResolver;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverMiddlewareInterface;\nuse Digia\\GraphQL\\Schema\\Resolver\\ResolverRegistry;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse function Digia\\GraphQL\\Test\\Functional\\getDroid;\nuse function Digia\\GraphQL\\Test\\Functional\\getHero;\nuse function Digia\\GraphQL\\Test\\Functional\\getHuman;\n\nclass ResolverRegistryTest extends TestCase\n{\n    public function testResolverMap()\n    {\n        $registry = new ResolverRegistry([\n            'Query' => [\n                'human' => function ($_, $args) {\n                    return getHuman($args['id']);\n                },\n                'droid' => function ($_, $args) {\n                    return getDroid($args['id']);\n                },\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'Luke Skywalker',\n        ], $registry->getFieldResolver('Query', 'human')(null, ['id' => '1000']));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'R2-D2',\n        ], $registry->getFieldResolver('Query', 'droid')(null, ['id' => '2001']));\n    }\n\n    public function testTypeResolver()\n    {\n        $registry = new ResolverRegistry([\n            'Query' => new QueryResolver(),\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'Luke Skywalker',\n        ], $registry->getFieldResolver('Query', 'human')(null, ['id' => '1000']));\n    }\n\n    public function testFieldResolver()\n    {\n        $registry = new ResolverRegistry([\n            'Query' => [\n                'human' => new HumanResolver(),\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'Luke Skywalker',\n        ], $registry->getFieldResolver('Query', 'human')(null, ['id' => '1000']));\n    }\n\n    public function testRegisterResolver()\n    {\n        $registry = new ResolverRegistry();\n\n        $registry->register('Query', new QueryResolver());\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'Luke Skywalker',\n        ], $registry->getFieldResolver('Query', 'human')(null, ['id' => '1000']));\n    }\n\n    public function testExtendExistingResolver()\n    {\n        $registry = new ResolverRegistry([\n            'Query' => [\n                'human' => function ($_, $args) {\n                    return getHuman($args['id']);\n                },\n                'droid' => function ($_, $args) {\n                    return getDroid($args['id']);\n                },\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'Luke Skywalker',\n        ], $registry->getFieldResolver('Query', 'human')(null, ['id' => '1000']));\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'R2-D2',\n        ], $registry->getFieldResolver('Query', 'droid')(null, ['id' => '2001']));\n\n        /** @noinspection PhpUndefinedMethodInspection */\n        $registry->getResolver('Query')->addResolver('hero', function ($_, $args) {\n            return getHero($args['episode'] ?? null);\n        });\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertArraySubset([\n            'name' => 'Luke Skywalker',\n        ], $registry->getFieldResolver('Query', 'hero')(null, ['episode' => 'EMPIRE']));\n    }\n\n    public function testMiddleware()\n    {\n        $messages = [];\n\n        $logCallback = function (string $message) use (&$messages) {\n            $messages[] = $message;\n        };\n\n        $registry = new ResolverRegistry([\n            'Query' => [\n                'hello' => new HelloResolver($logCallback),\n            ],\n        ], [\n            new LogInputMiddleware($logCallback),\n            new LogResultMiddleware($logCallback)\n        ]);\n\n        $result = $registry->getFieldResolver('Query', 'hello')(null, ['name' => 'Bob']);\n\n        $this->assertEquals('Hello Bob!', $result);\n        $this->assertEquals([\n            '1. logInput {\"name\":\"Bob\"}',\n            '2. logResult',\n            '3. resolver: hello',\n            '4. logResult',\n            '5. logInput',\n        ], $messages);\n    }\n\n    public function testResolverWithSpecificMiddleware()\n    {\n        $messages = [];\n\n        $logCallback = function (string $message) use (&$messages) {\n            $messages[] = $message;\n        };\n\n        $registry = new ResolverRegistry([\n            'Query' => [\n                'hello' => new HelloResolverWithSpecificMiddleware($logCallback),\n            ],\n        ], [\n            new LogInputMiddleware($logCallback),\n            new LogResultMiddleware($logCallback)\n        ]);\n\n        $registry->getFieldResolver('Query', 'hello')(null, ['name' => 'Bob']);\n\n        $this->assertEquals([\n            '1. logInput {\"name\":\"Bob\"}',\n            '3. resolver: hello',\n            '5. logInput',\n        ], $messages);\n    }\n}\n\nabstract class LogMiddleware implements ResolverMiddlewareInterface\n{\n    protected $logCallback;\n\n    public function __construct(callable $logCallback)\n    {\n        $this->logCallback = $logCallback;\n    }\n}\n\nclass LogInputMiddleware extends LogMiddleware\n{\n    /**\n     * @inheritdoc\n     */\n    public function resolve(\n        callable $resolveCallback,\n        $rootValue,\n        array $arguments,\n        $context = null,\n        ?ResolveInfo $info = null\n    ) {\n        \\call_user_func($this->logCallback, \\sprintf('1. logInput %s', \\json_encode($arguments)));\n        $result = $resolveCallback($rootValue, $arguments, $context, $info);\n        \\call_user_func($this->logCallback, '5. logInput');\n        return $result;\n    }\n}\n\nclass LogResultMiddleware extends LogMiddleware\n{\n    /**\n     * @inheritdoc\n     */\n    public function resolve(\n        callable $resolveCallback,\n        $rootValue,\n        array $arguments,\n        $context = null,\n        ?ResolveInfo $info = null\n    ) {\n        \\call_user_func($this->logCallback, '2. logResult');\n        $result = $resolveCallback($rootValue, $arguments, $context, $info);\n        \\call_user_func($this->logCallback, '4. logResult');\n        return $result;\n    }\n}\n\nclass QueryResolver extends AbstractTypeResolver\n{\n    public function resolveHuman($rootValue, array $arguments, $context = null, ?ResolveInfo $info = null): array\n    {\n        return getHuman($arguments['id']);\n    }\n}\n\nclass HumanResolver extends AbstractFieldResolver\n{\n    public function resolve($rootValue, array $arguments, $context = null, ?ResolveInfo $info = null): array\n    {\n        return getHuman($arguments['id']);\n    }\n}\n\nclass HelloResolver extends AbstractFieldResolver\n{\n    protected $logCallback;\n\n    public function __construct(callable $logCallback)\n    {\n        $this->logCallback = $logCallback;\n    }\n\n    public function resolve($rootValue, array $arguments, $context = null, ?ResolveInfo $info = null): string\n    {\n        \\call_user_func($this->logCallback, '3. resolver: hello');\n        return \\sprintf('Hello %s!', $arguments['name'] ?? 'world');\n    }\n}\n\nclass HelloResolverWithSpecificMiddleware extends HelloResolver\n{\n    public function getMiddleware(): ?array\n    {\n        return [\n            LogInputMiddleware::class,\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Type/Coercer/CoercerInterfaceTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Coercer\\BooleanCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\CoercerInterface;\nuse Digia\\GraphQL\\Type\\Coercer\\FloatCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\IntCoercer;\nuse Digia\\GraphQL\\Type\\Coercer\\StringCoercer;\n\nclass CoercerInterfaceTest extends TestCase\n{\n    public function testCoercersImplementsThisInterface()\n    {\n        $this->assertInstanceOf(CoercerInterface::class, new IntCoercer());\n        $this->assertInstanceOf(CoercerInterface::class, new FloatCoercer());\n        $this->assertInstanceOf(CoercerInterface::class, new StringCoercer());\n        $this->assertInstanceOf(CoercerInterface::class, new BooleanCoercer());\n    }\n}"
  },
  {
    "path": "tests/Unit/Type/Coercer/FloatCoercerTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Coercer\\FloatCoercer;\n\nclass FloatCoercerTest extends TestCase\n{\n    /**\n     * @var FloatCoercer\n     */\n    private $coercer;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n\n        $this->coercer = new FloatCoercer();\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testSuccessfulCoercion(): void\n    {\n        $this->assertSame(0.0, $this->coercer->coerce(false));\n        $this->assertSame(1.0, $this->coercer->coerce(true));\n        $this->assertSame(2.0, $this->coercer->coerce(2));\n    }\n}"
  },
  {
    "path": "tests/Unit/Type/Coercer/IntCoercerTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Error\\InvalidTypeException;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Coercer\\IntCoercer;\n\nclass IntCoercerTest extends TestCase\n{\n\n    /**\n     * @var IntCoercer\n     */\n    private $coercer;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n\n        $this->coercer = new IntCoercer();\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testSuccessfulCoercion(): void\n    {\n        $this->assertSame(0, $this->coercer->coerce(false));\n        $this->assertSame(1, $this->coercer->coerce(true));\n        $this->assertSame(2, $this->coercer->coerce(2.0));\n    }\n\n    /**\n     * @param mixed $value\n     * @dataProvider coerceTooLargeIntegerDataProvider\n     * @throws InvalidTypeException\n     */\n    public function testCoerceTooLargeInteger($value): void\n    {\n        $this->expectException(InvalidTypeException::class);\n        $this->expectExceptionMessageRegExp('*Int cannot represent non 32-bit signed integer value*');\n\n        $this->coercer->coerce($value);\n    }\n\n    /**\n     * @return array\n     */\n    public function coerceTooLargeIntegerDataProvider(): array\n    {\n        return [\n            ['1273898127398213987219837198273232314324324324324324324324324324'],\n            [1e100],\n            [-1e100],\n        ];\n    }\n\n    /**\n     * @throws InvalidTypeException\n     */\n    public function testCoerceFloat(): void\n    {\n        $this->expectException(InvalidTypeException::class);\n        $this->expectExceptionMessageRegExp('*Int cannot represent non-integer value*');\n\n        $this->coercer->coerce(4.55);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Type/Coercer/StringCoercerTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Type\\Coercer;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Type\\Coercer\\StringCoercer;\n\nclass StringCoercerTest extends TestCase\n{\n    /**\n     * @var StringCoercer\n     */\n    private $coercer;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n\n        $this->coercer = new StringCoercer();\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\InvalidTypeException\n     */\n    public function testSuccessfulCoercion(): void\n    {\n        $this->assertSame('false', $this->coercer->coerce(false));\n        $this->assertSame('true', $this->coercer->coerce(true));\n        $this->assertSame('null', $this->coercer->coerce(null));\n        $this->assertSame('2', $this->coercer->coerce(2));\n        $this->assertSame('3.1415926535898', $this->coercer->coerce(pi()));\n    }\n}"
  },
  {
    "path": "tests/Unit/Util/AbstractEnumTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Util;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\AbstractEnum;\n\n/**\n * Class AbstractEnumTest\n * @package Digia\\GraphQL\\Test\\Unit\\Util\n */\nclass AbstractEnumTest extends TestCase\n{\n\n    /**\n     * @throws \\ReflectionException\n     */\n    public function testValues()\n    {\n        $this->assertSame([\n            1,\n            2\n        ], DummyEnum::values());\n    }\n}\n\n/**\n * Class DummyEnum\n * @package Digia\\GraphQL\\Test\\Unit\\Util\n */\nclass DummyEnum extends AbstractEnum\n{\n    public const VALUE_1 = 1;\n    public const VALUE_2 = 2;\n}\n"
  },
  {
    "path": "tests/Unit/Util/NameHelperTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Util;\n\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\NameHelper;\n\n/**\n * Class NameHelperTest\n * @package Digia\\GraphQL\\Test\\Unit\\Util\n */\nclass NameHelperTest extends TestCase\n{\n\n    /**\n     * @expectedException  \\Digia\\GraphQL\\Validation\\ValidationException\n     * @expectedExceptionMessage Name \"__invalid\" must not begin with \"__\", which is reserved by GraphQL introspection.\n     */\n    public function testAssertInvalidReservedCharacters()\n    {\n        $exception = NameHelper::isValidError('__invalid');\n\n        if ($exception !== null) {\n            throw $exception;\n        }\n    }\n\n    /**\n     * @expectedException \\Digia\\GraphQL\\Validation\\ValidationException\n     * @expectedExceptionMessage Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but \"-\" does not.\n     */\n    public function testAssertInvalidRegularExpression()\n    {\n        $exception = NameHelper::isValidError('-');\n\n        if ($exception !== null) {\n            throw $exception;\n        }\n    }\n\n    public function testIsValidErrorNoError()\n    {\n        $exception = NameHelper::isValidError('name');\n\n        $this->assertNull($exception);\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Util/NodeComparatorTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Util;\n\nuse Digia\\GraphQL\\GraphQL;\nuse Digia\\GraphQL\\Language\\Node\\NodeKindEnum;\nuse Digia\\GraphQL\\Language\\NodeBuilderInterface;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\NodeComparator;\n\nclass NodeComparatorTest extends TestCase\n{\n    /**\n     * @var NodeBuilderInterface\n     */\n    private $nodeBuilder;\n\n    public function setUp()\n    {\n        $this->nodeBuilder = GraphQL::make(NodeBuilderInterface::class);\n    }\n\n    public function testCompareSameNode()\n    {\n        $node = $this->nodeBuilder->build([\n            'kind'  => NodeKindEnum::NAME,\n            'value' => ['kind' => NodeKindEnum::STRING, 'value' => 'Foo'],\n        ]);\n\n        $this->assertTrue(NodeComparator::compare($node, $node));\n    }\n\n    public function testCompareDifferentNode()\n    {\n        $node = $this->nodeBuilder->build([\n            'kind'  => NodeKindEnum::NAME,\n            'value' => ['kind' => NodeKindEnum::STRING, 'value' => 'Foo'],\n        ]);\n\n        $other = $this->nodeBuilder->build([\n            'kind'  => NodeKindEnum::NAME,\n            'value' => ['kind' => NodeKindEnum::STRING, 'value' => 'Bar'],\n        ]);\n\n        $this->assertFalse(NodeComparator::compare($node, $other));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Util/ValueASTConverterTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Util;\n\nuse Digia\\GraphQL\\Util\\ConversionException;\nuse Digia\\GraphQL\\Language\\Node\\EnumValueNode;\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ListValueNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\NullValueNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectFieldNode;\nuse Digia\\GraphQL\\Language\\Node\\ObjectValueNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Language\\Node\\VariableNode;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\ValueASTConverter;\nuse function Digia\\GraphQL\\Type\\intType;\nuse function Digia\\GraphQL\\Type\\newEnumType;\nuse function Digia\\GraphQL\\Type\\newInputObjectType;\nuse function Digia\\GraphQL\\Type\\newList;\nuse function Digia\\GraphQL\\Type\\newNonNull;\nuse function Digia\\GraphQL\\Type\\stringType;\n\nclass ValueASTConverterTest extends TestCase\n{\n    /**\n     * @var ValueASTConverter\n     */\n    protected $converter;\n\n    public function setUp()\n    {\n        $this->converter = new ValueASTConverter();\n    }\n\n    public function testConvertNonNullWithStringValue()\n    {\n        $node = new StringValueNode('foo', false, null);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame('foo', $this->converter->convert($node, newNonNull(stringType())));\n    }\n\n    public function testConvertNonNullWithNullValue()\n    {\n        $node = new NullValueNode(null);\n        $this->expectException(ConversionException::class);\n        $this->expectExceptionMessage('Cannot convert non-null values from null value node');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(null, $this->converter->convert($node, newNonNull(stringType())));\n    }\n\n    public function testConvertValidListOfStrings()\n    {\n        $node = new ListValueNode(\n            [\n                new StringValueNode('A', false, null),\n                new StringValueNode('B', false, null),\n                new StringValueNode('C', false, null),\n            ],\n            null\n        );\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(['A', 'B', 'C'], $this->converter->convert($node, newList(stringType())));\n    }\n\n    public function testConvertListWithMissingVariableValue()\n    {\n        $node = new ListValueNode(\n            [\n                new VariableNode(new NameNode('$a', null), null),\n                new VariableNode(new NameNode('$b', null), null),\n                new VariableNode(new NameNode('$c', null), null),\n            ],\n            null\n        );\n        // Null-able inputs in a variable can be omitted\n        $variables = ['$a' => 'A', '$c' => 'C'];\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(['A', null, 'C'], $this->converter->convert($node, newList(stringType()), $variables));\n    }\n\n    public function testConvertValidInputObject()\n    {\n        $node = new ObjectValueNode(\n            [new ObjectFieldNode(new NameNode('a', null), new IntValueNode(1, null), null)],\n            null\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $type = newInputObjectType([\n            'name'   => 'InputObject',\n            'fields' => [\n                'a' => ['type' => intType()],\n            ],\n        ]);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(['a' => 1], $this->converter->convert($node, $type));\n    }\n\n    public function testConvertInputObjectWithNodeOfInvalidType()\n    {\n        $node = new StringValueNode(null, false, null);\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $type = newInputObjectType([\n            'name'   => 'InputObject',\n            'fields' => [\n                'a' => ['type' => intType()],\n            ],\n        ]);\n\n        $this->expectException(ConversionException::class);\n        $this->expectExceptionMessage('Input object values can only be converted form object value nodes.');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(1, $this->converter->convert($node, $type));\n    }\n\n    public function testConvertInputObjectWithMissingNonNullField()\n    {\n        $node = new ObjectValueNode(\n            [new ObjectFieldNode(new NameNode('a', null), new IntValueNode(1, null), null)],\n            null\n        );\n\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $type = newInputObjectType([\n            'name'   => 'InputObject',\n            'fields' => [\n                'a' => ['type' => intType()],\n                'b' => ['type' => newNonNull(stringType())],\n            ],\n        ]);\n\n        $this->expectException(ConversionException::class);\n        $this->expectExceptionMessage('Cannot convert input object value for missing non-null field.');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(['a' => 1], $this->converter->convert($node, $type));\n    }\n\n    public function testConvertEnumWithIntValue()\n    {\n        $node = new EnumValueNode('FOO', null);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $type = newEnumType([\n            'name'   => 'EnumType',\n            'values' => [\n                'FOO' => ['value' => 1],\n            ],\n        ]);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(1, $this->converter->convert($node, $type));\n    }\n\n    public function testConvertEnumWithNodeOfInvalidType()\n    {\n        $node = new StringValueNode(null, false, null);\n        $type = newEnumType([\n            'name' => 'EnumType',\n        ]);\n\n        $this->expectException(ConversionException::class);\n        $this->expectExceptionMessage('Enum values can only be converted from enum value nodes.');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(1, $this->converter->convert($node, $type));\n    }\n\n    public function testConvertEnumWithMissingValue()\n    {\n        $node = new EnumValueNode('FOO', null);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $type = newEnumType([\n            'name'   => 'EnumType',\n            'values' => [\n                'BAR' => ['value' => 'foo'],\n            ],\n        ]);\n        $this->expectException(ConversionException::class);\n        $this->expectExceptionMessage('Cannot convert enum value for missing value \"FOO\".');\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame(1, $this->converter->convert($node, $type));\n    }\n\n    public function testConvertValidScalar()\n    {\n        $node = new StringValueNode('foo', false, null);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame('foo', $this->converter->convert($node, stringType()));\n    }\n\n    public function testConvertInvalidScalar()\n    {\n        $node = new StringValueNode(null, false, null);\n\n        $this->expectException(ConversionException::class);\n        /** @noinspection PhpUnhandledExceptionInspection */\n        $this->assertSame('foo', $this->converter->convert($node, stringType()));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Util/ValueConverterTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Util;\n\nuse Digia\\GraphQL\\Language\\Node\\IntValueNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\ValueConverter;\nuse function Digia\\GraphQL\\Type\\idType;\n\nclass ValueConverterTest extends TestCase\n{\n\n    /**\n     * @var ValueConverter\n     */\n    private $valueConverter;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n\n        $this->valueConverter = new ValueConverter();\n    }\n\n    /**\n     * @throws \\Digia\\GraphQL\\Error\\ConversionException\n     * @throws \\Digia\\GraphQL\\Error\\InvariantException\n     * @throws \\Digia\\GraphQL\\Error\\SyntaxErrorException\n     */\n    public function testIdType(): void\n    {\n        // Ensure numerical IDs become Ints\n        $this->assertInstanceOf(IntValueNode::class, $this->valueConverter->convert('45', idType()));\n        $this->assertInstanceOf(StringValueNode::class, $this->valueConverter->convert('abc123', idType()));\n    }\n}\n"
  },
  {
    "path": "tests/Unit/Util/ValueHelperTest.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test\\Unit\\Util;\n\nuse Digia\\GraphQL\\Language\\Node\\ArgumentNode;\nuse Digia\\GraphQL\\Language\\Node\\NameNode;\nuse Digia\\GraphQL\\Language\\Node\\StringValueNode;\nuse Digia\\GraphQL\\Test\\TestCase;\nuse Digia\\GraphQL\\Util\\ValueHelper;\n\n/**\n * Class ValueHelperTest\n * @package Digia\\GraphQL\\Test\\Unit\\Util\n */\nclass ValueHelperTest extends TestCase\n{\n    /**\n     * @var ValueHelper\n     */\n    private $valueHelper;\n\n    /**\n     * @inheritdoc\n     */\n    protected function setUp()\n    {\n        parent::setUp();\n\n        $this->valueHelper = new ValueHelper();\n    }\n\n    /**\n     *\n     */\n    public function testCompareArguments(): void\n    {\n        // Test argument count mismatch\n        $a = [\n            $this->makeStringArgumentNode('name', 'value'),\n            $this->makeStringArgumentNode('name', 'value'),\n        ];\n\n        $b = [\n            $this->makeStringArgumentNode('name', 'value'),\n        ];\n\n        $this->assertFalse($this->valueHelper->compareArguments($a, $b));\n\n        // Test with no matching name value\n        $a = [\n            $this->makeStringArgumentNode('name', 'value'),\n        ];\n\n        $b = [\n            $this->makeStringArgumentNode('other name', 'value'),\n        ];\n\n        $this->assertFalse($this->valueHelper->compareArguments($a, $b));\n\n        // Test with matching name value but mismatching value\n        $a = [\n            $this->makeStringArgumentNode('name', 'value'),\n        ];\n\n        $b = [\n            $this->makeStringArgumentNode('name', 'other value'),\n        ];\n\n        $this->assertFalse($this->valueHelper->compareArguments($a, $b));\n\n        // Test with full match\n        $a = [\n            $this->makeStringArgumentNode('name', 'value'),\n        ];\n\n        $b = [\n            $this->makeStringArgumentNode('name', 'value'),\n        ];\n\n        $this->assertTrue($this->valueHelper->compareArguments($a, $b));\n    }\n\n    /**\n     * @param string $name\n     * @param string $value\n     * @return ArgumentNode\n     */\n    private function makeStringArgumentNode(string $name, string $value): ArgumentNode\n    {\n        return new ArgumentNode(new NameNode($name, null), new StringValueNode($value, false, null), null);\n    }\n}\n"
  },
  {
    "path": "tests/utils.php",
    "content": "<?php\n\nnamespace Digia\\GraphQL\\Test;\n\n/**\n * @param mixed $value\n * @return string\n */\nfunction jsonEncode($value): string\n{\n    return json_encode($value, JSON_UNESCAPED_UNICODE);\n}\n\n/**\n * @param string $path\n * @return string\n */\nfunction readFileContents(string $path): string\n{\n    return mb_convert_encoding(file_get_contents($path), 'UTF-8');\n}\n"
  }
]