[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2\njobs:\n  build:\n    docker:\n      - image: circleci/node:11.8.0\n\n    environment:\n      TEST_REPORTS: /tmp/test-reports\n\n    steps:\n      - checkout\n\n      - restore_cache:\n          name: Restore Yarn Package Cache\n          keys:\n            - yarn-packages-{{ checksum \"yarn.lock\" }}\n      - run:\n          name: Install Dependencies\n          command: cd ./reason-graphql && yarn install --frozen-lockfile\n\n      - save_cache:\n          name: Save Yarn Package Cache\n          key: yarn-packages-{{ checksum \"yarn.lock\" }}\n          paths:\n            - ~/.cache/yarn\n\n      - run:\n          name: tests\n          command: cd ./reason-graphql && yarn test\n"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "content": "name: Node CI\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [8.x, 10.x, 12.x]\n\n    steps:\n    - uses: actions/checkout@v1\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v1\n      with:\n        node-version: ${{ matrix.node-version }}\n    - name: yarn install, build, and test\n      run: |\n        cd ./reason-graphql\n        yarn install \n        yarn build \n        yarn test\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.merlin\n.bsb.lock\nnpm-debug.log\nlib\nnode_modules\n.vscode\n*.bs.js\n.pnp\n.pnp.js"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## DEV\n### *reason-graphql*\n* (Breaking) Removed \"Variations\". Instead, we provide guidance on how to integrate this with different IO/Async libraries like `reason-promise` or `reason-future`. This prevents version conflicts due to users wanting to upgrade those libraries independently from `reason-graphql`. \n* (Breaking) Changed runtime representation of `List` graphql type to be Array to align better with reality of JS environment and upcoming Bucklescript changes (to prioritize array over list). (https://github.com/sikanhe/reason-graphql/pull/41)\n\n## 0.6.1 \n### *reason-graphql*\n* Fixed introspection not working due to subscription type missing ([#33](https://github.com/sikanhe/reason-graphql/pull/33))\n\n## 0.6.0\n### *reason-graphql*\n* Upgraded bs-platform to v7.0.1 ([#29](https://github.com/sikanhe/reason-graphql/pull/29))\n* Fixed erroring on undefined variables by coercing missing variables to `null` ([#29](https://github.com/sikanhe/reason-graphql/pull/29))\n\n## 0.4.2\n### *reason-graphql*\n* Added __typename support ([#24](https://github.com/sikanhe/reason-graphql/pull/24))\n\n## 0.4.0 \n\n### *reason-graphql*\n* Added `GraphqlPromise` which is a pre-configured variation  that uses `Js.Promise` as the IO type. \n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2019 Sikan He\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": "[![CircleCI](https://circleci.com/gh/sikanhe/reason-graphql/tree/master.svg?style=svg)](https://circleci.com/gh/sikanhe/reason-graphql/tree/master)\n\nType safe GraphQL server in pure reason. Compiles to nodejs. A direct port from https://github.com/andreas/ocaml-graphql-server to make it work with Javascript backend.\n\n\n\n### Motivation\n\nBucklescript is an amazing alternative to other compie-to-js languages. But it's a tragedy that we have such few libraries and bindings written for the server-side. \n\nIn the browser, we can get away with just one great binding for React. However, for the server side, people want major building blocks - a solid database abstractions, a fast http server and a Graphql layer are usually must haves for non-trivial projects. \n\nFor these type of frameworks, I believe we should do more than just writing simple bindings to existing npm libraries, because then we are not taking advantage of the expressive type system and rich features of OCaml/Reason. We also lose the chance to show what a language like Reason can do for developer happiness and why its worth it to use it over existing alternatives. \n\n### What we get over the traditional JS/TS/Flow + graphql-js combination\n\n#### Type safety without manual work\nLike the ReasonReact implementation, GraphQL schemas defined by this library can express more things and place more constraint on the graphql schema than the vanilla javascript or typescript counterparts. \n\nWith Typescript (or Flow), you are required to manually write out the types for all your fields, or use a type generation cli tool like https://graphql-code-generator.com - on top of a lot of manual typecasting, because its typesystem cannot express advanced concepts like heterogenous lists (essentially what arguments and fields are, in GraphQL). \n\nTo give you a taste of what this means - if we define a field argument called `id` with type `string` with graphql-js, even with typescript or flow, it cannot infer the type of `args` inside the resolver to be `{id: string}`. We have to manually type it, which makes it very error-prone. Forget about tracking the nullability of the fields - I have seen many production errors where the manually casted types are out of sync with the schema definition, and vice versa, when the schema gets out of sync with the underlying database models.\n\n```typescript\n  type PersonByIdArgs = {\n    id: string\n  }\n  \n  personById: {\n    type: Person,\n    args: { id: GraphqlNonNull(GraphqQLString) },\n    resolve: (ctx, parent, args: PersonByIdArgs) => {\n                           ^^^^ this is inferred as `Any`, so we need to manually cast it to `PersonByIdArgs`\n    }\n  }\n```\n\nIn Reason, we can use a more advanced feature of the type system called GADT (Generalized Algebriac Data Types) to express our schema types. \n\nWhat GADT allows us to do is to have type-safe definitions without needing to manually write types for field arguments and resolver. It can \"unfold\" the types for resolver as you write out field args! (https://drup.github.io/2016/08/02/difflists/)\n\n```reason \n field(\"PersonById\", \n  ~typ=person, \n  ~args=Args.[arg(\"id\", nonnull(string))] \n  ~resolve=(_ctx, _parent, id) => {\n//                         ^^ Unfolds args into resolver arguments and correctly types it as a string!\n  }\n```\n\nThis works for as many arguments as you like, it infers nullability for you as well and give you an `option('a)` if its nullable! \n\n```reason \n field(\"PersonById\", \n  ~typ=person, \n  ~args=Args.[arg(\"id\", nonnull(string)), arg(\"age\", int)] \n  ~resolve=(_ctx, _parent, id,     age) => {\n                           ^^      ^^^ \n                           string  option(int) because age is not non-null\n  }\n```\n \n### Features todolist:\n  - [x] Query \n  - [x] Mutation \n  - [x] Async Fields\n  - [x] Directives\n  - [ ] Subscription\n  - [ ] Non-type Validations (unused fragment, unused variables, and etc)\n"
  },
  {
    "path": "examples/starwars-api/.gitignore",
    "content": ".DS_Store\n.merlin\n.bsb.lock\nnpm-debug.log\n/lib/bs/\n/node_modules/\n"
  },
  {
    "path": "examples/starwars-api/README.md",
    "content": "# StarWars API using reason-graphql \n\nLive demo: https://reason-graphql-swapi.onrender.com/graphql"
  },
  {
    "path": "examples/starwars-api/bsconfig.json",
    "content": "{\n  \"name\": \"starwars-api\",\n  \"version\": \"0.1.0\",\n  \"sources\": {\n    \"dir\" : \"src\",\n    \"subdirs\" : true\n  },\n  \"package-specs\": {\n    \"module\": \"commonjs\",\n    \"in-source\": true\n  },\n  \"suffix\": \".bs.js\",\n  \"bs-dependencies\": [\n    \"bs-express\",\n    \"bs-fetch\",\n    \"@glennsl/bs-json\",\n    \"reason-future\",\n    \"reason-graphql\",\n    \"reason-graphql-bs-express\",\n    \"reason-dataloader\"\n  ],\n  \"warnings\": {\n    \"number\": \"-44-45\",\n    \"error\" : \"+101\"\n  },\n  \"namespace\": true,\n  \"refmt\": 3\n}\n"
  },
  {
    "path": "examples/starwars-api/package.json",
    "content": "{\n  \"name\": \"starwars-api\",\n  \"version\": \"0.1.0\",\n  \"scripts\": {\n    \"build\": \"bsb -make-world\",\n    \"start\": \"bsb -make-world -w\",\n    \"clean\": \"bsb -clean-world\"\n  },\n  \"keywords\": [\n    \"BuckleScript\"\n  ],\n  \"author\": \"\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"bs-platform\": \"^5.0.2\"\n  },\n  \"dependencies\": {\n    \"@glennsl/bs-json\": \"^3.0.0\",\n    \"bs-express\": \"^0.12.0\",\n    \"bs-fetch\": \"^0.3.1\",\n    \"bs-json\": \"^1.0.1\",\n    \"isomorphic-fetch\": \"^2.2.1\",\n    \"reason-dataloader\": \"^0.1.1\",\n    \"reason-graphql\": \"^0.3.2\",\n    \"reason-graphql-bs-express\": \"^0.2.0\"\n  }\n}\n"
  },
  {
    "path": "examples/starwars-api/src/schema.re",
    "content": "open GraphqlFuture;\n\nlet starship =\n  Schema.(\n    obj(\"starship\", ~fields=_ =>\n      [\n        field(\n          \"name\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.name\n        ),\n        field(\n          \"model\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.model\n        ),\n        field(\n          \"starshipClass\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.starshipClass\n        ),\n        field(\n          \"manufacturers\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.manufacturers\n        ),\n        field(\n          \"costInCredits\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.costInCredits\n        ),\n        field(\n          \"length\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.length\n        ),\n        field(\n          \"crew\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.crew\n        ),\n        field(\n          \"passengers\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.passengers\n        ),\n        field(\n          \"maxAtmospheringSpeed\",\n          int,\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.maxAtmospheringSpeed\n        ),\n        field(\n          \"hyperdriveRating\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.hyperdriveRating\n        ),\n        field(\n          \"mglt\", int, ~args=Arg.[], ~resolve=((), starship: Swapi.starship) =>\n          starship.mglt\n        ),\n        field(\n          \"cargoCapacity\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.cargoCapacity\n        ),\n        field(\n          \"consumables\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), starship: Swapi.starship) =>\n          starship.consumables\n        ),\n      ]\n    )\n  );\n\nlet rec film =\n  lazy\n    Schema.(\n      obj(\"film\", ~fields=_ =>\n        [\n          field(\n            \"title\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            film.title\n          ),\n          field(\n            \"episodeID\",\n            nonnull(int),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            film.episodeID\n          ),\n          field(\n            \"openingCrawl\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            film.openingCrawl\n          ),\n          field(\n            \"director\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            film.director\n          ),\n          field(\n            \"producers\",\n            nonnull(list(nonnull(string))),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            film.producers\n          ),\n          field(\n            \"releaseDate\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            film.releaseDate\n          ),\n          async_field(\n            \"characters\",\n            nonnull(list(nonnull(Lazy.force(person)))),\n            ~args=Arg.[],\n            ~resolve=((), film: Swapi.film) =>\n            Swapi.getEntitiesByUrls(Swapi.decodePerson, film.characterUrls)\n          ),\n        ]\n      )\n    )\n\nand person =\n  lazy\n    Schema.(\n      obj(\"person\", ~fields=_ =>\n        [\n          field(\n            \"name\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            person.name\n          ),\n          field(\n            \"birthYear\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            person.birthYear\n          ),\n          field(\n            \"eyeColor\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            person.eyeColor\n          ),\n          field(\n            \"gender\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            person.gender\n          ),\n          field(\n            \"hairColor\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            person.hairColor\n          ),\n          field(\n            \"height\", int, ~args=Arg.[], ~resolve=((), person: Swapi.person) =>\n            person.height\n          ),\n          field(\n            \"mass\", float, ~args=Arg.[], ~resolve=((), person: Swapi.person) =>\n            person.mass\n          ),\n          field(\n            \"skinColor\",\n            nonnull(string),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            person.skinColor\n          ),\n          async_field(\n            \"films\",\n            nonnull(list(nonnull(Lazy.force(film)))),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            Swapi.getEntitiesByUrls(Swapi.decodeFilm, person.filmUrls)\n          ),\n          async_field(\n            \"starships\",\n            nonnull(list(nonnull(starship))),\n            ~args=Arg.[],\n            ~resolve=((), person: Swapi.person) =>\n            Swapi.getEntitiesByUrls(Swapi.decodeStarship, person.starshipUrls)\n          ),\n        ]\n      )\n    );\n\nlet planet =\n  Schema.(\n    obj(\"planet\", ~fields=_ =>\n      [\n        field(\n          \"name\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.name\n        ),\n        field(\n          \"diameter\", int, ~args=Arg.[], ~resolve=((), planet: Swapi.planet) =>\n          planet.diameter\n        ),\n        field(\n          \"rotationPeriod\",\n          int,\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.rotationPeriod\n        ),\n        field(\n          \"orbitalPeriod\",\n          int,\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.orbitalPeriod\n        ),\n        field(\n          \"gravity\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.gravity\n        ),\n        field(\n          \"population\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.population\n        ),\n        field(\n          \"climates\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.climates\n        ),\n        field(\n          \"terrains\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.terrains\n        ),\n        field(\n          \"surfaceWater\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), planet: Swapi.planet) =>\n          planet.surfaceWater\n        ),\n      ]\n    )\n  );\n\nlet species =\n  Schema.(\n    obj(\"species\", ~fields=_ =>\n      [\n        field(\n          \"name\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.name\n        ),\n        field(\n          \"classification\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.classification\n        ),\n        field(\n          \"designation\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.designation\n        ),\n        field(\n          \"averageHeight\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.averageHeight\n        ),\n        field(\n          \"averageLifespan\",\n          int,\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.averageLifespan\n        ),\n        field(\n          \"eyeColors\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.eyeColors\n        ),\n        field(\n          \"hairColors\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.hairColors\n        ),\n        field(\n          \"skinColors\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.skinColors\n        ),\n        field(\n          \"language\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), species: Swapi.species) =>\n          species.language\n        ),\n      ]\n    )\n  );\n\nlet vehicle =\n  Schema.(\n    obj(\"vehicle\", ~fields=_ =>\n      [\n        field(\n          \"name\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.name\n        ),\n        field(\n          \"model\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.model\n        ),\n        field(\n          \"starshipClass\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.vehicleClass\n        ),\n        field(\n          \"manufacturers\",\n          nonnull(list(nonnull(string))),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.manufacturers\n        ),\n        field(\n          \"costInCredits\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.costInCredits\n        ),\n        field(\n          \"length\", float, ~args=Arg.[], ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.length\n        ),\n        field(\n          \"crew\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.crew\n        ),\n        field(\n          \"passengers\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.passengers\n        ),\n        field(\n          \"maxAtmospheringSpeed\",\n          int,\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.maxAtmospheringSpeed\n        ),\n        field(\n          \"cargoCapacity\",\n          float,\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.cargoCapacity\n        ),\n        field(\n          \"consumables\",\n          nonnull(string),\n          ~args=Arg.[],\n          ~resolve=((), vehicle: Swapi.vehicle) =>\n          vehicle.consumables\n        ),\n      ]\n    )\n  );\n\nLazy.force(film);\nLazy.force(person);\n\nlet rootQuery =\n  Schema.(\n    query([\n      async_field(\n        \"allFilms\",\n        nonnull(list(nonnull(Lazy.force(film)))),\n        ~args=Arg.[],\n        ~resolve=((), ()) =>\n        Swapi.getAllFilms()\n      ),\n      async_field(\n        \"film\",\n        Lazy.force(film),\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=((), (), id) =>\n        Swapi.getFilm(id)\n      ),\n      async_field(\n        \"allPeople\",\n        nonnull(list(nonnull(Lazy.force(person)))),\n        ~args=Arg.[],\n        ~resolve=((), ()) =>\n        Swapi.getAllPeople()\n      ),\n      async_field(\n        \"person\",\n        Lazy.force(person),\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=((), (), id) =>\n        Swapi.getPerson(id)\n      ),\n      async_field(\n        \"allPlanets\",\n        nonnull(list(nonnull(planet))),\n        ~args=Arg.[],\n        ~resolve=((), ()) =>\n        Swapi.getAllPlanets()\n      ),\n      async_field(\n        \"planet\",\n        planet,\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=((), (), id) =>\n        Swapi.getPlanet(id)\n      ),\n      async_field(\n        \"allSpecies\",\n        nonnull(list(nonnull(species))),\n        ~args=Arg.[],\n        ~resolve=((), ()) =>\n        Swapi.getAllSpecies()\n      ),\n      async_field(\n        \"species\",\n        species,\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=((), (), id) =>\n        Swapi.getSpecies(id)\n      ),\n      async_field(\n        \"allStarships\",\n        nonnull(list(nonnull(starship))),\n        ~args=Arg.[],\n        ~resolve=((), ()) =>\n        Swapi.getAllStarships()\n      ),\n      async_field(\n        \"starship\",\n        starship,\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=((), (), id) =>\n        Swapi.getStarship(id)\n      ),\n      async_field(\n        \"allVehicles\",\n        nonnull(list(nonnull(vehicle))),\n        ~args=Arg.[],\n        ~resolve=((), ()) =>\n        Swapi.getAllVehicles()\n      ),\n      async_field(\n        \"vehicle\",\n        vehicle,\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=((), (), id) =>\n        Swapi.getVehicle(id)\n      ),\n    ])\n  );\n\nlet schema = Schema.create(rootQuery);"
  },
  {
    "path": "examples/starwars-api/src/server.re",
    "content": "open Express;\n\nlet app = express();\n\nApp.use(app, Middleware.json(~limit=ByteLimit.mb(5.0), ()));\n\nApp.useOnPath(app, ~path=\"/graphql\") @@\nGraphqlExpress.middleware(Schema.schema, ~provideCtx=_ => (), ~graphiql=true);\n\nApp.get(app, ~path=\"*\") @@\nMiddleware.from((_, _) => Response.redirect(\"/graphql\"));\n\nlet onListen = e =>\n  switch (e) {\n  | exception (Js.Exn.Error(e)) =>\n    Js.log(e);\n    Node.Process.exit(1);\n  | _ => Js.log(\"Listening at http://127.0.0.1:3000\")\n  };\n\nApp.listen(app, ~port=3000, ~onListen, ());"
  },
  {
    "path": "examples/starwars-api/src/swapi.re",
    "content": "type film = {\n  title: string,\n  episodeID: int,\n  openingCrawl: string,\n  director: string,\n  producers: list(string),\n  releaseDate: string,\n  characterUrls: list(string),\n};\n\ntype person = {\n  name: string,\n  birthYear: string,\n  eyeColor: string,\n  gender: string,\n  hairColor: string,\n  height: option(int),\n  mass: option(float),\n  skinColor: string,\n  filmUrls: list(string),\n  speciesUrls: list(string),\n  vehicleUrls: list(string),\n  starshipUrls: list(string),\n};\n\ntype planet = {\n  name: string,\n  diameter: option(int),\n  rotationPeriod: option(int),\n  orbitalPeriod: option(int),\n  gravity: string,\n  population: option(float),\n  climates: list(string),\n  terrains: list(string),\n  surfaceWater: option(float),\n};\n\ntype species = {\n  name: string,\n  classification: string,\n  designation: string,\n  averageHeight: option(float),\n  averageLifespan: option(int),\n  eyeColors: list(string),\n  hairColors: list(string),\n  skinColors: list(string),\n  language: string,\n};\n\ntype starship = {\n  name: string,\n  model: string,\n  starshipClass: string,\n  manufacturers: list(string),\n  costInCredits: option(float),\n  length: option(float),\n  crew: string,\n  passengers: string,\n  maxAtmospheringSpeed: option(int),\n  hyperdriveRating: option(float),\n  mglt: option(int),\n  cargoCapacity: option(float),\n  consumables: string,\n};\n\ntype vehicle = {\n  name: string,\n  model: string,\n  vehicleClass: string,\n  manufacturers: list(string),\n  costInCredits: option(float),\n  length: option(float),\n  crew: string,\n  passengers: string,\n  maxAtmospheringSpeed: option(int),\n  cargoCapacity: option(float),\n  consumables: string,\n};\n\n[%raw \"require('isomorphic-fetch')\"];\n\nlet baseUrl = \"https://swapi.co/api/\";\n\nexception RecordNotFound;\n\nlet removeGrouping = numberString =>\n  Js.String.replaceByRe([%re \"/,/\"], \"\", numberString);\n\nlet parseFloat = n =>\n  n |> Js.String.replaceByRe([%re \"/,/\"], \"\") |> Js.Float.fromString;\nlet parseFloatOpt =\n  fun\n  | \"n/a\"\n  | \"unknown\" => None\n  | n =>\n    try (Some(n |> parseFloat)) {\n    | Failure(_) => None\n    };\n\nlet parseInt = n => {\n  (n |> Js.String.replaceByRe([%re \"/,/\"], \"\"))->int_of_string;\n};\nlet parseIntOpt =\n  fun\n  | \"n/a\"\n  | \"unknown\" => None\n  | n =>\n    try (Some(n |> parseInt)) {\n    | Failure(_) => None\n    };\n\nlet rec futureAll =\n  Future.(\n    fun\n    | [] => value([])\n    | [future, ...rest] =>\n      flatMap(future, value => map(futureAll(rest), acc => [value, ...acc]))\n  );\n\nlet urlDataloader =\n  Dataloader.make(urls =>\n    urls\n    |> List.map(url =>\n         Js.Promise.(\n           Fetch.fetch(url)\n           |> then_(res =>\n                Fetch.Response.status(res) == 404\n                  ? reject(RecordNotFound) : resolve(res)\n              )\n           |> then_(Fetch.Response.json)\n           |> FutureJs.fromPromise(_, Js.String.make)\n         )\n       )\n    |> futureAll\n  );\n\nlet getEntityByUrl = (decoder, url) =>\n  Future.map(\n    urlDataloader.load(url),\n    fun\n    | Ok(thing) => Belt.Result.Ok(Some(decoder(thing)))\n    | Error(_) => Ok(None),\n  );\n\nlet getEntityById = (path, decoder, id) =>\n  getEntityByUrl(decoder, baseUrl ++ path ++ \"/\" ++ string_of_int(id));\n\nlet getAllEntitiesForType = (path, decoder, ()) => {\n  let rec aux = (acc, nextUrl) => {\n    urlDataloader.load(nextUrl)\n    ->Future.flatMapOk(json => {\n        let results = Json.Decode.(json |> field(\"results\", list(decoder)));\n        let nextUrl = Json.Decode.(json |> field(\"next\", optional(string)));\n\n        switch (nextUrl) {\n        | Some(url) => aux(List.concat([acc, results]), url)\n        | None => Future.value(Belt.Result.Ok(List.concat([acc, results])))\n        };\n      });\n  };\n\n  aux([], baseUrl ++ path);\n};\n\nlet getEntitiesByUrls = (decoder, urls) => {\n  urlDataloader.loadMany(urls)\n  ->Future.map(\n      List.fold_left(\n        acc =>\n          fun\n          | Belt.Result.Ok(result) => [decoder(result), ...acc]\n          | Error(_) => acc,\n        [],\n      ),\n    )\n  ->Future.map(list => Belt.Result.Ok(list));\n};\n\nlet decodeFilm = (json: Js.Json.t): film =>\n  Json.Decode.{\n    title: json |> field(\"title\", string),\n    episodeID: json |> field(\"episode_id\", int),\n    openingCrawl: json |> field(\"opening_crawl\", string),\n    director: json |> field(\"director\", string),\n    producers:\n      json\n      |> field(\"producer\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    releaseDate: json |> field(\"release_date\", string),\n    characterUrls: json |> field(\"characters\", list(string)),\n  };\n\nlet getFilm = getEntityById(\"films\", decodeFilm);\nlet getAllFilms = getAllEntitiesForType(\"films\", decodeFilm);\n\nlet decodePerson = (json: Js.Json.t): person =>\n  Json.Decode.{\n    name: json |> field(\"name\", string),\n    birthYear: json |> field(\"birth_year\", string),\n    eyeColor: json |> field(\"eye_color\", string),\n    gender: json |> field(\"gender\", string),\n    hairColor: json |> field(\"hair_color\", string),\n    height: json |> field(\"height\", string) |> parseIntOpt,\n    mass: json |> field(\"mass\", string) |> parseFloatOpt,\n    skinColor: json |> field(\"skin_color\", string),\n    filmUrls: json |> field(\"films\", list(string)),\n    starshipUrls: json |> field(\"starships\", list(string)),\n    vehicleUrls: json |> field(\"vehicles\", list(string)),\n    speciesUrls: json |> field(\"species\", list(string)),\n  };\n\nlet getPerson = getEntityById(\"people\", decodePerson);\nlet getAllPeople = getAllEntitiesForType(\"people\", decodePerson);\n\nlet decodePlanet = (json: Js.Json.t): planet =>\n  Json.Decode.{\n    name: json |> field(\"name\", string),\n    diameter: json |> field(\"diameter\", string) |> parseIntOpt,\n    rotationPeriod: json |> field(\"rotation_period\", string) |> parseIntOpt,\n    orbitalPeriod: json |> field(\"orbital_period\", string) |> parseIntOpt,\n    gravity: json |> field(\"gravity\", string),\n    population: json |> field(\"population\", string) |> parseFloatOpt,\n    climates:\n      json\n      |> field(\"climate\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    terrains:\n      json\n      |> field(\"terrain\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    surfaceWater: json |> field(\"surface_water\", string) |> parseFloatOpt,\n  };\n\nlet getPlanet = getEntityById(\"planets\", decodePlanet);\nlet getAllPlanets = getAllEntitiesForType(\"planets\", decodePlanet);\n\nlet decodeSpecies = (json: Js.Json.t): species =>\n  Json.Decode.{\n    name: json |> field(\"name\", string),\n    classification: json |> field(\"classification\", string),\n    designation: json |> field(\"designation\", string),\n    averageHeight: json |> field(\"average_height\", string) |> parseFloatOpt,\n    averageLifespan: json |> field(\"average_lifespan\", string) |> parseIntOpt,\n    eyeColors:\n      json\n      |> field(\"eye_colors\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    hairColors:\n      json\n      |> field(\"hair_colors\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    skinColors:\n      json\n      |> field(\"skin_colors\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    language: json |> field(\"language\", string),\n  };\n\nlet getSpecies = getEntityById(\"species\", decodeSpecies);\nlet getAllSpecies = getAllEntitiesForType(\"species\", decodeSpecies);\n\nlet decodeStarship = (json: Js.Json.t): starship =>\n  Json.Decode.{\n    name: json |> field(\"name\", string),\n    model: json |> field(\"model\", string),\n    starshipClass: json |> field(\"starship_class\", string),\n    manufacturers:\n      json\n      |> field(\"manufacturer\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    costInCredits: json |> field(\"cost_in_credits\", string) |> parseFloatOpt,\n    length: json |> field(\"length\", string) |> parseFloatOpt,\n    crew: json |> field(\"crew\", string),\n    passengers: json |> field(\"passengers\", string),\n    maxAtmospheringSpeed:\n      json |> field(\"max_atmosphering_speed\", string) |> parseIntOpt,\n    hyperdriveRating:\n      json |> field(\"hyperdrive_rating\", string) |> parseFloatOpt,\n    mglt: json |> field(\"MGLT\", string) |> parseIntOpt,\n    cargoCapacity: json |> field(\"cargo_capacity\", string) |> parseFloatOpt,\n    consumables: json |> field(\"consumables\", string),\n  };\n\nlet getStarship = getEntityById(\"starships\", decodeStarship);\nlet getAllStarships = getAllEntitiesForType(\"starships\", decodeStarship);\n\nlet decodeVehicle = (json: Js.Json.t): vehicle =>\n  Json.Decode.{\n    name: json |> field(\"name\", string),\n    model: json |> field(\"model\", string),\n    vehicleClass: json |> field(\"vehicle_class\", string),\n    manufacturers:\n      json\n      |> field(\"manufacturer\", string)\n      |> Js.String.split(\", \")\n      |> Array.to_list,\n    costInCredits: json |> field(\"cost_in_credits\", string) |> parseFloatOpt,\n    length: json |> field(\"length\", string) |> parseFloatOpt,\n    crew: json |> field(\"crew\", string),\n    passengers: json |> field(\"passengers\", string),\n    maxAtmospheringSpeed:\n      json |> field(\"max_atmosphering_speed\", string) |> parseIntOpt,\n    cargoCapacity: json |> field(\"cargo_capacity\", string) |> parseFloatOpt,\n    consumables: json |> field(\"consumables\", string),\n  };\n\nlet getVehicle = getEntityById(\"vehicles\", decodeVehicle);\nlet getAllVehicles = getAllEntitiesForType(\"vehicles\", decodeVehicle);"
  },
  {
    "path": "reason-graphql/__tests__/GraphqlJsPromise.re",
    "content": "module Schema =\n  Graphql.Schema.Make({\n    type t('a) = Js.Promise.t('a);\n\n    let return = Js.Promise.resolve;\n    let map = (p, continuation) => {\n      p |> Js.Promise.then_(value => continuation(value)->Js.Promise.resolve);\n    };\n    let bind = (p, continuation) => {\n      Js.Promise.then_(continuation, p);\n    };\n  });\n"
  },
  {
    "path": "reason-graphql/__tests__/StarWarsData.re",
    "content": "type episode =\n  | NEWHOPE\n  | EMPIRE\n  | JEDI;\n\ntype human = {\n  id: int,\n  name: string,\n  friends: list(int),\n  appearsIn: array(episode),\n  homePlanet: option(string),\n};\n\ntype droid = {\n  id: int,\n  name: string,\n  friends: list(int),\n  appearsIn: array(episode),\n  primaryFunction: string,\n};\n\ntype character =\n  | Human(human)\n  | Droid(droid);\n\nlet luke = {\n  id: 1000,\n  name: \"Luke Skywalker\",\n  friends: [1002, 1003, 2000, 2001],\n  appearsIn: [|NEWHOPE, EMPIRE, JEDI|],\n  homePlanet: Some(\"Tatooine\"),\n};\n\nlet vader = {\n  id: 1001,\n  name: \"Darth Vader\",\n  friends: [1004],\n  appearsIn: [|NEWHOPE, EMPIRE, JEDI|],\n  homePlanet: Some(\"Tatooine\"),\n};\n\nlet han = {\n  id: 1002,\n  name: \"Han Solo\",\n  friends: [1000, 1003, 2001],\n  appearsIn: [|NEWHOPE, EMPIRE, JEDI|],\n  homePlanet: None,\n};\n\nlet leia = {\n  id: 1003,\n  name: \"Leia Organa\",\n  friends: [1000, 1002, 2000, 2001],\n  appearsIn: [|NEWHOPE, EMPIRE, JEDI|],\n  homePlanet: Some(\"Alderaan\"),\n};\n\nlet threepio = {\n  id: 2000,\n  name: \"C-3PO\",\n  friends: [1000, 1002, 1003, 2001],\n  appearsIn: [|NEWHOPE, EMPIRE, JEDI|],\n  primaryFunction: \"Protocol\",\n};\n\nlet artoo = {\n  id: 2001,\n  name: \"R2-D2\",\n  friends: [1000, 1002, 1003],\n  appearsIn: [|NEWHOPE, EMPIRE, JEDI|],\n  primaryFunction: \"Astromech\",\n};\n\nlet getHuman = id =>\n  Js.Promise.resolve(Belt.List.getBy([luke, han, leia, vader], human => human.id == id));\nlet getDroid = id =>\n  Js.Promise.resolve(Belt.List.getBy([threepio, artoo], droid => droid.id == id));\nlet getCharacter = id => {\n  getHuman(id)\n  |> Js.Promise.(\n       then_(\n         fun\n         | Some(human) => resolve(Some(Human(human)))\n         | None => {\n             getDroid(id)\n             |> then_(\n                  fun\n                  | Some(droid) => resolve(Some(Droid(droid)))\n                  | None => resolve(None),\n                );\n           },\n       )\n     );\n};\n\ntype updateCharacterNameError =\n  | CharacterNotFound(int);\n\ntype updateCharacterResult = Belt.Result.t(character, updateCharacterNameError);\n\nlet updateCharacterName = (id, name): Js.Promise.t(updateCharacterResult) => {\n  getCharacter(id)\n  |> Js.Promise.(\n       then_(\n         fun\n         | Some(Human(human)) => resolve(Belt.Result.Ok(Human({...human, name})))\n         | Some(Droid(droid)) => resolve(Belt.Result.Ok(Droid({...droid, name})))\n         | None => resolve(Belt.Result.Error(CharacterNotFound(id))),\n       )\n     );\n};\n\nlet rec futureAll =\n  fun\n  | [] => Js.Promise.resolve([])\n  | [x, ...xs] =>\n    Js.Promise.then_(\n      xs' => Js.Promise.then_(x' => Js.Promise.resolve([x', ...xs']), x),\n      futureAll(xs),\n    );\n\nlet getFriends = ids => {\n  Belt.List.map(ids, id => {\n    id |> getCharacter |> Js.Promise.(then_(x => resolve(Belt.Option.getExn(x))))\n  })\n  |> Array.of_list\n  |> Js.Promise.all\n};\n"
  },
  {
    "path": "reason-graphql/__tests__/StarWarsSchema.re",
    "content": "open Belt.Result;\nopen GraphqlJsPromise;\n\nmodule StarWars = StarWarsData;\n\nlet episodeEnum =\n  Schema.(\n    makeEnum(\n      \"Episode\",\n      [\n        enumValue(\"NEWHOPE\", ~value=StarWars.NEWHOPE, ~description=\"Released in 1977\"),\n        enumValue(\"EMPIRE\", ~value=StarWars.EMPIRE, ~description=\"Released in 1980\"),\n        enumValue(\"JEDI\", ~value=StarWars.JEDI, ~description=\"Released in 1983\"),\n      ],\n    )\n  );\n\nlet rec characterInterface: Schema.abstractType('ctx, [ | `Character]) =\n  Schema.(\n    interface(\"Character\", ~fields=character =>\n      [\n        abstractField(\"id\", nonnull(int), ~args=[]),\n        abstractField(\"name\", nonnull(string), ~args=[]),\n        abstractField(\"appearsIn\", nonnull(list(nonnull(episodeEnum.fieldType))), ~args=[]),\n        abstractField(\"friends\", nonnull(list(nonnull(character))), ~args=[]),\n      ]\n    )\n  )\n\nand humanAsCharacterInterface =\n  lazy(Schema.addType(characterInterface, Lazy.force(humanTypeLazy)))\nand droidAsCharacterInterface =\n  lazy(Schema.addType(characterInterface, Lazy.force(droidTypeLazy)))\nand asCharacterInterface =\n  fun\n  | StarWars.Human(human) => Lazy.force(humanAsCharacterInterface, human)\n  | Droid(droid) => Lazy.force(droidAsCharacterInterface, droid)\n\nand humanTypeLazy =\n  lazy(\n    Schema.(\n      obj(\"Human\", ~description=\"A humanoid creature in the Star Wars universe.\", ~fields=_ =>\n        [\n          field(\"id\", nonnull(int), ~args=[], ~resolve=(_ctx, human: StarWars.human) => human.id),\n          field(\"name\", nonnull(string), ~args=[], ~resolve=(_ctx, human: StarWars.human) =>\n            human.StarWars.name\n          ),\n          field(\n            \"appearsIn\",\n            nonnull(list(nonnull(episodeEnum.fieldType))),\n            ~args=[],\n            ~resolve=(_ctx, human: StarWars.human) =>\n            human.StarWars.appearsIn\n          ),\n          async_field(\n            \"friends\",\n            nonnull(list(nonnull(characterInterface))),\n            ~args=[],\n            ~resolve=(_ctx, human: StarWars.human) =>\n            Js.Promise.(\n              StarWars.getFriends(human.friends)\n              |> then_(list => resolve(Ok(Belt.Array.map(list, asCharacterInterface))))\n            )\n          ),\n          field(\"homePlanet\", string, ~args=[], ~resolve=(_ctx, human: StarWars.human) =>\n            human.homePlanet\n          ),\n        ]\n      )\n    )\n  )\n\nand droidTypeLazy =\n  lazy(\n    Schema.(\n      obj(\"Droid\", ~description=\"A mechanical creature in the Star Wars universe.\", ~fields=_ =>\n        [\n          field(\"id\", nonnull(int), ~args=[], ~resolve=(_ctx, droid: StarWars.droid) => droid.id),\n          field(\"name\", nonnull(string), ~args=[], ~resolve=(_ctx, droid: StarWars.droid) =>\n            droid.StarWars.name\n          ),\n          field(\n            \"appearsIn\",\n            nonnull(list(nonnull(episodeEnum.fieldType))),\n            ~args=[],\n            ~resolve=(_ctx, droid: StarWars.droid) =>\n            droid.StarWars.appearsIn\n          ),\n          field(\n            \"primaryFunction\", nonnull(string), ~args=[], ~resolve=(_ctx, droid: StarWars.droid) =>\n            droid.primaryFunction\n          ),\n          async_field(\n            \"friends\",\n            nonnull(list(nonnull(characterInterface))),\n            ~args=[],\n            ~resolve=(_ctx, droid: StarWars.droid) =>\n            Js.Promise.(\n              StarWars.getFriends(droid.friends)\n              |> then_(list => resolve(Belt.Array.map(list, asCharacterInterface)))\n              |> then_(list => resolve(Ok(list)))\n            )\n          ),\n        ]\n      )\n    )\n  );\n\nlet humanType = Lazy.force(humanTypeLazy);\nlet droidType = Lazy.force(droidTypeLazy);\nlet humanAsCharacterInterface = Lazy.force(humanAsCharacterInterface);\nlet droidAsCharacterInterface = Lazy.force(droidAsCharacterInterface);\n\nlet query =\n  Schema.(\n    query([\n      field(\n        \"hero\",\n        nonnull(characterInterface),\n        ~args=\n          Arg.[\n            arg(\n              \"episode\",\n              episodeEnum.argTyp,\n              ~description=\n                \"If omitted, returns the hero of the whole saga. \"\n                ++ \"If provided, returns the hero of that particular episode.\",\n            ),\n          ],\n        ~resolve=(_ctx, (), episode) =>\n        switch (episode) {\n        | Some(EMPIRE) => humanAsCharacterInterface(StarWarsData.luke)\n        | _ => droidAsCharacterInterface(StarWarsData.artoo)\n        }\n      ),\n      async_field(\n        \"human\",\n        humanType,\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=(_ctx, (), argId) => {\n          let id = argId;\n          StarWarsData.getHuman(id) |> Js.Promise.(then_(human => resolve(Ok(human))));\n        },\n      ),\n      async_field(\n        \"droid\",\n        droidType,\n        ~args=Arg.[arg(\"id\", nonnull(int))],\n        ~resolve=(_ctx, (), argId) => {\n          let id = argId;\n          StarWarsData.getDroid(id) |> Js.Promise.(then_(human => resolve(Ok(human))));\n        },\n      ),\n    ])\n  );\n\nlet updateCharacterResponse =\n  Schema.(\n    obj(\"UpdateCharacterResponse\", ~fields=_ =>\n      [\n        field(\n          \"error\",\n          string,\n          ~args=[],\n          ~resolve=(_, updateCharResult: StarWars.updateCharacterResult) =>\n          switch (updateCharResult) {\n          | Ok(_) => None\n          | Error(CharacterNotFound(id)) =>\n            Some(\"Character with ID \" ++ string_of_int(id) ++ \" not found\")\n          }\n        ),\n        field(\n          \"character\",\n          characterInterface,\n          ~args=[],\n          ~resolve=(_, updateCharResult: StarWars.updateCharacterResult) =>\n          switch (updateCharResult) {\n          | Ok(char) => Some(char->asCharacterInterface)\n          | Error(_) => None\n          }\n        ),\n      ]\n    )\n  );\n\nlet mutation =\n  Schema.(\n    mutation([\n      async_field(\n        \"updateCharacterName\",\n        nonnull(updateCharacterResponse),\n        ~args=\n          Arg.[\n            arg(\"characterId\", nonnull(int)),\n            arg(\"name\", nonnull(string)),\n            arg(\"appearsIn\", string),\n          ],\n        ~resolve=(_ctx, (), charId, name, _appearsIn) =>\n        StarWarsData.updateCharacterName(charId, name)\n        |> Js.Promise.(then_(x => resolve(Ok(x))))\n      ),\n    ])\n  );\n\nlet schema: Schema.schema(unit) = Schema.create(query, ~mutation);\n"
  },
  {
    "path": "reason-graphql/__tests__/parser_test.re",
    "content": "open Jest;\nopen Graphql_Language;\n\ndescribe(\"Parse and print a graphql query\", () => {\n  open Expect;\n\n  let query = {|\n    query My1stQuery($id: Int, $another: [String!]!) { field {\n                hello: name\n                stringField(name:\"\\\"test\\\"\",nameagain:\"汉字\")\n        # Commentsssss\n                age(default: 4.5, a: [4, 5, 5])\n        ... on Foo {\n                bar(h:{hello:5,nested:{world:1}})\n                      ... on BarType {\n                baz    @skip(if: $another) @skip(if: $another)\n                ...bazFields\n        }\n        }\n      }\n    }\n\n    fragment bazFields on FragmentModel {\n      foo\n      baz {\n                g @skip(if: $another)\n        ... on Bar {\n          # dfffdfdfd\n          b @skip(if: $another) @skip(if: {a: [1, 3, 4]})\n                  c\n            a\n        }\n      }\n    }\n |};\n\n  let document = Parser.parse(query);\n  let out = document->Belt.Result.getExn->Printer.print;\n\n  test(\"Should prettify the query correctly\", () => {\n    let pretty = {|query My1stQuery($id: Int, $another: [String!]!) {\n  field {\n    hello: name\n    stringField(name: \"\\\"test\\\"\", nameagain: \"汉字\")\n    age(default: 4.5, a: [4, 5, 5])\n    ... on Foo {\n      bar(h: {hello: 5, nested: {world: 1}})\n      ... on BarType {\n        baz @skip(if: $another) @skip(if: $another)\n        ...bazFields\n      }\n    }\n  }\n}\n\nfragment bazFields on FragmentModel {\n  foo\n  baz {\n    g @skip(if: $another)\n    ... on Bar {\n      b @skip(if: $another) @skip(if: {a: [1, 3, 4]})\n      c\n      a\n    }\n  }\n}|};\n\n    expect(out) |> toBe(pretty);\n  });\n});\n\ndescribe(\"Ast mapper\", () => {\n  let query = {|query My1stQuery($id: Int, $another: [String!]!) {\n  field {\n    hello: name\n    stringField(name: \"\\\"test\\\"\", nameagain: \"汉字\")\n    age(default: 4.5, a: [4, 5, 5])\n    ... on Foo {\n      bar(h: {hello: 5, nested: {world: 1}})\n      ... on BarType {\n        baz @skip(if: $another) @skip(if: $another)\n        ...bazFields\n      }\n    }\n  }\n}\n\nfragment bazFields on FragmentModel {\n  foo\n  baz {\n    g @skip(if: $another)\n    ... on Bar {\n      b @skip(if: $another) @skip(if: {a: [1, 3, 4]})\n      c\n      a\n    }\n  }\n}|};\n\n  let expected = {|query My1stQuery($id: Int, $another: [String!]!) {\n  HI {\n    hello: HI\n    HI(name: \"\\\"test\\\"\", nameagain: \"汉字\")\n    HI(default: 4.5, a: [4, 5, 5])\n    ... on Foo {\n      HI(h: {hello: 5, nested: {world: 1}})\n      ... on BarType {\n        HI @skip(if: $another) @skip(if: $another)\n        ...bazFields\n      }\n    }\n  }\n}\n\nfragment bazFields on FragmentModel {\n  HI\n  HI {\n    HI @skip(if: $another)\n    ... on Bar {\n      HI @skip(if: $another) @skip(if: {a: [1, 3, 4]})\n      HI\n      HI\n    }\n  }\n}|};\n\n  test(\"default mapper\", () => {\n    open Expect;\n\n    let document = Parser.parse(query)->Belt.Result.getExn;\n\n    let modified = Ast.visit(~enter=Ast.defaultMapper, document);\n\n    let out = Printer.print(modified);\n\n    expect(out) |> toBe(query);\n  });\n\n  test(\"enter\", () => {\n    open Expect;\n\n    let document = Parser.parse(query)->Belt.Result.getExn;\n\n    let modified =\n      Ast.visit(\n        ~enter={\n          ...Ast.defaultMapper,\n          field: field => {...field, name: \"HI\"},\n        },\n        document,\n      );\n\n    let out = Printer.print(modified);\n\n    expect(out) |> toBe(expected);\n  });\n\n    test(\"leave\", () => {\n    open Expect;\n\n    let document = Parser.parse(query)->Belt.Result.getExn;\n\n    let modified =\n      Ast.visit(\n        ~leave={\n          ...Ast.defaultMapper,\n          field: field => {...field, name: \"HI\"},\n        },\n        document,\n      );\n\n    let out = Printer.print(modified);\n\n    expect(out) |> toBe(expected);\n  });\n});"
  },
  {
    "path": "reason-graphql/__tests__/schema_test.re",
    "content": "open Jest;\nopen Expect;\nopen Graphql.Language;\nopen GraphqlJsPromise;\n\nlet schema = StarWarsSchema.schema;\n\nlet okResponse = a => `Object([(\"data\", a)]);\n\ndescribe(\"Basic Queries\", () => {\n  testAsync(\"Correctly identifies R2-D2 as the hero of the Star Wars Saga\", assertion => {\n    let query = {|\n      query HeroNameQuery {\n        hero {\n          name\n        }\n      }\n    |};\n\n    let expected =\n      okResponse(`Object([(\"hero\", `Object([(\"name\", `String(\"R2-D2\"))]))]))\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n\n  testAsync(\"Allows us to query for the ID and friends of R2-D2\", assertion => {\n    let query = {|\n        query HeroNameAndFriendsQuery {\n          hero {\n            id\n            name\n            friends {\n              name\n            }\n          }\n        }\n    |};\n\n    let expected =\n      okResponse(\n        `Object([\n          (\n            \"hero\",\n            `Object([\n              (\"id\", `Int(2001)),\n              (\"name\", `String(\"R2-D2\")),\n              (\n                \"friends\",\n                `List([\n                  `Object([(\"name\", `String(\"Luke Skywalker\"))]),\n                  `Object([(\"name\", `String(\"Han Solo\"))]),\n                  `Object([(\"name\", `String(\"Leia Organa\"))]),\n                ]),\n              ),\n            ]),\n          ),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n});\n\ndescribe(\"Nested Queries\", () =>\n  testAsync(\"Allows us to query for the friends of friends of R2-D2\", assertion => {\n    let query = {|\n      query NestedQuery {\n        hero {\n          name\n          friends {\n            name\n            appearsIn\n            friends {\n              name\n            }\n          }\n        }\n      }\n    |};\n\n    let expected =\n      okResponse(\n        `Object([\n          (\n            \"hero\",\n            `Object([\n              (\"name\", `String(\"R2-D2\")),\n              (\n                \"friends\",\n                `List([\n                  `Object([\n                    (\"name\", `String(\"Luke Skywalker\")),\n                    (\n                      \"appearsIn\",\n                      `List([`String(\"NEWHOPE\"), `String(\"EMPIRE\"), `String(\"JEDI\")]),\n                    ),\n                    (\n                      \"friends\",\n                      `List([\n                        `Object([(\"name\", `String(\"Han Solo\"))]),\n                        `Object([(\"name\", `String(\"Leia Organa\"))]),\n                        `Object([(\"name\", `String(\"C-3PO\"))]),\n                        `Object([(\"name\", `String(\"R2-D2\"))]),\n                      ]),\n                    ),\n                  ]),\n                  `Object([\n                    (\"name\", `String(\"Han Solo\")),\n                    (\n                      \"appearsIn\",\n                      `List([`String(\"NEWHOPE\"), `String(\"EMPIRE\"), `String(\"JEDI\")]),\n                    ),\n                    (\n                      \"friends\",\n                      `List([\n                        `Object([(\"name\", `String(\"Luke Skywalker\"))]),\n                        `Object([(\"name\", `String(\"Leia Organa\"))]),\n                        `Object([(\"name\", `String(\"R2-D2\"))]),\n                      ]),\n                    ),\n                  ]),\n                  `Object([\n                    (\"name\", `String(\"Leia Organa\")),\n                    (\n                      \"appearsIn\",\n                      `List([`String(\"NEWHOPE\"), `String(\"EMPIRE\"), `String(\"JEDI\")]),\n                    ),\n                    (\n                      \"friends\",\n                      `List([\n                        `Object([(\"name\", `String(\"Luke Skywalker\"))]),\n                        `Object([(\"name\", `String(\"Han Solo\"))]),\n                        `Object([(\"name\", `String(\"C-3PO\"))]),\n                        `Object([(\"name\", `String(\"R2-D2\"))]),\n                      ]),\n                    ),\n                  ]),\n                ]),\n              ),\n            ]),\n          ),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  })\n);\n\ndescribe(\"Mutation operation\", () => {\n  open Expect;\n\n  let mutation = {|\n    mutation MyMutation($id: Int!, $name: String!, $appearsIn: String){\n      updateCharacterName(characterId: $id, name: $name, appearsIn: $appearsIn) {\n        character {\n          id\n          name\n        }\n        error\n      }\n    }\n  |};\n\n  let variables =\n    \"{\\\"id\\\": 1000, \\\"name\\\": \\\"Sikan Skywalker\\\"}\"\n    ->Js.Json.parseExn\n    ->Graphql_Json.toVariables\n    ->Belt.Result.getExn;\n\n  let result =\n    schema\n    |> Schema.execute(\n         _,\n         ~document=Parser.parse(mutation)->Belt.Result.getExn,\n         ~ctx=(),\n         ~variables,\n       )\n    |> Schema.resultToJson;\n\n  testAsync(\"returns the right data\", assertion => {\n    let expected =\n      okResponse(\n        `Object([\n          (\n            \"updateCharacterName\",\n            `Object([\n              (\n                \"character\",\n                `Object([(\"id\", `Int(1000)), (\"name\", `String(\"Sikan Skywalker\"))]),\n              ),\n              (\"error\", `Null),\n            ]),\n          ),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    Schema.Io.map(result, res => assertion(expect(res) |> toEqual(expected)))->ignore;\n  });\n});\n\ndescribe(\"Using aliases to change the key in the response\", () => {\n  open Expect;\n\n  testAsync(\"Allows us to query for Luke, changing his key with an alias\", assertion => {\n    let query = {|\n      query FetchLukeAliased {\n        luke: human(id: 1000) {\n          name\n        }\n      }\n    |};\n\n    let expected =\n      okResponse(`Object([(\"luke\", `Object([(\"name\", `String(\"Luke Skywalker\"))]))]))\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n\n  testAsync(\n    \"Allows us to query for both Luke and Leia, using two root fields and an alias\", assertion => {\n    let query = {|\n      query FetchLukeAndLeiaAliased {\n        luke: human(id: 1000) {\n          name\n        }\n        leia: human(id: 1003) {\n          name\n        }\n      }\n    |};\n\n    let expected =\n      okResponse(\n        `Object([\n          (\"luke\", `Object([(\"name\", `String(\"Luke Skywalker\"))])),\n          (\"leia\", `Object([(\"name\", `String(\"Leia Organa\"))])),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n});\n\ndescribe(\"Uses fragments to express more complex queries\", () => {\n  open Expect;\n\n  testAsync(\"Allows us to query using duplicated content\", assertion => {\n    let query = {|\n      query DuplicateFields {\n        luke: human(id: 1000) {\n          name\n          homePlanet\n        }\n        leia: human(id: 1003) {\n          name\n          homePlanet\n        }\n      }\n    |};\n\n    let expected =\n      okResponse(\n        `Object([\n          (\n            \"luke\",\n            `Object([\n              (\"name\", `String(\"Luke Skywalker\")),\n              (\"homePlanet\", `String(\"Tatooine\")),\n            ]),\n          ),\n          (\n            \"leia\",\n            `Object([(\"name\", `String(\"Leia Organa\")), (\"homePlanet\", `String(\"Alderaan\"))]),\n          ),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n\n  testAsync(\"Allows us to use a fragment to avoid duplicating content\", assertion => {\n    let query = {|\n    query UseFragment {\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    let schema = StarWarsSchema.schema;\n\n    let expected =\n      okResponse(\n        `Object([\n          (\n            \"luke\",\n            `Object([\n              (\"name\", `String(\"Luke Skywalker\")),\n              (\"homePlanet\", `String(\"Tatooine\")),\n            ]),\n          ),\n          (\n            \"leia\",\n            `Object([(\"name\", `String(\"Leia Organa\")), (\"homePlanet\", `String(\"Alderaan\"))]),\n          ),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n\n  testAsync(\"Allows us to use __typename to get a containing object's type name\", assertion => {\n    let query = {|\n    query UseFragment {\n      luke: human(id: 1000) {\n        __typename\n      }\n    }\n  |};\n\n    let schema = StarWarsSchema.schema;\n\n    let expected =\n      okResponse(`Object([(\"luke\", `Object([(\"__typename\", `String(\"Human\"))]))]))\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  });\n});\n\ndescribe(\"introspection query\", () => {\n  testAsync(\"should reply with queries, mutations, and subscriptions\", assertion => {\n    let query = {|\n      query IntrospectionQuery {\n        __schema {\n          queryType {\n            name\n            fields {\n              name\n            }\n          }\n          mutationType {\n            name\n            fields {\n              name\n            }\n          }\n          subscriptionType {\n            name\n            fields {\n              name\n            }\n          }\n        }\n      }\n    |};\n\n    let expected =\n      okResponse(\n        `Object([\n          (\n            \"__schema\",\n            `Object([\n              (\n                \"queryType\",\n                `Object([\n                  (\"name\", `String(\"Query\")),\n                  (\n                    \"fields\",\n                    `List([\n                      `Object([(\"name\", `String(\"hero\"))]),\n                      `Object([(\"name\", `String(\"human\"))]),\n                      `Object([(\"name\", `String(\"droid\"))]),\n                    ]),\n                  ),\n                ]),\n              ),\n              (\n                \"mutationType\",\n                `Object([\n                  (\"name\", `String(\"Mutation\")),\n                  (\"fields\", `List([`Object([(\"name\", `String(\"updateCharacterName\"))])])),\n                ]),\n              ),\n              (\"subscriptionType\", `Null),\n            ]),\n          ),\n        ]),\n      )\n      |> Graphql_Json.fromConstValue;\n\n    schema\n    ->Schema.execute(~document=Parser.parse(query)->Belt.Result.getExn, ~ctx=())\n    ->Schema.resultToJson\n    ->Schema.Io.map(res => assertion(expect(res) |> toEqual(expected)))\n    ->ignore;\n  })\n});\n"
  },
  {
    "path": "reason-graphql/bsconfig.json",
    "content": "{\n  \"name\": \"reason-graphql\",\n  \"version\": \"0.6.1\",\n  \"sources\": [\n    {\n      \"dir\": \"src\",\n      \"subdirs\": true\n    },\n    {\n      \"dir\": \"__tests__\",\n      \"type\": \"dev\",\n      \"subdirs\": true\n    }\n  ],\n  \"package-specs\": {\n    \"module\": \"commonjs\",\n    \"in-source\": true\n  },\n  \"suffix\": \".bs.js\",\n  \"bs-dependencies\": [],\n  \"bs-dev-dependencies\": [\"@glennsl/bs-jest\"],\n  \"ppx-flags\": [\"bs-let/ppx\"],\n  \"warnings\": {\n    \"number\": \"-45-44-30\",\n    \"error\": \"+101\"\n  },\n  \"namespace\": false,\n  \"refmt\": 3\n}\n"
  },
  {
    "path": "reason-graphql/package.json",
    "content": "{\n  \"name\": \"reason-graphql\",\n  \"version\": \"0.6.1\",\n  \"author\": \"Sikan He\",\n  \"license\": \"MIT\",\n  \"repository\": \"https://github.com/sikanhe/reason-graphql\",\n  \"homepage\": \"https://github.com/sikanhe/reason-graphql#readme\",\n  \"keywords\": [\n    \"BuckleScript\",\n    \"GraphQL\",\n    \"Reason\",\n    \"ReasonML\"\n  ],\n  \"scripts\": {\n    \"build\": \"bsb -make-world\",\n    \"start\": \"bsb -make-world -w\",\n    \"clean\": \"bsb -clean-world\",\n    \"test\": \"yarn build && jest\"\n  },\n  \"files\": [\n    \"src/\",\n    \"bsconfig.json\"\n  ],\n  \"jest\": {\n    \"testMatch\": [\n      \"**/?(*_)(spec|test).bs.js?(x)\"\n    ]\n  },\n  \"devDependencies\": {\n    \"@glennsl/bs-jest\": \"^0.4.9\",\n    \"bs-platform\": \"^8.2.0\"\n  },\n  \"dependencies\": {\n    \"bs-let\": \"^0.1.11\"\n  }\n}\n"
  },
  {
    "path": "reason-graphql/src/Graphql.re",
    "content": "module Schema = Graphql_Schema;\nmodule Language = Graphql_Language;\nmodule Json = Graphql_Json;\nmodule Interface = Graphql_Interface;\n"
  },
  {
    "path": "reason-graphql/src/Graphql_Interface.re",
    "content": "module type IO = {\n  type t(+'a);\n  let return: 'a => t('a);\n  let bind: (t('a), 'a => t('b)) => t('b);\n  let map: (t('a), 'a => 'b) => t('b);\n};\n\nmodule type Schema = {\n  module Io: IO;\n\n  type variableList = list((string, Graphql_Language.Ast.constValue));\n\n  type deprecation =\n    | NotDeprecated\n    | Deprecated(option(string));\n  type enumValue('a) = {\n    name: string,\n    description: option(string),\n    deprecated: deprecation,\n    value: 'a,\n  };\n  type enum('a) = {\n    name: string,\n    description: option(string),\n    values: list(enumValue('a)),\n  };\n  module Arg: {\n    type arg(_) =\n      | Arg(argument('a)): arg('a)\n      | DefaultArg(argumentWithDefault('a)): arg('a)\n    and argTyp(_) =\n      | Scalar(scalar('a)): argTyp(option('a))\n      | Enum(enum('a)): argTyp(option('a))\n      | InputObject(inputObject('a, 'b)): argTyp(option('a))\n      | List(argTyp('a)): argTyp(option(array('a)))\n      | NonNull(argTyp(option('a))): argTyp('a)\n    and scalar('a) = {\n      name: string,\n      description: option(string),\n      parse: Graphql_Language.Ast.constValue => result('a, string),\n    }\n    and inputObject('a, 'b) = {\n      name: string,\n      description: option(string),\n      fields: arglist('a, 'b),\n      coerce: 'b,\n    }\n    and argument('a) = {\n      name: string,\n      description: option(string),\n      typ: argTyp('a),\n    }\n    and argumentWithDefault('a) = {\n      name: string,\n      description: option(string),\n      typ: argTyp(option('a)),\n      default: 'a,\n    }\n    and arglist(_, _) =\n      | []: arglist('a, 'a)\n      | ::(arg('a), arglist('b, 'c)): arglist('b, 'a => 'c);\n    let arg: (~description: string=?, string, argTyp('a)) => arg('a);\n    let defaultArg:\n      (~description: string=?, ~default: 'a, string, argTyp(option('a))) =>\n      arg('a);\n    let string: argTyp(option(string));\n    let int: argTyp(option(int));\n    let float: argTyp(option(float));\n    let boolean: argTyp(option(bool));\n    let list: argTyp('a) => argTyp(option(array('a)));\n    let nonnull: argTyp(option('a)) => argTyp('a);\n  };\n  type typ(_, _) =\n    | Scalar(scalar('src)): typ('ctx, option('src))\n    | Enum(enum('src)): typ('ctx, option('src))\n    | List(typ('ctx, 'src)): typ('ctx, option(array('src)))\n    | Object(obj('ctx, 'src)): typ('ctx, option('src))\n    | Abstract(abstract): typ('ctx, option(abstractValue('ctx, 'a)))\n    | NonNull(typ('ctx, option('src))): typ('ctx, 'src)\n  and scalar('src) = {\n    name: string,\n    description: option(string),\n    serialize: 'src => Graphql_Language.Ast.constValue,\n  }\n  and obj('ctx, 'src) = {\n    name: string,\n    description: option(string),\n    fields: Lazy.t(list(field('ctx, 'src))),\n    abstracts: ref(list(abstract)),\n  }\n  and field(_, _) =\n    | Field(fieldDefinition('src, 'out, 'ctx, 'a, 'args)): field('ctx, 'src)\n  and fieldDefinition('src, 'out, 'ctx, 'a, 'args) = {\n    name: string,\n    description: option(string),\n    deprecated: deprecation,\n    typ: typ('ctx, 'out),\n    args: Arg.arglist('a, 'args),\n    resolve: ('ctx, 'src) => 'args,\n    lift: 'a => Io.t(result('out, string)),\n  }\n  and anyTyp =\n    | AnyTyp(typ('a, 'b)): anyTyp\n    | AnyArgTyp(Arg.argTyp('c)): anyTyp\n  and abstract = {\n    name: string,\n    description: option(string),\n    mutable types: list(anyTyp),\n    kind: [ | `Interface(Lazy.t(list(abstractField))) | `Union],\n  }\n  and abstractField =\n    | AbstractField(field('a, 'b)): abstractField\n  and abstractValue('ctx, 'a) =\n    | AbstractValue((typ('ctx, option('src)), 'src))\n      : abstractValue('ctx, 'a);\n  type abstractType('ctx, 'a) = typ('ctx, option(abstractValue('ctx, 'a)));\n  type directiveLocation = [\n    | `Field\n    | `FragmentDefinition\n    | `FragmentSpread\n    | `InlineFragment\n    | `Mutation\n    | `Query\n    | `Subscription\n    | `VariableDefinition\n  ];\n  type directiveInfo('args) = {\n    name: string,\n    description: option(string),\n    locations: list(directiveLocation),\n    args: Arg.arglist([ | `Include | `Skip], 'args),\n    resolve: 'args,\n  };\n  type directive =\n    | Directive(directiveInfo('args)): directive;\n  let skipDirective: directive;\n  let includeDirective: directive;\n  type schema('ctx) = {\n    query: obj('ctx, unit),\n    mutation: option(obj('ctx, unit)),\n  };\n  type combinedEnum('ctx, 'a) = {\n    argTyp: Arg.argTyp('a),\n    fieldType: typ('ctx, 'a),\n  };\n  let makeEnum:\n    (string, ~description: string=?, list(enumValue('a))) =>\n    combinedEnum('b, option('a));\n  let enumValue:\n    (~description: string=?, ~deprecated: deprecation=?, ~value: 'a, string) =>\n    enumValue('a);\n  let obj:\n    (\n      ~description: string=?,\n      ~implements: ref(list(abstract))=?,\n      ~fields: typ('a, option('b)) => list(field('a, 'b)),\n      string\n    ) =>\n    typ('a, option('b));\n  let field:\n    (\n      ~description: string=?,\n      ~deprecated: deprecation=?,\n      ~args: Arg.arglist('a, 'b),\n      ~resolve: ('c, 'd) => 'b,\n      string,\n      typ('c, 'a)\n    ) =>\n    field('c, 'd);\n  let async_field:\n    (\n      ~description: string=?,\n      ~deprecated: deprecation=?,\n      ~args: Arg.arglist(Io.t(result('a, string)), 'b),\n      ~resolve: ('c, 'd) => 'b,\n      string,\n      typ('c, 'a)\n    ) =>\n    field('c, 'd);\n  let abstractField:\n    (\n      ~description: string=?,\n      ~deprecated: deprecation=?,\n      ~args: Arg.arglist('a, 'b),\n      string,\n      typ('c, 'a)\n    ) =>\n    abstractField;\n  let union:\n    (~description: string=?, string) =>\n    typ('a, option(abstractValue('a, 'b)));\n  let interface:\n    (\n      ~description: string=?,\n      ~fields: typ('a, option(abstractValue('a, 'b))) =>\n               list(abstractField),\n      string\n    ) =>\n    typ('a, option(abstractValue('a, 'b)));\n  let addType:\n    (typ('a, option(abstractValue('a, 'b))), typ('c, option('d)), 'd) =>\n    abstractValue('c, 'e);\n  let query: list(field('ctx, unit)) => obj('ctx, unit);\n  let mutation: list(field('ctx, unit)) => obj('ctx, unit);\n  let create: (~mutation: obj('a, unit)=?, obj('a, unit)) => schema('a);\n  let string: typ('ctx, option(string));\n  let int: typ('ctx, option(int));\n  let float: typ('ctx, option(float));\n  let boolean: typ('ctx, option(bool));\n  let list: typ('a, 'b) => typ('a, option(array('b)));\n  let nonnull: typ('a, option('b)) => typ('a, 'b);\n\n  type path = list(string);\n  \n  type error = (string, path);\n\n  type resolveError = [\n    | `ArgumentError(string)\n    | `ResolveError(error)\n    | `ValidationError(string)\n  ];\n  type executeError = [\n    | `ArgumentError(string)\n    | `MutationsNotConfigured\n    | `NoOperationFound\n    | `OperationNameRequired\n    | `OperationNotFound\n    | `ResolveError(error)\n    | `SubscriptionsNotConfigured\n    | `ValidationError(string)\n  ];\n\n  let execute:\n    (\n      ~variables: variableList=?,\n      ~document: Graphql_Language.Ast.document,\n      schema('ctx),\n      ~ctx: 'ctx\n    ) =>\n    Io.t(Graphql_Language.Ast.constValue);\n    \n  let resultToJson: Io.t(Graphql_Language.Ast.constValue) => Io.t(Js.Json.t);\n};\n"
  },
  {
    "path": "reason-graphql/src/Graphql_Json.re",
    "content": "let rec fromConstValue: Graphql_Language_Ast.constValue => Js.Json.t =\n  fun\n  | `String(string)\n  | `Enum(string) => Js.Json.string(string)\n  | `Float(float) => Js.Json.number(float)\n  | `Int(int) => Js.Json.number(float_of_int(int))\n  | `Boolean(bool) => Js.Json.boolean(bool)\n  | `List(list) =>\n    Belt.List.map(list, item => fromConstValue(item)) |> Belt.List.toArray |> Js.Json.array\n  | `Object(rows) => {\n      let dict =\n        Belt.List.reduceReverse(\n          rows,\n          Js.Dict.empty(),\n          (dict, (name, value)) => {\n            Js.Dict.set(dict, name, fromConstValue(value));\n            dict;\n          },\n        );\n      Js.Json.object_(dict);\n    }\n  | `Null => Js.Json.null;\n\nlet rec toConstValue = (json: Js.Json.t): Graphql_Language_Ast.constValue =>\n  switch (Js.Json.classify(json)) {\n  | JSONString(value) => `String(value)\n  | JSONNumber(num) when Js.Math.floor_float(num) == num => `Int(int_of_float(num))\n  | JSONNumber(num) => `Float(num)\n  | JSONTrue => `Boolean(true)\n  | JSONFalse => `Boolean(false)\n  | JSONNull => `Null\n  | JSONArray(array) =>\n    `List(Belt.Array.map(array, item => toConstValue(item)) |> Belt.List.fromArray)\n  | JSONObject(dict) =>\n    `Object(\n      Js.Dict.entries(dict)\n      ->Belt.Array.map(((k, v)) => (k, toConstValue(v)))\n      ->Belt.List.fromArray,\n    )\n  };\n\nlet toVariables =\n    (json: Js.Json.t): Belt.Result.t(list((string, Graphql_Language_Ast.constValue)), string) => {\n  switch (Js.Json.classify(json)) {\n  | JSONObject(dict) =>\n    Ok(\n      Js.Dict.entries(dict)\n      ->Belt.Array.map(((k, v)) => (k, toConstValue(v)))\n      ->Belt.List.fromArray\n    )\n  | _ => Error(\"Variables must be a JSON object\")\n  };\n};"
  },
  {
    "path": "reason-graphql/src/Graphql_Schema.re",
    "content": "open Graphql_Language;\n\nmodule Result = Belt.Result;\nmodule Option = Belt.Option;\n\nmodule List = {\n  include Belt.List;\n\n  module Result = {\n    include Belt.Result;\n\n    let rec join = (~memo=[]) =>\n      fun\n      | [] => Ok(Belt.List.reverse(memo))\n      | [Error(_) as err, ..._] => err\n      | [Ok(x), ...xs] => join(~memo=[x, ...memo], xs);\n\n    let all = (list, f) => Belt.List.map(list, f) |> join;\n  };\n};\n\nmodule StringMap = Belt.Map.String;\nmodule StringSet = Set.Make(String);\n\ntype variableMap = StringMap.t(Ast.constValue);\ntype fragmentMap = StringMap.t(Ast.fragmentDefinition);\n\nmodule type IO = {\n  type t(+'a);\n  let return: 'a => t('a);\n  let bind: (t('a), 'a => t('b)) => t('b);\n};\n\nlet id: 'a. 'a => 'a = x => x;\n\nmodule Make = (Io: IO) => {\n  open Result;\n\n  module Io = {\n    include Io;\n\n    let ok = x => return(Ok(x));\n    let error = x => return(Error(x));\n    let map = (x, f) => bind(x, x' => return(f(x')));\n\n    let rec all =\n      fun\n      | [] => return([])\n      | [x, ...xs] => bind(all(xs), xs' => map(x, x' => [x', ...xs']));\n\n    module Result = {\n      let bind = (x, f) =>\n        bind(\n          x,\n          fun\n          | Ok(x') => f(x')\n          | Error(_) as err => return(err),\n        );\n\n      let mapError = (x, f) =>\n        map(\n          x,\n          fun\n          | Ok(_) as ok => ok\n          | Error(err) => Error(f(err)),\n        );\n\n      let map = (x, f) =>\n        map(\n          x,\n          fun\n          | Ok(x') => Ok(f(x'))\n          | Error(_) as err => err,\n        );\n\n      let let_ = bind;\n    };\n\n    let rec mapSerial = (~memo=[], list, f) =>\n      switch (list) {\n      | [] => Io.return(List.reverse(memo))\n      | [x, ...xs] => bind(f(x), x' => mapSerial(~memo=[x', ...memo], xs, f))\n      };\n\n    let mapParalell = (list, f) => list->List.map(f)->all;\n\n    let let_ = bind;\n  };\n\n  type variableList = list((string, Ast.constValue));\n\n  type deprecation =\n    | NotDeprecated\n    | Deprecated(option(string));\n\n  type enumValue('a) = {\n    name: string,\n    description: option(string),\n    deprecated: deprecation,\n    value: 'a,\n  };\n\n  type enum('a) = {\n    name: string,\n    description: option(string),\n    values: list(enumValue('a)),\n  };\n\n  module Arg = {\n    type arg(_) =\n      | Arg(argument('a)): arg('a)\n      | DefaultArg(argumentWithDefault('a)): arg('a)\n    and argTyp(_) =\n      | Scalar(scalar('a)): argTyp(option('a))\n      | Enum(enum('a)): argTyp(option('a))\n      | InputObject(inputObject('a, 'b)): argTyp(option('a))\n      | List(argTyp('a)): argTyp(option(array('a)))\n      | NonNull(argTyp(option('a))): argTyp('a)\n    and scalar('a) = {\n      name: string,\n      description: option(string),\n      parse: Ast.constValue => Result.t('a, string),\n    }\n    and inputObject('a, 'b) = {\n      name: string,\n      description: option(string),\n      fields: arglist('a, 'b),\n      coerce: 'b,\n    }\n    and argument('a) = {\n      name: string,\n      description: option(string),\n      typ: argTyp('a),\n    }\n    and argumentWithDefault('a) = {\n      name: string,\n      description: option(string),\n      typ: argTyp(option('a)),\n      default: 'a,\n    }\n    and arglist(_, _) =\n      | []: arglist('a, 'a)\n      | ::(arg('a), arglist('b, 'c)): arglist('b, 'a => 'c);\n\n    let arg = (~description=?, name, typ) => Arg({name, typ, description});\n\n    let defaultArg = (~description=?, ~default, name, typ) =>\n      DefaultArg({name, typ, description, default});\n\n    /* Built in scalars */\n\n    let string =\n      Scalar({\n        name: \"String\",\n        description: None,\n\n        parse: input =>\n          switch (input) {\n          | `String(str) => Ok(str)\n          | _ => Error(\"Invalid string\")\n          },\n      });\n\n    let int =\n      Scalar({\n        name: \"Int\",\n        description: None,\n        parse: input =>\n          switch (input) {\n          | `Int(int) => Ok(int)\n          | _ => Error(\"Invalid integer\")\n          },\n      });\n\n    let float =\n      Scalar({\n        name: \"Float\",\n        description: None,\n        parse: input =>\n          switch (input) {\n          | `Float(float) => Ok(float)\n          | _ => Error(\"Invalid float\")\n          },\n      });\n\n    let boolean =\n      Scalar({\n        name: \"Boolean\",\n        description: None,\n        parse: input =>\n          switch (input) {\n          | `Boolean(bool) => Ok(bool)\n          | _ => Error(\"Invalid boolean\")\n          },\n      });\n\n    let list = a => List(a);\n    let nonnull = a => NonNull(a);\n  };\n\n  type typ(_, _) =\n    | Scalar(scalar('src)): typ('ctx, option('src))\n    | Enum(enum('src)): typ('ctx, option('src))\n    | List(typ('ctx, 'src)): typ('ctx, option(array('src)))\n    | Object(obj('ctx, 'src)): typ('ctx, option('src))\n    | Abstract(abstract): typ('ctx, option(abstractValue('ctx, 'a)))\n    | NonNull(typ('ctx, option('src))): typ('ctx, 'src)\n  and scalar('src) = {\n    name: string,\n    description: option(string),\n    serialize: 'src => Ast.constValue,\n  }\n  and obj('ctx, 'src) = {\n    name: string,\n    description: option(string),\n    fields: Lazy.t(list(field('ctx, 'src))),\n    abstracts: ref(list(abstract)),\n  }\n  and field(_, _) =\n    | Field(fieldDefinition('src, 'out, 'ctx, 'a, 'args)): field('ctx, 'src)\n  and fieldDefinition('src, 'out, 'ctx, 'a, 'args) = {\n    name: string,\n    description: option(string),\n    deprecated: deprecation,\n    typ: typ('ctx, 'out),\n    args: Arg.arglist('a, 'args),\n    resolve: ('ctx, 'src) => 'args,\n    lift: 'a => Io.t(Result.t('out, string)),\n  }\n  and anyTyp =\n    | AnyTyp(typ(_, _)): anyTyp\n    | AnyArgTyp(Arg.argTyp(_)): anyTyp\n  and abstract = {\n    name: string,\n    description: option(string),\n    mutable types: list(anyTyp),\n    kind: [ | `Union | `Interface(Lazy.t(list(abstractField)))],\n  }\n  and abstractField =\n    | AbstractField(field(_, _)): abstractField\n  and abstractValue('ctx, 'a) =\n    | AbstractValue((typ('ctx, option('src)), 'src)): abstractValue('ctx, 'a);\n\n  type abstractType('ctx, 'a) = typ('ctx, option(abstractValue('ctx, 'a)));\n\n  type directiveLocation = [\n    | `Query\n    | `Mutation\n    | `Subscription\n    | `Field\n    | `FragmentDefinition\n    | `FragmentSpread\n    | `InlineFragment\n    | `VariableDefinition\n  ];\n\n  type directiveInfo('args) = {\n    name: string,\n    description: option(string),\n    locations: list(directiveLocation),\n    args: Arg.arglist([ | `Skip | `Include], 'args),\n    resolve: 'args,\n  };\n\n  type directive =\n    | Directive(directiveInfo('args)): directive;\n\n  let skipDirective =\n    Directive({\n      name: \"skip\",\n      description:\n        Some(\n          \"Directs the executor to skip this field or fragment when the `if` argument is true.\",\n        ),\n      locations: [`Field, `FragmentSpread, `InlineFragment],\n      args: Arg.[arg(\"if\", nonnull(boolean), ~description=\"Skipped when true.\")],\n      resolve:\n        fun\n        | true => `Skip\n        | false => `Include,\n    });\n\n  let includeDirective =\n    Directive({\n      name: \"include\",\n      description:\n        Some(\n          \"Directs the executor to include this field or fragment only when the `if` argument is true.\",\n        ),\n      locations: [`Field, `FragmentSpread, `InlineFragment],\n      args: Arg.[arg(\"if\", nonnull(boolean), ~description=\"Included when true.\")],\n      resolve:\n        fun\n        | true => `Include\n        | false => `Skip,\n    });\n\n  type schema('ctx) = {\n    query: obj('ctx, unit),\n    mutation: option(obj('ctx, unit)),\n  };\n\n  type combinedEnum('ctx, 'a) = {\n    argTyp: Arg.argTyp('a),\n    fieldType: typ('ctx, 'a),\n  };\n\n  let makeEnum = (name, ~description=?, values) => {\n    argTyp: Arg.Enum({name, description, values}),\n    fieldType: Enum({name, description, values}),\n  };\n\n  let enumValue = (~description=?, ~deprecated=NotDeprecated, ~value, name) => {\n    name,\n    description,\n    deprecated,\n    value,\n  };\n\n  let obj = (~description=?, ~implements: ref(list(abstract))=ref([]), ~fields, name) => {\n    let rec self =\n      Object({name, description, fields: lazy(fields(self)), abstracts: implements});\n    self;\n  };\n\n  let field = (~description=?, ~deprecated=NotDeprecated, ~args, ~resolve, name, typ) =>\n    Field({name, typ, resolve, deprecated, description, args, lift: Io.ok});\n\n  let async_field = (~description=?, ~deprecated=NotDeprecated, ~args, ~resolve, name, typ) =>\n    Field({name, typ, resolve, deprecated, description, args, lift: id});\n\n  let abstractField = (~description=?, ~deprecated=NotDeprecated, ~args, name, typ) =>\n    AbstractField(\n      Field({lift: Io.ok, name, description, deprecated, typ, args, resolve: Obj.magic()}),\n    );\n\n  let union = (~description=?, name) => Abstract({name, description, types: [], kind: `Union});\n\n  let interface = (~description=?, ~fields, name) => {\n    let rec t = Abstract({name, description, types: [], kind: `Interface(lazy(fields(t)))});\n    t;\n  };\n\n  let addType = (abstractType, typ) => {\n    switch (abstractType, typ) {\n    | (Abstract(a), Object(o)) =>\n      a.types = [AnyTyp(typ), ...a.types];\n      o.abstracts := [a, ...o.abstracts^];\n      (src => AbstractValue((typ, src)));\n    | _ => invalid_arg(\"Arguments must be Interface/Union and Object\")\n    };\n  };\n\n  let query = (fields): obj('ctx, unit) => {\n    name: \"Query\",\n    description: None,\n    fields: lazy(fields),\n    abstracts: ref([]),\n  };\n\n  let mutation = (fields): obj('ctx, unit) => {\n    name: \"Mutation\",\n    description: None,\n    fields: lazy(fields),\n    abstracts: ref([]),\n  };\n\n  let create = (~mutation=?, query) => {query, mutation};\n\n  /* Built in scalars */\n  let string: 'ctx. typ('ctx, option(string)) =\n    Scalar({name: \"String\", description: None, serialize: str => `String(str)});\n  let int: 'ctx. typ('ctx, option(int)) =\n    Scalar({name: \"Int\", description: None, serialize: int => `Int(int)});\n  let float: 'ctx. typ('ctx, option(float)) =\n    Scalar({name: \"Float\", description: None, serialize: float => `Float(float)});\n  let boolean: 'ctx. typ('ctx, option(bool)) =\n    Scalar({name: \"Boolean\", description: None, serialize: bool => `Boolean(bool)});\n  let list = typ => List(typ);\n  let nonnull = typ => NonNull(typ);\n\n  module Introspection = {\n    /* anyTyp, anyField and anyArg hide type parameters to avoid scope escaping errors */\n    type anyField =\n      | AnyField(field(_, _)): anyField\n      | AnyArgField(Arg.arg(_)): anyField;\n    type anyArg =\n      | AnyArg(Arg.arg(_)): anyArg;\n    type anyEnumValue =\n      | AnyEnumValue(enumValue(_)): anyEnumValue;\n\n    let unlessVisited = ((result, visited), name, f) =>\n      if (StringSet.mem(name, visited)) {\n        (result, visited);\n      } else {\n        f((result, visited));\n      };\n\n    /* Extracts all types contained in a single type */\n\n\n    let rec types:\n      type ctx src.\n        (~memo: (list(anyTyp), StringSet.t)=?, typ(ctx, src)) => (list(anyTyp), StringSet.t) =\n      (~memo=([], StringSet.empty), typ) =>\n        switch (typ) {\n        | List(typ) => types(~memo, typ)\n        | NonNull(typ) => types(~memo, typ)\n        | Scalar(s) as scalar =>\n          unlessVisited(memo, s.name, ((result, visited)) =>\n            ([AnyTyp(scalar), ...result], StringSet.add(s.name, visited))\n          )\n        | Enum(e) as enum =>\n          unlessVisited(memo, e.name, ((result, visited)) =>\n            ([AnyTyp(enum), ...result], StringSet.add(e.name, visited))\n          )\n        | Object(o) as obj =>\n          unlessVisited(\n            memo,\n            o.name,\n            ((result, visited)) => {\n              let result' = [AnyTyp(obj), ...result];\n              let visited' = StringSet.add(o.name, visited);\n              let reducer = (memo, Field(f)) => {\n                let memo' = types(~memo, f.typ);\n                arg_list_types(memo', f.args);\n              };\n\n              List.reduceReverse(Lazy.force(o.fields), (result', visited'), reducer);\n            },\n          )\n        | Abstract(a) as abstract =>\n          unlessVisited(\n            memo,\n            a.name,\n            ((result, visited)) => {\n              let result' = [AnyTyp(abstract), ...result];\n              let visited' = StringSet.add(a.name, visited);\n              List.reduceReverse(a.types, (result', visited'), (memo, typ) =>\n                switch (typ) {\n                | AnyTyp(typ) => types(~memo, typ)\n                | AnyArgTyp(_) => failwith(\"Abstracts can't have argument types\")\n                }\n              );\n            },\n          )\n        }\n\n    and arg_types:\n      type a. ((list(anyTyp), StringSet.t), Arg.argTyp(a)) => (list(anyTyp), StringSet.t) =\n      (memo, argtyp) =>\n        switch (argtyp) {\n        | Arg.List(typ) => arg_types(memo, typ)\n        | Arg.NonNull(typ) => arg_types(memo, typ)\n        | Arg.Scalar(s) as scalar =>\n          unlessVisited(memo, s.name, ((result, visited)) =>\n            ([AnyArgTyp(scalar), ...result], StringSet.add(s.name, visited))\n          )\n        | Arg.Enum(e) as enum =>\n          unlessVisited(memo, e.name, ((result, visited)) =>\n            ([AnyArgTyp(enum), ...result], StringSet.add(e.name, visited))\n          )\n        | Arg.InputObject(o) as obj =>\n          unlessVisited(\n            memo,\n            o.name,\n            ((result, visited)) => {\n              let memo' = ([AnyArgTyp(obj), ...result], StringSet.add(o.name, visited));\n              arg_list_types(memo', o.fields);\n            },\n          )\n        }\n\n    and arg_list_types:\n      type a b.\n        ((list(anyTyp), StringSet.t), Arg.arglist(a, b)) => (list(anyTyp), StringSet.t) =\n      (memo, arglist) =>\n        Arg.(\n          switch (arglist) {\n          | [] => memo\n          | [arg, ...args] =>\n            let memo' =\n              switch (arg) {\n              | Arg(a) => arg_types(memo, a.typ)\n              | DefaultArg(a) => arg_types(memo, a.typ)\n              };\n            arg_list_types(memo', args);\n          }\n        );\n\n    let rec args_to_list: type a b. (~memo: list(anyArg)=?, Arg.arglist(a, b)) => list(anyArg) =\n      (~memo=[], arglist) =>\n        Arg.(\n          switch (arglist) {\n          | [] => memo\n          | [arg, ...args] =>\n            let arg = AnyArg(arg);\n            let memo': list(anyArg) = [arg, ...memo];\n            args_to_list(~memo=memo', args);\n          }\n        );\n\n    let no_abstracts = ref([]);\n\n    let __type_kind =\n      Enum({\n        name: \"__TypeKind\",\n        description: None,\n        values: [\n          {name: \"SCALAR\", description: None, deprecated: NotDeprecated, value: `Scalar},\n          {name: \"OBJECT\", description: None, deprecated: NotDeprecated, value: `Object},\n          {name: \"INTERFACE\", description: None, deprecated: NotDeprecated, value: `Interface},\n          {name: \"UNION\", description: None, deprecated: NotDeprecated, value: `Union},\n          {name: \"ENUM\", description: None, deprecated: NotDeprecated, value: `Enum},\n          {\n            name: \"INPUT_OBJECT\",\n            description: None,\n            deprecated: NotDeprecated,\n            value: `InputObject,\n          },\n          {name: \"LIST\", description: None, deprecated: NotDeprecated, value: `List},\n          {name: \"NON_NULL\", description: None, deprecated: NotDeprecated, value: `NonNull},\n        ],\n      });\n\n    let __enumValue: 'ctx. typ('ctx, option(anyEnumValue)) =\n      Object({\n        name: \"__EnumValue\",\n        description: None,\n        abstracts: no_abstracts,\n        fields:\n          lazy([\n            Field({\n              name: \"name\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(string),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, AnyEnumValue(enum_value)) => enum_value.name,\n            }),\n            Field({\n              name: \"description\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, AnyEnumValue(enum_value)) => {\n                enum_value.description;\n              },\n            }),\n            Field({\n              name: \"isDeprecated\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(boolean),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, AnyEnumValue(enum_value)) => enum_value.deprecated != NotDeprecated,\n            }),\n            Field({\n              name: \"deprecationReason\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, AnyEnumValue(enum_value)) =>\n                switch (enum_value.deprecated) {\n                | Deprecated(reason) => reason\n                | NotDeprecated => None\n                },\n            }),\n          ]),\n      });\n\n    let rec __input_value: 'ctx. typ('ctx, option(anyArg)) =\n      Object({\n        name: \"__InputValue\",\n        description: None,\n        abstracts: no_abstracts,\n        fields:\n          lazy([\n            Field({\n              name: \"name\",\n              typ: NonNull(string),\n              args: Arg.[],\n              deprecated: NotDeprecated,\n              description: None,\n              lift: Io.ok,\n              resolve: (_, AnyArg(arg)) =>\n                switch (arg) {\n                | Arg.DefaultArg(a) => a.name\n                | Arg.Arg(a) => a.name\n                },\n            }),\n            Field({\n              name: \"description\",\n              typ: string,\n              args: Arg.[],\n              deprecated: NotDeprecated,\n              description: None,\n              lift: Io.ok,\n              resolve: (_, AnyArg(arg)) =>\n                switch (arg) {\n                | Arg.DefaultArg(a) => a.description\n                | Arg.Arg(a) => a.description\n                },\n            }),\n            Field({\n              name: \"type\",\n              typ: NonNull(__type),\n              args: Arg.[],\n              deprecated: NotDeprecated,\n              description: None,\n              lift: Io.ok,\n              resolve: (_, AnyArg(arg)) =>\n                switch (arg) {\n                | Arg.DefaultArg(a) => AnyArgTyp(a.typ)\n                | Arg.Arg(a) => AnyArgTyp(a.typ)\n                },\n            }),\n            Field({\n              name: \"defaultValue\",\n              typ: string,\n              args: Arg.[],\n              deprecated: NotDeprecated,\n              description: None,\n              lift: Io.ok,\n              resolve: (_, AnyArg(_)) => None,\n            }),\n          ]),\n      })\n    and __type: 'ctx. typ('ctx, option(anyTyp)) =\n      Object({\n        name: \"__Type\",\n        description: None,\n        abstracts: no_abstracts,\n        fields:\n          lazy([\n            Field({\n              name: \"kind\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(__type_kind),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Object(_)) => `Object\n                | AnyTyp(Abstract({kind: `Union, _})) => `Union\n                | AnyTyp(Abstract({kind: `Interface(_), _})) => `Interface\n                | AnyTyp(List(_)) => `List\n                | AnyTyp(Scalar(_)) => `Scalar\n                | AnyTyp(Enum(_)) => `Enum\n                | AnyTyp(NonNull(_)) => `NonNull\n                | AnyArgTyp(Arg.InputObject(_)) => `InputObject\n                | AnyArgTyp(Arg.List(_)) => `List\n                | AnyArgTyp(Arg.Scalar(_)) => `Scalar\n                | AnyArgTyp(Arg.Enum(_)) => `Enum\n                | AnyArgTyp(Arg.NonNull(_)) => `NonNull\n                },\n            }),\n            Field({\n              name: \"ofType\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: __type,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(NonNull(typ)) => Some(AnyTyp(typ))\n                | AnyTyp(List(typ)) => Some(AnyTyp(typ))\n                | AnyArgTyp(Arg.NonNull(typ)) => Some(AnyArgTyp(typ))\n                | AnyArgTyp(Arg.List(typ)) => Some(AnyArgTyp(typ))\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"name\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Object(o)) => Some(o.name)\n                | AnyTyp(Scalar(s)) => Some(s.name)\n                | AnyTyp(Enum(e)) => Some(e.name)\n                | AnyTyp(Abstract(a)) => Some(a.name)\n                | AnyArgTyp(Arg.InputObject(o)) => Some(o.name)\n                | AnyArgTyp(Arg.Scalar(s)) => Some(s.name)\n                | AnyArgTyp(Arg.Enum(e)) => Some(e.name)\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"description\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Object(o)) => o.description\n                | AnyTyp(Scalar(s)) => s.description\n                | AnyTyp(Enum(e)) => e.description\n                | AnyTyp(Abstract(a)) => a.description\n                | AnyArgTyp(Arg.InputObject(o)) => o.description\n                | AnyArgTyp(Arg.Scalar(s)) => s.description\n                | AnyArgTyp(Arg.Enum(e)) => e.description\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"fields\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: List(NonNull(__field)),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Object(o)) =>\n                  Some(List.map(Lazy.force(o.fields), f => AnyField(f))->List.toArray)\n                | AnyTyp(Abstract({kind: `Interface(fields), _})) =>\n                  Some(\n                    List.map(Lazy.force(fields), (AbstractField(f)) => AnyField(f))\n                    ->List.toArray,\n                  )\n                | AnyArgTyp(Arg.InputObject(o)) =>\n                  let arg_list = args_to_list(o.fields);\n                  Some(List.map(arg_list, (AnyArg(f)) => AnyArgField(f))->List.toArray);\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"interfaces\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: List(NonNull(__type)),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Object(o)) =>\n                  let interfaces =\n                    List.keep(\n                      o.abstracts^,\n                      fun\n                      | {kind: `Interface(_), _} => true\n                      | _ => false,\n                    );\n                  Some(List.map(interfaces, i => AnyTyp(Abstract(i)))->List.toArray);\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"possibleTypes\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: List(NonNull(__type)),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Abstract(a)) => Some(a.types->List.toArray)\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"inputFields\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: List(NonNull(__input_value)),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyArgTyp(Arg.InputObject(o)) => Some(args_to_list(o.fields)->List.toArray)\n                | _ => None\n                },\n            }),\n            Field({\n              name: \"enumValues\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: List(NonNull(__enumValue)),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, t) =>\n                switch (t) {\n                | AnyTyp(Enum(e)) => Some(List.map(e.values, x => AnyEnumValue(x))->List.toArray)\n                | AnyArgTyp(Arg.Enum(e)) => Some(List.map(e.values, x => AnyEnumValue(x))->List.toArray)\n                | _ => None\n                },\n            }),\n          ]),\n      })\n    and __field: type ctx. typ(ctx, option(anyField)) =\n      Object({\n        name: \"__Field\",\n        description: None,\n        abstracts: no_abstracts,\n        fields:\n          lazy([\n            Field({\n              name: \"name\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(string),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, f) =>\n                switch (f) {\n                | AnyField(Field(f)) => f.name\n                | AnyArgField(Arg.Arg(a)) => a.name\n                | AnyArgField(Arg.DefaultArg(a)) => a.name\n                },\n            }),\n            Field({\n              name: \"description\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, f) =>\n                switch (f) {\n                | AnyField(Field(f)) => f.description\n                | AnyArgField(Arg.Arg(a)) => a.description\n                | AnyArgField(Arg.DefaultArg(a)) => a.description\n                },\n            }),\n            Field({\n              name: \"args\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(List(NonNull(__input_value))),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, f) =>\n                switch (f) {\n                | AnyField(Field(f)) => args_to_list(f.args)->List.toArray\n                | AnyArgField(_) => [||]\n                },\n            }),\n            Field({\n              name: \"type\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(__type),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, f) =>\n                switch (f) {\n                | AnyField(Field(f)) => AnyTyp(f.typ)\n                | AnyArgField(Arg.Arg(a)) => AnyArgTyp(a.typ)\n                | AnyArgField(Arg.DefaultArg(a)) => AnyArgTyp(a.typ)\n                },\n            }),\n            Field({\n              name: \"isDeprecated\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(boolean),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, f) =>\n                switch (f) {\n                | AnyField(Field({deprecated: Deprecated(_), _})) => true\n                | _ => false\n                },\n            }),\n            Field({\n              name: \"deprecationReason\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, f) =>\n                switch (f) {\n                | AnyField(Field({deprecated: Deprecated(reason), _})) => reason\n                | _ => None\n                },\n            }),\n          ]),\n      });\n\n    let __directiveLocation =\n      Enum({\n        name: \"__DirectiveLocation\",\n        description: None,\n        values: [\n          {name: \"QUERY\", description: None, deprecated: NotDeprecated, value: `Query},\n          {name: \"MUTATION\", description: None, deprecated: NotDeprecated, value: `Mutation},\n          {\n            name: \"SUBSCRIPTION\",\n            description: None,\n            deprecated: NotDeprecated,\n            value: `Subscription,\n          },\n          {name: \"FIELD\", description: None, deprecated: NotDeprecated, value: `Field},\n          {\n            name: \"FragmentDefinition\",\n            description: None,\n            deprecated: NotDeprecated,\n            value: `FragmentDefinition,\n          },\n          {\n            name: \"FragmentSpread\",\n            description: None,\n            deprecated: NotDeprecated,\n            value: `FragmentSpread,\n          },\n          {\n            name: \"InlineFragment\",\n            description: None,\n            deprecated: NotDeprecated,\n            value: `InlineFragment,\n          },\n          {\n            name: \"VariableDefinition\",\n            description: None,\n            deprecated: NotDeprecated,\n            value: `VariableDefinition,\n          },\n        ],\n      });\n\n    let __directive =\n      Object({\n        name: \"__Directive\",\n        description: None,\n        abstracts: no_abstracts,\n        fields:\n          lazy([\n            Field({\n              name: \"name\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(string),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, Directive(d)) => d.name,\n            }),\n            Field({\n              name: \"description\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: string,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, Directive(d)) => d.description,\n            }),\n            Field({\n              name: \"locations\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(List(NonNull(__directiveLocation))),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, Directive(d)) => d.locations->List.toArray,\n            }),\n            Field({\n              name: \"args\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(List(NonNull(__input_value))),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, Directive(d)) => args_to_list(d.args)->List.toArray,\n            }),\n          ]),\n      });\n\n    let __schema: 'ctx. typ('ctx, option(schema('ctx))) =\n      Object({\n        name: \"__Schema\",\n        description: None,\n        abstracts: no_abstracts,\n        fields:\n          lazy([\n            Field({\n              name: \"types\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(List(NonNull(__type))),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, s) => {\n                let (types, _) =\n                  List.reduceReverse(\n                    [\n                      Some(s.query),\n                      s.mutation,\n                      // Option.map(s.subscription, ~f=obj_of_subscription_obj),\n                    ],\n                    ([], StringSet.empty),\n                    (memo, op) =>\n                    switch (op) {\n                    | None => memo\n                    | Some(op) => types(~memo, Object(op))\n                    }\n                  );\n                types->List.toArray;\n              },\n            }),\n            Field({\n              name: \"queryType\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(__type),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, s) => AnyTyp(Object(s.query)),\n            }),\n            Field({\n              name: \"mutationType\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: __type,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, s) => Option.map(s.mutation, mut => AnyTyp(Object(mut))),\n            }),\n            Field({\n              name: \"subscriptionType\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: __type,\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, _) => None,\n            }),\n            Field({\n              name: \"directives\",\n              description: None,\n              deprecated: NotDeprecated,\n              typ: NonNull(List(NonNull(__directive))),\n              args: Arg.[],\n              lift: Io.ok,\n              resolve: (_, _) => [||],\n            }),\n          ]),\n      });\n\n    let addSchemaField = schema => {\n      {\n        ...schema,\n        query: {\n          ...schema.query,\n          fields:\n            lazy([\n              Field({\n                name: \"__schema\",\n                typ: NonNull(__schema),\n                args: [],\n                description: None,\n                deprecated: NotDeprecated,\n                lift: Io.ok,\n                resolve: (_, _) => schema,\n              }),\n              ...Lazy.force(schema.query.fields),\n            ]),\n        },\n      };\n    };\n  };\n\n  // Execution\n\n  type executionContext('ctx) = {\n    schema: schema('ctx),\n    operation: Ast.operationDefinition,\n    fragmentMap,\n    variableMap,\n    ctx: 'ctx,\n  };\n\n  type path = list(string);\n  type error = (string, path);\n\n  type resolveError = [\n    | `ResolveError(error)\n    | `ArgumentError(string)\n    | `ValidationError(string)\n  ];\n\n  type executeError = [\n    resolveError\n    | `MutationsNotConfigured\n    | `SubscriptionsNotConfigured\n    | `NoOperationFound\n    | `OperationNameRequired\n    | `OperationNotFound\n  ];\n\n  type executionResult = {data: Ast.constValue};\n\n  module ArgEval = {\n    open Arg;\n\n    let rec valueToConstValue: (variableMap, Ast.value) => Ast.constValue =\n      variableMap =>\n        fun\n        | `Null => `Null\n        | `Int(_) as i => i\n        | `Float(_) as f => f\n        | `String(_) as s => s\n        | `Boolean(_) as b => b\n        | `Enum(_) as e => e\n        | `Variable(v) =>\n          switch (StringMap.get(variableMap, v)) {\n          | Some(value) => value\n          | None => `Null\n          }\n        | `List(xs) => `List(List.map(xs, valueToConstValue(variableMap)))\n        | `Object(props) => {\n            let props' =\n              List.map(props, ((name, value)) =>\n                (name, valueToConstValue(variableMap, value))\n              );\n            `Object(props');\n          };\n\n    let rec stringOfConstValue: Ast.constValue => string = (\n      fun\n      | `Null => \"null\"\n      | `Int(i) => string_of_int(i)\n      | `Float(f) => Js.Float.toString(f)\n      | `String(s) => Printf.sprintf(\"\\\"%s\\\"\", s)\n      | `Boolean(b) => string_of_bool(b)\n      | `Enum(e) => e\n      | `List(l) => {\n          let values = List.map(l, i => stringOfConstValue(i));\n          Printf.sprintf(\"[%s]\", String.concat(\", \", values));\n        }\n      | `Object(a) => {\n          let values =\n            List.map(a, ((k, v)) => Printf.sprintf(\"%s: %s\", k, stringOfConstValue(v)));\n\n          Printf.sprintf(\"{%s}\", String.concat(\", \", values));\n        }:\n        Ast.constValue => string\n    );\n\n    let rec stringOfArgType: type a. argTyp(a) => string =\n      fun\n      | Scalar(a) => Printf.sprintf(\"%s\", a.name)\n      | InputObject(a) => Printf.sprintf(\"%s\", a.name)\n      | Enum(a) => Printf.sprintf(\"%s\", a.name)\n      | List(a) => Printf.sprintf(\"[%s]\", stringOfArgType(a))\n      | NonNull(a) => Printf.sprintf(\"%s!\", stringOfArgType(a));\n\n    let evalArgError = (~fieldType=\"field\", ~fieldName, ~argName, argTyp, value) => {\n      let foundStr =\n        switch (value) {\n        | Some(v) => Printf.sprintf(\"found %s\", stringOfConstValue(v))\n        | None => \"but not provided\"\n        };\n\n      Printf.sprintf(\n        \"Argument `%s` of type `%s` expected on %s `%s`, %s.\",\n        argName,\n        stringOfArgType(argTyp),\n        fieldType,\n        fieldName,\n        foundStr,\n      );\n    };\n\n\n    let rec evalArgList:\n      type a b.\n        (\n          variableMap,\n          ~fieldType: string=?,\n          ~fieldName: string,\n          arglist(a, b),\n          list((string, Ast.value)),\n          b\n        ) =>\n        Result.t(a, string) =\n      (variableMap, ~fieldType=?, ~fieldName, arglist, key_values, f) =>\n        switch (arglist) {\n        | [] => Ok(f)\n        | [DefaultArg(arg), ...arglist'] =>\n          let arglist'' = [\n            Arg({name: arg.name, description: arg.description, typ: arg.typ}),\n            ...arglist',\n          ];\n\n          evalArgList(\n            variableMap,\n            ~fieldType?,\n            ~fieldName,\n            arglist'',\n            key_values,\n            fun\n            | None => f(arg.default)\n            | Some(v) => f(v),\n          );\n        | [Arg(arg), ...arglist'] =>\n          let value = List.getAssoc(key_values, arg.name, (==));\n          let constValue = Option.map(value, valueToConstValue(variableMap));\n          evalArg(variableMap, ~fieldType?, ~fieldName, ~argName=arg.name, arg.typ, constValue)\n          ->Result.flatMap(coerced =>\n              evalArgList(variableMap, ~fieldType?, ~fieldName, arglist', key_values, f(coerced))\n            );\n        }\n\n    and evalArg:\n      type a.\n        (\n          variableMap,\n          ~fieldType: string=?,\n          ~fieldName: string,\n          ~argName: string,\n          argTyp(a),\n          option(Ast.constValue)\n        ) =>\n        Result.t(a, string) =\n      (variableMap, ~fieldType=?, ~fieldName, ~argName, typ, value) =>\n        switch (typ, value) {\n        | (NonNull(_), None) =>\n          Error(evalArgError(~fieldType?, ~fieldName, ~argName, typ, value))\n        | (NonNull(_), Some(`Null)) =>\n          Error(evalArgError(~fieldType?, ~fieldName, ~argName, typ, value))\n        | (Scalar(_), None) => Ok(None)\n        | (Scalar(_), Some(`Null)) => Ok(None)\n        | (InputObject(_), None) => Ok(None)\n        | (InputObject(_), Some(`Null)) => Ok(None)\n        | (List(_), None) => Ok(None)\n        | (List(_), Some(`Null)) => Ok(None)\n        | (Enum(_), None) => Ok(None)\n        | (Enum(_), Some(`Null)) => Ok(None)\n        | (NonNull(typ), Some(value)) =>\n          evalArg(variableMap, ~fieldType?, ~fieldName, ~argName, typ, Some(value))\n          ->Result.flatMap(\n              fun\n              | Some(value) => Ok(value)\n              | None => Error(evalArgError(~fieldType?, ~fieldName, ~argName, typ, None)),\n            )\n        | (Scalar(s), Some(value)) =>\n          switch (s.parse(value)) {\n          | Ok(coerced) => Ok(Some(coerced))\n          | Error(_) => Error(evalArgError(~fieldType?, ~fieldName, ~argName, typ, Some(value)))\n          }\n        | (InputObject(o), Some(value)) =>\n          switch (value) {\n          | `Object((props: list((string, Ast.constValue)))) =>\n            evalArgList(\n              variableMap,\n              ~fieldType?,\n              ~fieldName,\n              o.fields,\n              (props :> list((string, Ast.value))),\n              o.coerce,\n            )\n            ->Result.map(coerced => Some(coerced))\n          | _ => Error(evalArgError(~fieldType?, ~fieldName, ~argName, typ, Some(value)))\n          }\n        | (List(typ), Some(value)) =>\n          switch (value) {\n          | `List(values) =>\n            let optionValues = List.map(values, x => Some(x));\n            List.Result.all(\n              optionValues,\n              evalArg(variableMap, ~fieldType?, ~fieldName, ~argName, typ),\n            )\n            ->Result.map(coerced => Some(List.toArray(coerced)));\n          | value =>\n            evalArg(variableMap, ~fieldType?, ~fieldName, ~argName, typ, Some(value))\n            ->Result.map((coerced) => (Some([| coerced |]): a))\n          }\n        | (Enum(enum), Some(value)) =>\n          switch (value) {\n          | `Enum(v)\n          | `String(v) =>\n            switch (Belt.List.getBy(enum.values, enumValue => enumValue.name == v)) {\n            | Some(enumValue) => Ok(Some(enumValue.value))\n            | None =>\n              Error(\n                Printf.sprintf(\n                  \"Invalid enum value for argument `%s` on field `%s`\",\n                  argName,\n                  fieldName,\n                ),\n              )\n            }\n          | _ =>\n            Error(\n              Printf.sprintf(\"Expected enum for argument `%s` on field `%s`\", argName, fieldName),\n            )\n          }\n        };\n  };\n\n  let matchesTypeCondition = (typeCondition: string, obj: obj('ctx, 'src)) =>\n    typeCondition == obj.name\n    || Belt.List.some(obj.abstracts^, abstract => abstract.name == typeCondition);\n\n  let rec shouldIncludeField = (ctx, directives: list(Ast.directive)) =>\n    switch (directives) {\n    | [] => Ok(true)\n    | [{name: \"skip\", arguments}, ...rest] =>\n      eval_directive(ctx, skipDirective, arguments, rest)\n    | [{name: \"include\", arguments}, ...rest] =>\n      eval_directive(ctx, includeDirective, arguments, rest)\n    | [{name, _}, ..._] =>\n      let err = Format.sprintf(\"Unknown directive: %s\", name);\n      Error(err);\n    }\n  and eval_directive = (ctx, Directive({name, args, resolve, _}), arguments, rest) =>\n    ArgEval.evalArgList(\n      ctx.variableMap,\n      ~fieldType=\"directive\",\n      ~fieldName=name,\n      args,\n      arguments,\n      resolve,\n    )\n    ->Result.flatMap(\n        fun\n        | `Skip => Ok(false)\n        | `Include => shouldIncludeField(ctx, rest),\n      );\n\n  let rec collectFields:\n    (executionContext('ctx), obj('ctx, 'src), list(Ast.selection)) =>\n    Result.t(list(Ast.field), string) =\n    (ctx, obj, selectionSet) =>\n      selectionSet\n      ->List.map(\n          fun\n          | Ast.Field(field) =>\n            shouldIncludeField(ctx, field.directives)\n            ->Result.map(shouldInclude => shouldInclude ? [field] : [])\n          | Ast.FragmentSpread(fragmentSpread) =>\n            switch (StringMap.get(ctx.fragmentMap, fragmentSpread.name)) {\n            | Some({typeCondition, selectionSet, directives})\n                when matchesTypeCondition(typeCondition, obj) =>\n              shouldIncludeField(ctx, directives)\n              ->Result.flatMap(shouldInclude =>\n                  shouldInclude ? collectFields(ctx, obj, selectionSet) : Ok([])\n                )\n            | _ => Ok([])\n            }\n          | Ast.InlineFragment({typeCondition: Some(condition), directives} as inlineFragment)\n              when matchesTypeCondition(condition, obj) => {\n              shouldIncludeField(ctx, directives)\n              ->Result.flatMap(shouldInclude =>\n                  shouldInclude ? collectFields(ctx, obj, inlineFragment.selectionSet) : Ok([])\n                );\n            }\n          | Ast.InlineFragment({typeCondition: _}) => Ok([]),\n        )\n      ->List.Result.join\n      ->List.Result.map(Belt.List.flatten);\n\n  let fieldName: Ast.field => string =\n    fun\n    | {alias: Some(alias)} => alias\n    | field => field.name;\n\n  let getObjField = (fieldName: string, obj: obj('ctx, 'src)): option(field('ctx, 'src)) =>\n    obj.fields |> Lazy.force |> Belt.List.getBy(_, (Field(field)) => field.name == fieldName);\n\n  let coerceOrNull = (src, f) =>\n    switch (src) {\n    | Some(src') => f(src')\n    | None => Io.ok(`Null)\n    };\n\n\n  let rec resolveValue:\n    type ctx src.\n      (executionContext(ctx), src, Ast.field, typ(ctx, src)) =>\n      Io.t(Result.t(Ast.constValue, [> resolveError])) =\n    (executionContext, src, field, typ) =>\n      switch (typ) {\n      | NonNull(typ') => resolveValue(executionContext, Some(src), field, typ')\n      | Scalar(scalar) => coerceOrNull(src, src' => Io.ok(scalar.serialize(src')))\n      | Enum(enum) =>\n        coerceOrNull(src, src' =>\n          switch (Belt.List.getBy(enum.values, enumValue => enumValue.value == src')) {\n          | Some(enumValue) => Io.ok(`String(enumValue.name))\n          | None => Io.ok(`Null)\n          }\n        )\n      | Object(obj) =>\n        coerceOrNull(src, src' =>\n          switch (collectFields(executionContext, obj, field.selectionSet)) {\n          | Ok(fields) => resolveFields(executionContext, src', obj, fields)\n          | Error(e) => Io.error(`ArgumentError(e))\n          }\n        )\n      | List(typ') =>\n        coerceOrNull(src, src' =>\n          Belt.Array.map(src', srcItem => resolveValue(executionContext, srcItem, field, typ'))\n          ->List.fromArray\n          ->Io.all\n          ->Io.map(List.Result.join)\n          ->Io.Result.map(list => `List(list))\n        )\n      | Abstract(_) =>\n        coerceOrNull(\n          src,\n          src' => {\n            let AbstractValue((typ', src')) = src';\n            resolveValue(executionContext, Some(src'), field, typ');\n          },\n        )\n      }\n\n  and resolveField:\n    type ctx src.\n      (executionContext(ctx), src, Ast.field, field(ctx, src)) =>\n      Io.t(Result.t((string, Ast.constValue), [> resolveError])) =\n    (executionContext, src, field, Field(fieldDef)) => {\n      let name = fieldName(field);\n      let resolver = fieldDef.resolve(executionContext.ctx, src);\n\n      switch (\n        ArgEval.evalArgList(\n          executionContext.variableMap,\n          ~fieldName=fieldDef.name,\n          fieldDef.args,\n          field.arguments,\n          resolver,\n        )\n      ) {\n      | Ok(unlifted) =>\n        let%Io.Result resolved =\n          fieldDef.lift(unlifted)->Io.Result.mapError(err => `ResolveError((err, [])));\n\n        let%Io resolvedValue = resolveValue(executionContext, resolved, field, fieldDef.typ);\n\n        Io.return(\n          switch (resolvedValue) {\n          | Ok(value) => Ok((name, value))\n          | Error(`ArgumentError(_) | `ValidationError(_)) as error => error\n          | Error(`ResolveError(_)) as error =>\n            switch (fieldDef.typ) {\n            | NonNull(_) => error\n            | _ => Ok((name, `Null))\n            }\n          },\n        );\n\n      | Error(err) => Io.error(`ArgumentError(err))\n      };\n    }\n\n  and resolveFields:\n    type ctx src.\n      (executionContext(ctx), src, obj(ctx, src), list(Ast.field)) =>\n      Io.t(Result.t(Ast.constValue, [> resolveError])) =\n    (executionContext, src, obj, fields) => {\n      let mapFields =\n        switch (executionContext.operation.operationType) {\n        | Query\n        | Subscription => Io.mapParalell\n        | Mutation => Io.mapSerial(~memo=[])\n        };\n\n      mapFields(fields, field =>\n        if (field.name == \"__typename\") {\n          Io.ok((fieldName(field), `String(obj.name)));\n        } else {\n          switch (getObjField(field.name, obj)) {\n          | Some(objField) => resolveField(executionContext, src, field, objField)\n          | None =>\n            let err =\n              Printf.sprintf(\"Field '%s' is not defined on type '%s'\", field.name, obj.name);\n            Io.error(`ValidationError(err));\n          };\n        }\n      )\n      ->Io.map(List.Result.join)\n      ->Io.Result.map(assocList => `Object(assocList));\n    };\n\n  let executeOperation =\n      (executionContext: executionContext('ctx), operation: Ast.operationDefinition)\n      : Io.t(Result.t(Ast.constValue, [> executeError])) =>\n    switch (operation.operationType) {\n    | Query =>\n      let%Io.Result fields =\n        Io.return(\n          collectFields(executionContext, executionContext.schema.query, operation.selectionSet),\n        )\n        ->Io.Result.mapError(e => `ArgumentError(e));\n\n      (\n        resolveFields(executionContext, (), executionContext.schema.query, fields):\n          Io.t(Result.t(Ast.constValue, resolveError)) :>\n          Io.t(Result.t(Ast.constValue, [> executeError]))\n      );\n    | Mutation =>\n      switch (executionContext.schema.mutation) {\n      | Some(mutation) =>\n        let%Io.Result fields =\n          Io.return(collectFields(executionContext, mutation, operation.selectionSet))\n          ->Io.Result.mapError(e => `ArgumentError(e));\n\n        (\n          resolveFields(executionContext, (), mutation, fields):\n            Io.t(Result.t(Ast.constValue, resolveError)) :>\n            Io.t(Result.t(Ast.constValue, [> executeError]))\n        );\n      | None => Io.error(`MutationsNotConfigured)\n      }\n    | _ => failwith(\"Subscription Not implemented\")\n    };\n\n  let collectOperations = (document: Ast.document) =>\n    Belt.List.reduceReverse(document.definitions, [], (list, x) =>\n      switch (x) {\n      | Ast.Operation(operation) => [operation, ...list]\n      | _ => list\n      }\n    );\n\n  let collectFragments = (document: Ast.document) => {\n    Belt.List.reduceReverse(document.definitions, StringMap.empty, fragmentMap =>\n      fun\n      | Ast.Fragment(fragment) => StringMap.set(fragmentMap, fragment.name, fragment)\n      | _ => fragmentMap\n    );\n  };\n\n  exception FragmentCycle(list(string));\n\n  let rec validateFragments = fragmentMap =>\n    try(\n      {\n        StringMap.forEach(fragmentMap, (name, _) =>\n          validateFragment(fragmentMap, StringSet.empty, name)\n        );\n        Ok(fragmentMap);\n      }\n    ) {\n    | FragmentCycle(fragmentNames) =>\n      let cycle = String.concat(\", \", fragmentNames);\n      let err = Format.sprintf(\"Fragment cycle detected: %s\", cycle);\n      Error(`ValidationError(err));\n    }\n\n  and validateFragment = (fragmentMap: fragmentMap, visited, name) => {\n    switch (StringMap.get(fragmentMap, name)) {\n    | None => ()\n    | Some(fragment) when StringSet.mem(fragment.name, visited) =>\n      raise(FragmentCycle(StringSet.elements(visited)))\n    | Some(fragment) =>\n      let visited' = StringSet.add(fragment.name, visited);\n      Belt.List.forEach(fragment.selectionSet, validateFragmentSelection(fragmentMap, visited'));\n    };\n  }\n\n  and validateFragmentSelection = (fragmentMap, visited, selection) =>\n    switch (selection) {\n    | Field(field) =>\n      Belt.List.forEach(field.selectionSet, validateFragmentSelection(fragmentMap, visited))\n    | InlineFragment(inlineFragment) =>\n      Belt.List.forEach(\n        inlineFragment.selectionSet,\n        validateFragmentSelection(fragmentMap, visited),\n      )\n    | FragmentSpread(fragmentSpread) =>\n      validateFragment(fragmentMap, visited, fragmentSpread.name)\n    };\n\n  let collectAndValidateFragments = doc => {\n    let fragments = collectFragments(doc);\n    validateFragments(fragments);\n  };\n\n  let okResponse = data => {\n    `Object([(\"data\", data)]);\n  };\n\n  let errorResponse = (~path=?, msg): Ast.constValue => {\n    let path' =\n      switch (path) {\n      | Some(path) => path\n      | None => []\n      };\n    `Object([\n      (\"data\", `Null),\n      (\n        \"errors\",\n        `List([\n          `Object([\n            (\"message\", `String(msg)),\n            (\"path\", `List(List.map(path', s => `String(s)))),\n          ]),\n        ]),\n      ),\n    ]);\n  };\n\n  let execute =\n      (~variables: variableList=[], ~document: Ast.document, schema: schema('ctx), ~ctx: 'ctx) => {\n    let execute' = (schema, ctx, document) => {\n      let operations = collectOperations(document);\n      let%Io.Result fragmentMap = Io.return(collectAndValidateFragments(document));\n\n      let variableMap =\n        Belt.List.reduce(variables, StringMap.empty, (map, (name, value)) =>\n          StringMap.set(map, name, value)\n        );\n\n      let schema' = Introspection.addSchemaField(schema);\n\n      List.map(\n        operations,\n        operation => {\n          let executionContext = {schema: schema', fragmentMap, operation, variableMap, ctx};\n          executeOperation(executionContext, operation);\n        },\n      )\n      ->Belt.List.headExn;\n    };\n\n    execute'(schema, ctx, document)\n    ->Io.map(\n        fun\n        | Ok(res) => okResponse(res)\n        | Error(`NoOperationFound) => errorResponse(\"No operation found\")\n        | Error(`OperationNotFound) => errorResponse(\"Operation not found\")\n        | Error(`OperationNameRequired) => errorResponse(\"Operation name required\")\n        | Error(`SubscriptionsNotConfigured) => errorResponse(\"Subscriptions not configured\")\n        | Error(`MutationsNotConfigured) => errorResponse(\"Mutations not configured\")\n        | Error(`ValidationError(msg)) => errorResponse(msg)\n        | Error(`ArgumentError(msg)) => errorResponse(msg)\n        | Error(`ResolveError(msg, path)) => errorResponse(msg, ~path),\n      );\n  };\n\n  let resultToJson: Io.t(Ast.constValue) => Io.t(Js.Json.t) =\n    result => Io.map(result, Graphql_Json.fromConstValue);\n};\n"
  },
  {
    "path": "reason-graphql/src/Graphql_Schema.rei",
    "content": "module Make: (Io: Graphql_Interface.IO) => Graphql_Interface.Schema with module Io = Io;\n"
  },
  {
    "path": "reason-graphql/src/language/Graphql_Language.re",
    "content": "module Ast = Graphql_Language_Ast;\nmodule Lexer = Graphql_Language_Lexer;\nmodule Parser = Graphql_Language_Parser;\nmodule Printer = Graphql_Language_Printer;\n"
  },
  {
    "path": "reason-graphql/src/language/Graphql_Language_Ast.re",
    "content": "type primitiveValue = [\n  | `Int(int)\n  | `Float(float)\n  | `Boolean(bool)\n  | `String(string)\n  | `Enum(string)\n  | `Null\n];\n\ntype constValue = [\n  primitiveValue\n  | `List(list(constValue))\n  | `Object(list((string, constValue)))\n];\n\ntype value = [\n  primitiveValue\n  | `List(list(value))\n  | `Object(list((string, value)))\n  | `Variable(string)\n];\n\ntype argument = (string, value);\n\ntype document = {definitions: list(definition)}\n\nand definition =\n  | Operation(operationDefinition)\n  | Fragment(fragmentDefinition)\n\nand operationDefinition = {\n  operationType,\n  name: option(string),\n  variableDefinition: list(variableDefinition),\n  directives: list(directive),\n  selectionSet: list(selection),\n}\n\nand operationType =\n  | Query\n  | Mutation\n  | Subscription\n\nand variableDefinition = {\n  variable: [ | `Variable(string)],\n  typ: typeReference,\n  defaultValue: option(constValue),\n  directives: list(directive),\n}\n\nand selection =\n  | Field(field)\n  | FragmentSpread(fragmentSpread)\n  | InlineFragment(inlineFragmentDefinition)\n\nand field = {\n  alias: option(string),\n  name: string,\n  arguments: list(argument),\n  selectionSet: list(selection),\n  directives: list(directive),\n}\n\nand fragmentDefinition = {\n  name: string,\n  typeCondition: string,\n  selectionSet: list(selection),\n  directives: list(directive),\n}\n\nand inlineFragmentDefinition = {\n  typeCondition: option(string),\n  selectionSet: list(selection),\n  directives: list(directive),\n}\n\nand fragmentSpread = {\n  name: string,\n  directives: list(directive),\n}\n\n/* Directives */\nand directive = {\n  name: string,\n  arguments: list(argument),\n}\n\nand typeReference =\n  | NamedType(string)\n  | ListType(typeReference)\n  | NonNullType(typeReference)\n\nand typeSystemDefinition =\n  | SchemaDefinition(schemaDefinition)\n  | TypeDefinition(typeDefinition)\n  | TypeExtension(typeExtensionDefinition)\n  | DirectiveDefinitionNode(directiveDefinition)\n\nand schemaDefinition = {operationTypes: operationTypeDefinition}\n\nand operationTypeDefinition = {\n  typ: string,\n  operation: operationType,\n}\n\nand typeDefinition =\n  | ScalarTypeDefinition(string)\n  | ObjectTypeDefinition(objectTypeDefinition)\n  | InterfaceTypeDefinition(interfaceTypeDefinition)\n  | UnionTypeDefinition(unionTypeDefinition)\n  | EnumTypeDefinition(enumTypeDefintion)\n  | InputObjectTypeDefinition(inputObjectTypeDefinition)\n\nand objectTypeDefinition = {\n  name: string,\n  interfaces: list(string),\n  fields: list(fieldDefinition),\n}\n\nand fieldDefinition = {\n  name: string,\n  arguments: list(inputValueDefinition),\n  typ: typeReference,\n}\n\nand inputValueDefinition = {\n  name: string,\n  typ: typeReference,\n  defaultValue: option(constValue),\n}\n\nand interfaceTypeDefinition = {\n  name: string,\n  fields: list(fieldDefinition),\n}\n\nand unionTypeDefinition = {\n  name: string,\n  types: list(string),\n}\n\nand enumTypeDefintion = {\n  name: string,\n  values: list(string),\n}\n\nand inputObjectTypeDefinition = {\n  name: string,\n  fields: list(inputValueDefinition),\n}\n\nand typeExtensionDefinition = {definition: objectTypeDefinition}\n\nand directiveDefinition = {\n  name: string,\n  arguments: list(inputValueDefinition),\n};\n\ntype astMapping = {\n  name: string => string,\n  document: document => document,\n  operationDefinition: operationDefinition => operationDefinition,\n  fragmentDefinition: fragmentDefinition => fragmentDefinition,\n  variableDefinition: variableDefinition => variableDefinition,\n  directives: list(directive) => list(directive),\n  directive: directive => directive,\n  selection: selection => selection,\n  selectionSet: list(selection) => list(selection),\n  field: field => field,\n  arguments: list(argument) => list(argument),\n  argument: argument => argument,\n  inlineFragmentDefinition:\n    inlineFragmentDefinition => inlineFragmentDefinition,\n  fragmentSpread: fragmentSpread => fragmentSpread,\n  typeReference: typeReference => typeReference,\n  namedType: string => typeReference,\n  listType: typeReference => typeReference,\n  nonNullType: typeReference => typeReference,\n  constValue: constValue => constValue,\n  value: value => value,\n  variable: string => string,\n};\n\nlet id = a => a;\n\nlet defaultMapper = {\n  name: id,\n  document: id,\n  operationDefinition: id,\n  fragmentDefinition: id,\n  variableDefinition: id,\n  directives: id,\n  directive: id,\n  selection: id,\n  selectionSet: id,\n  field: id,\n  arguments: id,\n  argument: id,\n  inlineFragmentDefinition: id,\n  fragmentSpread: id,\n  typeReference: a => a,\n  namedType: a => NamedType(a),\n  constValue: id,\n  value: id,\n  listType: a => ListType(a),\n  nonNullType: a => NonNullType(a),\n  variable: id,\n};\n\nlet rec visit = (~enter=defaultMapper, ~leave=defaultMapper, ast: document) => {\n  let document = enter.document(ast);\n  {\n    definitions:\n      document.definitions |> List.map(visitDefinition(~enter, ~leave)),\n  }\n  |> leave.document;\n}\nand visitDefinition = (~enter, ~leave) =>\n  fun\n  | Operation(operationDefinition) =>\n    Operation(visitOperationDefinition(~enter, ~leave, operationDefinition))\n  | Fragment(fragmentDefinition) =>\n    Fragment(visitFragmentDefinition(~enter, ~leave, fragmentDefinition))\nand visitOperationDefinition = (~enter, ~leave, operationDefinition) => {\n  let operationDefinition = enter.operationDefinition(operationDefinition);\n  {\n    ...operationDefinition,\n    name:\n      switch (operationDefinition.name) {\n      | Some(name) => Some(visitName(~enter, ~leave, name))\n      | None => None\n      },\n    variableDefinition:\n      List.map(\n        visitVariableDefinition(~enter, ~leave),\n        operationDefinition.variableDefinition,\n      ),\n    directives:\n      visitDirectives(~enter, ~leave, operationDefinition.directives),\n    selectionSet:\n      visitSelectionSet(~enter, ~leave, operationDefinition.selectionSet),\n  };\n}\nand visitFragmentDefinition = (~enter, ~leave, fragmentDefinition) => {\n  let fragmentDefinition = enter.fragmentDefinition(fragmentDefinition);\n\n  {\n    ...fragmentDefinition,\n    name: visitName(~enter, ~leave, fragmentDefinition.name),\n    selectionSet:\n      visitSelectionSet(~enter, ~leave, fragmentDefinition.selectionSet),\n    directives:\n      visitDirectives(~enter, ~leave, fragmentDefinition.directives),\n  }\n  |> leave.fragmentDefinition;\n}\nand visitVariableDefinition = (~enter, ~leave, variableDefinition) => {\n  let variableDefinition = enter.variableDefinition(variableDefinition);\n  let `Variable(variable) = variableDefinition.variable;\n\n  {\n    variable: `Variable(enter.variable(variable)),\n    typ: visitTypeReference(~enter, ~leave, variableDefinition.typ),\n    directives:\n      visitDirectives(~enter, ~leave, variableDefinition.directives),\n    defaultValue:\n      switch (variableDefinition.defaultValue) {\n      | Some(constValue) =>\n        Some(visitConstValue(~enter, ~leave, constValue))\n      | None => None\n      },\n  }\n  |> leave.variableDefinition;\n}\nand visitDirectives = (~enter, ~leave, directives) => {\n  directives\n  |> enter.directives\n  |> List.map(visitDirective(~enter, ~leave))\n  |> leave.directives;\n}\nand visitDirective = (~enter, ~leave, directive) => {\n  let directive = enter.directive(directive);\n  {\n    name: visitName(~enter, ~leave, directive.name),\n    arguments: visitArguments(~enter, ~leave, directive.arguments),\n  }\n  |> leave.directive;\n}\nand visitArguments = (~enter, ~leave, arguments) => {\n  arguments\n  |> enter.arguments\n  |> List.map(visitArgument(~enter, ~leave))\n  |> leave.arguments;\n}\nand visitArgument = (~enter, ~leave, argument) => {\n  let (name, value) = enter.argument(argument);\n  (name, visitValue(~enter, ~leave, value)) |> leave.argument;\n}\nand visitSelectionSet = (~enter, ~leave, selectionSet) => {\n  selectionSet\n  |> enter.selectionSet\n  |> List.map(visitSelection(~enter, ~leave))\n  |> leave.selectionSet;\n}\nand visitSelection = (~enter, ~leave, selection) => {\n  (\n    switch (enter.selection(selection)) {\n    | Field(field) => Field(visitField(~enter, ~leave, field))\n    | FragmentSpread(fragmentSpread) =>\n      FragmentSpread(visitFragmentSpread(~enter, ~leave, fragmentSpread))\n    | InlineFragment(inlineFragment) =>\n      InlineFragment(visitInlineFragment(~enter, ~leave, inlineFragment))\n    }\n  )\n  |> leave.selection;\n}\nand visitField = (~enter, ~leave, field) => {\n  let field = enter.field(field);\n  {\n    ...field,\n    name: visitName(~enter, ~leave, field.name),\n    arguments: visitArguments(~enter, ~leave, field.arguments),\n    selectionSet: visitSelectionSet(~enter, ~leave, field.selectionSet),\n    directives: visitDirectives(~enter, ~leave, field.directives),\n  }\n  |> leave.field;\n}\nand visitFragmentSpread = (~enter, ~leave, fragmentSpread) => {\n  let fragmentSpread = enter.fragmentSpread(fragmentSpread);\n  {\n    name: visitName(~enter, ~leave, fragmentSpread.name),\n    directives: visitDirectives(~enter, ~leave, fragmentSpread.directives),\n  }\n  |> leave.fragmentSpread;\n}\nand visitInlineFragment = (~enter, ~leave, inlineFragment) => {\n  let inlineFragment = enter.inlineFragmentDefinition(inlineFragment);\n  {\n    ...inlineFragment,\n    selectionSet:\n      visitSelectionSet(~enter, ~leave, inlineFragment.selectionSet),\n    directives: visitDirectives(~enter, ~leave, inlineFragment.directives),\n  }\n  |> leave.inlineFragmentDefinition;\n}\nand visitTypeReference = (~enter, ~leave, typeReference) => {\n  (\n    switch (enter.typeReference(typeReference)) {\n    | NamedType(string) => enter.namedType(string)\n    | ListType(listType) => enter.listType(listType)\n    | NonNullType(nonNullType) => enter.nonNullType(nonNullType)\n    }\n  )\n  |> leave.typeReference;\n}\nand visitName = (~enter, ~leave, name) => {\n  enter.name(name) |> leave.name;\n}\nand visitValue = (~enter, ~leave, value) => {\n  enter.value(value) |> leave.value;\n}\nand visitConstValue = (~enter, ~leave, constValue) => {\n  enter.constValue(constValue) |> leave.constValue;\n};"
  },
  {
    "path": "reason-graphql/src/language/Graphql_Language_Error.re",
    "content": "type t =\n  | SyntaxError(string);\n"
  },
  {
    "path": "reason-graphql/src/language/Graphql_Language_Lexer.re",
    "content": "module Result = {\n  include Belt.Result;\n  let let_ = flatMap;\n};\n\ntype result('a) = Result.t('a, Graphql_Language_Error.t);\nlet syntaxError = a => Result.Error(Graphql_Language_Error.SyntaxError(a));\n\ntype location = {\n  start: int,\n  end_: int,\n  line: int,\n  column: int,\n};\n\ntype token =\n  | StartOfFile\n  | EndOfFile\n  | Bang\n  | Dollar\n  | Amp\n  | ParenOpen\n  | ParenClose\n  | Spread\n  | Colon\n  | Equals\n  | At\n  | BracketOpen\n  | BracketClose\n  | BraceOpen\n  | BraceClose\n  | Pipe\n  | Name(string)\n  | Int(string)\n  | Float(string)\n  | String(string)\n  | Comment(string);\n\nlet tokenKind =\n  fun\n  | StartOfFile => \"<SOF>\"\n  | EndOfFile => \"<EOF>\"\n  | Bang => \"!\"\n  | Dollar => \"$\"\n  | Amp => \"$\"\n  | ParenOpen => \"(\"\n  | ParenClose => \")\"\n  | Spread => \"...\"\n  | Colon => \":\"\n  | Equals => \"=\"\n  | At => \"@\"\n  | BracketOpen => \"[\"\n  | BracketClose => \"]\"\n  | BraceOpen => \"{\"\n  | BraceClose => \"}\"\n  | Pipe => \"|\"\n  | Name(_) => \"Name\"\n  | Int(_) => \"Int\"\n  | Float(_) => \"Float\"\n  | String(_) => \"String\"\n  | Comment(_) => \"Comment\";\n\ntype tokenResult = {\n  token,\n  location,\n};\n\ntype t = {\n  source: string,\n  mutable curr: tokenResult,\n  mutable line: int,\n  mutable lineStart: int,\n};\n\n/* (line:col) kind: <kind>, value: <value> */\nlet tokenDesc = ({token, location}) => {\n  \"(\"\n  ++ string_of_int(location.line)\n  ++ \":\"\n  ++ string_of_int(location.column)\n  ++ \")\"\n  ++ (\n    switch (token) {\n    | Name(v) => \" kind: '\" ++ tokenKind(token) ++ \"', value: \" ++ v\n    | Int(v) => \" kind: '\" ++ tokenKind(token) ++ \"', value: \" ++ v\n    | Float(v) => \" kind: '\" ++ tokenKind(token) ++ \"', value: \" ++ v\n    | String(v) => \" kind: '\" ++ tokenKind(token) ++ \"', value: \" ++ v\n    | Comment(v) => \" kind: '\" ++ tokenKind(token) ++ \"', value: \" ++ v\n    | token => \" kind: '\" ++ tokenKind(token) ++ \"'\"\n    }\n  );\n};\n\nlet isChar = (source, position, char) =>\n  position < String.length(source) && source.[position] == char;\n\n/**\n * Reads from source starting at startPosition until it finds a non-whitespace\n * character, then returns the position of that character for lexing.\n */\nlet positionAfterWhitespace = (lexer, startPosition) => {\n  let {source} = lexer;\n\n  let rec aux = position =>\n    if (position >= String.length(source)) {\n      position;\n    } else {\n      switch (source.[position]) {\n      | bom when int_of_char(bom) == 0xFEFF => position + 1\n      | ' '\n      | ','\n      | '\\t' => aux(position + 1)\n      | '\\n' =>\n        let newPosition = position + 1;\n        lexer.line = lexer.line + 1;\n        lexer.lineStart = newPosition;\n        aux(newPosition);\n      | '\\r' =>\n        let newPosition =\n          isChar(source, position + 1, '\\n') ? position + 2 : position + 1;\n\n        lexer.line = lexer.line + 1;\n        lexer.lineStart = newPosition;\n        aux(newPosition);\n      | _ => position\n      };\n    };\n\n  aux(startPosition);\n};\n\nlet isNameChar =\n  fun\n  | 'A'..'Z'\n  | 'a'..'z'\n  | '0'..'9'\n  | '_' => true\n  | _ => false;\n\n/**\n * Reads an alphanumeric + underscore name from the source.\n *\n * [_A-Za-z][_0-9A-Za-z]*\n */\nlet readName = (source, ~start, ~line, ~column): tokenResult => {\n  let rec aux = position =>\n    switch (source.[position]) {\n    | 'A'..'Z'\n    | 'a'..'z'\n    | '0'..'9'\n    | '_' => aux(position + 1)\n    | _ => {\n        token: Name(String.sub(source, start, position - start)),\n        location: {\n          start,\n          line,\n          end_: position,\n          column,\n        },\n      }\n    };\n\n  aux(start);\n};\n\n/**\n * #[\\u0009\\u0020-\\uFFFF]*\n */\nlet readComment = (source, ~start, ~line, ~column): tokenResult => {\n  let rec aux = position =>\n    if (position > String.length(source)) {\n      position;\n    } else {\n      switch (source.[position]) {\n      | '\\r'\n      | '\\n' => position\n      | _ => aux(position + 1)\n      };\n    };\n\n  let position = aux(start);\n\n  {\n    token: Comment(String.sub(source, start, position - start)),\n    location: {\n      start,\n      line,\n      end_: position,\n      column,\n    },\n  };\n};\n\nlet readDigits = (source, startingPosition): result(int) => {\n  let rec aux = (source, pos) =>\n    if (pos >= String.length(source)) {\n      Result.Ok(pos);\n    } else {\n      switch (source.[pos]) {\n      | '0'..'9' => aux(source, pos + 1)\n      | c when pos === startingPosition =>\n        syntaxError(\n          \"Invalid number, expected digit but got: \" ++ String.make(1, c),\n        )\n      | _ => Ok(pos)\n      };\n    };\n\n  aux(source, startingPosition);\n};\n\n/**\n * Reads a number token from the source file, either a float\n * or an int depending on whether a decimal point appears.\n *\n * Int:   -?(0|[1-9][0-9]*)\n * Float: -?(0|[1-9][0-9]*)(\\.[0-9]+)?((E|e)(+|-)?[0-9]+)?\n */\nlet readNumber = (source, ~start, ~line, ~column): result(tokenResult) => {\n  let isFloat = ref(false);\n  let position = ref(start);\n\n  if (source.[start] == '-') {\n    position := position^ + 1;\n  };\n\n  let%Result () =\n    if (source.[position^] == '0') {\n      position := position^ + 1;\n      switch (source.[position^]) {\n      | '0'..'9' as char =>\n        syntaxError(\n          \"Invalid number, unexpected digit after 0: \" ++ String.make(1, char),\n        )\n      | _ => Ok()\n      };\n    } else {\n      let%Result pos = readDigits(source, position^);\n      Ok(position := pos);\n    };\n\n  let%Result () =\n    if (isChar(source, position^, '.')) {\n      isFloat := true;\n      position := position^ + 1;\n      let%Result pos = readDigits(source, position^);\n      Ok(position := pos);\n    } else {\n      Ok();\n    };\n\n  let%Result () =\n    if (isChar(source, position^, 'E') || isChar(source, position^, 'e')) {\n      isFloat := true;\n      position := position^ + 1;\n\n      if (isChar(source, position^, '+') || isChar(source, position^, '-')) {\n        position := position^ + 1;\n      };\n\n      let%Result pos = readDigits(source, position^);\n      Ok(position := pos);\n    } else {\n      Ok();\n    };\n\n  let loc = {start, end_: position^, line, column};\n\n  let tok =\n    isFloat^\n      ? Float(String.sub(source, start, position^ - start))\n      : Int(String.sub(source, start, position^ - start));\n\n  Ok({token: tok, location: loc});\n};\n\n/**\n * Converts a hex character to its integer value.\n * '0' becomes 0, '9' becomes 9\n * 'A' becomes 10, 'F' becomes 15\n * 'a' becomes 10, 'f' becomes 15\n *\n * Returns -1 on error.\n */\nlet char2hex = c =>\n  c >= 48 && c <= 57\n    ? c - 48  // 0-9\n    : c >= 65 && c <= 70\n        ? c - 55  // c-F\n        : c >= 97 && c <= 102\n            ? c - 87  // a-f\n            : (-1);\n\n/**\n * Converts four hexadecimal chars to the integer that the\n * string represents. For example, uniCharCode('0','0','0','f')\n * will return 15, and uniCharCode('0','0','f','f') returns 255.\n *\n * Returns a negative number on error, if a char was invalid.\n *\n * This is implemented by noting that char2hex() returns -1 on error,\n * which means the result of ORing the char2hex() will also be negative.\n */\nlet uniCharCode = (a, b, c, d) =>\n  char2hex(a)\n  lsl 12\n  lor char2hex(b)\n  lsl 8\n  lor char2hex(c)\n  lsl 4\n  lor char2hex(d);\n\n/**\n * Reads a string token from the source file.\n *\n * \"([^\"\\\\\\u000A\\u000D]|(\\\\(u[0-9a-fA-F]{4}|[\"\\\\/bfnrt])))*\"\n */\nlet readString = (source, ~start, ~line, ~column): result(tokenResult) => {\n  let rec aux = (value, position, chunkStart) => {\n    let%Result () =\n      if (position >= String.length(source)) {\n        syntaxError(\"Unterminated string\");\n      } else {\n        Ok();\n      };\n\n    switch (source.[position]) {\n    | '\\n' => syntaxError(\"Unterminated string\")\n    | '\"' =>\n      Ok({\n        token:\n          String(\n            value ++ String.sub(source, chunkStart, position - chunkStart),\n          ),\n        location: {\n          line,\n          column,\n          start,\n          end_: position + 1,\n        },\n      })\n    | c when Char.code(c) == 92 =>\n      let newPosition = ref(position + 1);\n      let code = source.[newPosition^]->Char.code;\n      let%Result rest =\n        switch (code) {\n        | 34 => Ok(\"\\\"\")\n        | 47 => Ok(\"/\")\n        | 92 => Ok(\"\\\\\")\n        | 98 => Ok(\"\\b\")\n        | 102 => Ok(\"\\\\f\")\n        | 110 => Ok(\"\\n\")\n        | 114 => Ok(\"\\r\")\n        | 116 => Ok(\"\\t\")\n        // u\n        | 117 =>\n          let charCode =\n            uniCharCode(\n              source.[position + 1]->Char.code,\n              source.[position + 2]->Char.code,\n              source.[position + 3]->Char.code,\n              source.[position + 4]->Char.code,\n            );\n\n          if (charCode < 0) {\n            syntaxError(\n              \"Invalid character escape sequence: \"\n              ++ \"\\\\u\"\n              ++ String.sub(source, position + 1, position + 5)\n              ++ \".\",\n            );\n          } else {\n            newPosition := newPosition^ + 4;\n            Ok(Char.chr(charCode) |> String.make(1));\n          };\n\n        | _ =>\n          syntaxError(\n            \"Invalid character escape sequence: \\\\\"\n            ++ (Char.chr(code) |> String.make(1)),\n          )\n        };\n      let value =\n        value\n        ++ String.sub(source, chunkStart, newPosition^ - chunkStart - 1)\n        ++ rest;\n\n      let nextPosition = newPosition^ + 1;\n      aux(value, nextPosition, nextPosition);\n    | _ => aux(value, position + 1, chunkStart)\n    };\n  };\n\n  aux(\"\", start + 1, start + 1);\n};\n\n/**\n * Gets the next token from the source starting at the given position.\n *\n * This skips over whitespace until it finds the next lexable token, then lexes\n * punctuators immediately or calls the appropriate helper function for more\n * complicated tokens.\n */\nlet readToken = (lexer, from): result(tokenResult) => {\n  let {source} = lexer;\n  let position = positionAfterWhitespace(lexer, from);\n  let line = lexer.line;\n  let column = 1 + position - lexer.lineStart;\n  let sourceLength = String.length(source);\n  let singleWidth = {start: position, end_: position + 1, line, column};\n\n  if (position >= String.length(source)) {\n    Ok({\n      token: EndOfFile,\n      location: {\n        start: sourceLength,\n        end_: sourceLength,\n        line,\n        column,\n      },\n    });\n  } else {\n    switch (source.[position]) {\n    | '!' => Ok({token: Bang, location: singleWidth})\n    | '$' => Ok({token: Dollar, location: singleWidth})\n    | '&' => Ok({token: Amp, location: singleWidth})\n    | '(' => Ok({token: ParenOpen, location: singleWidth})\n    | ')' => Ok({token: ParenClose, location: singleWidth})\n    | ':' => Ok({token: Colon, location: singleWidth})\n    | '=' => Ok({token: Equals, location: singleWidth})\n    | '@' => Ok({token: At, location: singleWidth})\n    | '[' => Ok({token: BracketOpen, location: singleWidth})\n    | ']' => Ok({token: BracketClose, location: singleWidth})\n    | '{' => Ok({token: BraceOpen, location: singleWidth})\n    | '|' => Ok({token: Pipe, location: singleWidth})\n    | '}' => Ok({token: BraceClose, location: singleWidth})\n    | '.' =>\n      if (isChar(source, position + 1, '.')\n          && isChar(source, position + 2, '.')) {\n        Ok({\n          token: Spread,\n          location: {\n            start: position,\n            end_: position + 3,\n            line,\n            column,\n          },\n        });\n      } else if (position + 1 >= String.length(source)) {\n        syntaxError(\"Unexpected End of File\");\n      } else {\n        syntaxError(\n          \"Unexpected Character\" ++ String.make(1, source.[position + 1]),\n        );\n      }\n    | 'A'..'Z'\n    | 'a'..'z'\n    | '_' => Ok(readName(source, ~start=position, ~line, ~column))\n    | '0'..'9'\n    | '-' => readNumber(source, ~start=position, ~line, ~column)\n    | '\"' => readString(source, ~start=position, ~line, ~column)\n    | '#' => Ok(readComment(source, ~start=position, ~line, ~column))\n    | char => syntaxError(\"Unexpected Character\" ++ String.make(1, char))\n    };\n  };\n};\n\nlet make = source => {\n  source,\n  curr: {\n    token: StartOfFile,\n    location: {\n      start: 0,\n      end_: 0,\n      column: 0,\n      line: 1,\n    },\n  },\n  line: 1,\n  lineStart: 0,\n};\n\nlet lookahead =\n  fun\n  | {curr: {token: EndOfFile} as tokenResult} => Result.Ok(tokenResult)\n  | lexer => {\n      let rec skipComment = prevToken => {\n        let%Result token = readToken(lexer, prevToken.location.end_);\n        switch (token) {\n        | {token: Comment(_)} => skipComment(token)\n        | token => Ok(token)\n        };\n      };\n\n      skipComment(lexer.curr);\n    };\n\nlet advance = lexer => {\n  let%Result curr = lookahead(lexer);\n  lexer.curr = curr;\n  Ok(curr);\n};"
  },
  {
    "path": "reason-graphql/src/language/Graphql_Language_Parser.re",
    "content": "open Graphql_Language_Ast;\nmodule Lexer = Graphql_Language_Lexer;\n\nmodule Result = {\n  include Belt.Result;\n  let let_ = flatMap;\n};\n\ntype result('a) = Result.t('a, Graphql_Language_Error.t);\n\nlet syntaxError = a => Result.Error(Graphql_Language_Error.SyntaxError(a));\n\nlet expectedError = (lexer: Lexer.t, token: Lexer.token) => {\n  syntaxError(\n    \"Expected\" ++ Lexer.tokenKind(token) ++ \", found \" ++ Lexer.tokenDesc(lexer.curr),\n  );\n};\n\nlet expect = (lexer: Lexer.t, token: Lexer.token) =>\n  switch (lexer.curr.token) {\n  | currToken when currToken == token => Lexer.advance(lexer)\n  | _ => expectedError(lexer, token)\n  };\n\nlet skip = (lexer: Lexer.t, skipToken: Lexer.token): result(bool) =>\n  switch (lexer.curr.token) {\n  | token when token == skipToken => Lexer.advance(lexer)->Result.map(_ => true)\n  | _ => Ok(false)\n  };\n\nlet skipKeyword = (lexer: Lexer.t, value: string): result(bool) =>\n  switch (lexer.curr.token) {\n  | Name(name) when name == value => Lexer.advance(lexer)->Result.map(_ => true)\n  | _ => Ok(false)\n  };\n\nlet expectKeyword = (lexer: Lexer.t, value: string): result(unit) => {\n  let%Result skipped = skipKeyword(lexer, value);\n  if (!skipped) {\n    syntaxError(\"Expected \" ++ value ++ \", found \" ++ Lexer.tokenDesc(lexer.curr));\n  } else {\n    Ok();\n  };\n};\n\nlet unexpected = (lexer: Lexer.t) => {\n  syntaxError(\"Unexpected \" ++ Lexer.tokenDesc(lexer.curr));\n};\n\nlet any =\n    (\n      lexer: Lexer.t,\n      openKind: Lexer.token,\n      parseFn: Lexer.t => result('a),\n      closeKind: Lexer.token,\n    ) => {\n  let%Result _ = expect(lexer, openKind);\n\n  let rec collect = nodes => {\n    let%Result skipped = skip(lexer, closeKind);\n    if (!skipped) {\n      let%Result node = parseFn(lexer);\n      collect([node, ...nodes]);\n    } else {\n      Ok(Belt.List.reverse(nodes));\n    };\n  };\n\n  collect([]);\n};\n\nlet many =\n    (\n      lexer: Lexer.t,\n      openKind: Lexer.token,\n      parseFn: Lexer.t => result('a),\n      closeKind: Lexer.token,\n    )\n    : result(list('a)) => {\n  let%Result _ = expect(lexer, openKind);\n  let%Result node = parseFn(lexer);\n\n  let rec collect = nodes => {\n    let%Result skipped = skip(lexer, closeKind);\n    if (!skipped) {\n      let%Result node = parseFn(lexer);\n      collect([node, ...nodes]);\n    } else {\n      Ok(Belt.List.reverse(nodes));\n    };\n  };\n\n  collect([node]);\n};\n\nlet parseName =\n  fun\n  | ({curr: {token: Name(value)}} as lexer: Lexer.t) =>\n    Lexer.advance(lexer)->Result.map(_ => value)\n\n  | lexer => expectedError(lexer, Name(\"\"));\n\nlet parseNamedType = (lexer: Lexer.t) => {\n  let%Result name = parseName(lexer);\n  Ok(NamedType(name));\n};\n\nlet parseVariable = (lexer: Lexer.t) => {\n  let%Result _ = expect(lexer, Dollar);\n  let%Result name = parseName(lexer);\n  Ok(`Variable(name));\n};\n\nlet rec parseValueLiteral = (lexer: Lexer.t, ~isConst: bool): result(value) =>\n  Result.(\n    switch (lexer.curr.token) {\n    | BracketOpen =>\n      any(lexer, BracketOpen, parseValueLiteral(~isConst), BracketClose)\n      ->map(list => `List(list))\n    | BraceOpen => parseObject(lexer, ~isConst)\n    | Int(value) => Lexer.advance(lexer)->map(_ => `Int(int_of_string(value)))\n    | Float(value) => Lexer.advance(lexer)->map(_ => `Float(float_of_string(value)))\n    | String(value) => Lexer.advance(lexer)->map(_ => `String(value))\n    | Name(\"true\") => Lexer.advance(lexer)->map(_ => `Boolean(true))\n    | Name(\"false\") => Lexer.advance(lexer)->map(_ => `Boolean(false))\n    | Name(\"null\") => Lexer.advance(lexer)->map(_ => `Null)\n    | Name(value) => Lexer.advance(lexer)->map(_ => `Enum(value))\n    | Dollar when !isConst => parseVariable(lexer)\n    | _ => unexpected(lexer)\n    }\n  )\n\nand parseObject = (lexer: Lexer.t, ~isConst: bool) => {\n  let%Result _ = expect(lexer, BraceOpen);\n\n  let rec parseFields = fields => {\n    let%Result skipped = skip(lexer, BraceClose);\n    if (!skipped) {\n      let%Result field = parseObjectField(lexer, ~isConst);\n      parseFields([field, ...fields]);\n    } else {\n      Ok(fields);\n    };\n  };\n\n  let%Result fields = parseFields([]);\n  Ok(`Object(Belt.List.reverse(fields)));\n}\n\nand parseObjectField = (lexer: Lexer.t, ~isConst: bool): result((string, value)) => {\n  let%Result name = parseName(lexer);\n  let%Result _ = expect(lexer, Colon);\n  let%Result value = parseValueLiteral(lexer, ~isConst);\n  Ok((name, value));\n};\n\nlet rec parseTypeReference = (lexer: Lexer.t) => {\n  let%Result typ = {\n    let%Result skipped = skip(lexer, BracketOpen);\n    if (skipped) {\n      let%Result t = parseTypeReference(lexer);\n      let%Result _ = expect(lexer, BracketClose);\n      Ok(ListType(t));\n    } else {\n      let%Result typ = parseNamedType(lexer);\n      Ok(typ);\n    };\n  };\n\n  let%Result skipped = skip(lexer, Bang);\n\n  skipped ? Ok(NonNullType(typ)) : Ok(typ);\n};\n\nlet parseArgument = (lexer: Lexer.t, ~isConst): result((string, value)) => {\n  let%Result name = parseName(lexer);\n  let%Result _ = expect(lexer, Colon);\n  let%Result valueLiteral = parseValueLiteral(lexer, ~isConst);\n  Ok((name, valueLiteral));\n};\n\nlet parseArguments = (lexer: Lexer.t, ~isConst: bool) =>\n  switch (lexer.curr.token) {\n  | ParenOpen => many(lexer, ParenOpen, parseArgument(~isConst), ParenClose)\n  | _ => Ok([])\n  };\n\nlet parseDirective = (lexer: Lexer.t, ~isConst: bool): result(directive) => {\n  let%Result _ = expect(lexer, At);\n  let%Result name = parseName(lexer);\n  let%Result arguments = parseArguments(lexer, ~isConst);\n  Ok({name, arguments}: directive);\n};\n\nlet parseDirectives = (lexer: Lexer.t, ~isConst: bool) => {\n  let rec collect = directives =>\n    switch (lexer.curr.token) {\n    | At =>\n      let%Result directive = parseDirective(lexer, ~isConst);\n      collect([directive, ...directives]);\n    | _ => Ok(Belt.List.reverse(directives))\n    };\n\n  collect([]);\n};\n\n/* Operation Definitions */\n\nlet parseOperationType = (lexer: Lexer.t): result(Graphql_Language_Ast.operationType) => {\n  switch (lexer.curr.token) {\n  | Name(\"query\") => Result.Ok(Query)\n  | Name(\"mutation\") => Ok(Mutation)\n  | Name(\"subscription\") => Ok(Subscription)\n  | _ => unexpected(lexer)\n  };\n};\n\nlet parseVariableDefinition = (lexer: Lexer.t): result(variableDefinition) => {\n  let%Result variable = parseVariable(lexer);\n  let%Result _ = expect(lexer, Colon);\n  let%Result typ = parseTypeReference(lexer);\n  let%Result directives = parseDirectives(lexer, ~isConst=true);\n  Ok({typ, variable, defaultValue: None, directives});\n};\n\nlet parseVariableDefinitions = (lexer: Lexer.t) =>\n  switch (lexer.curr.token) {\n  | ParenOpen => many(lexer, ParenOpen, parseVariableDefinition, ParenClose)\n  | _ => Ok([])\n  };\n\nlet rec parseSelectionSet = (lexer: Lexer.t): result(list(selection)) => {\n  many(lexer, BraceOpen, parseSelection, BraceClose);\n}\n\nand parseSelection = (lexer: Lexer.t): result(selection) =>\n  switch (lexer.curr.token) {\n  | Spread => parseFragment(lexer)\n  | _ => parseField(lexer)\n  }\n\nand parseFragmentName = (lexer: Lexer.t) =>\n  switch (lexer.curr.token) {\n  | Name(\"on\") => unexpected(lexer)\n  | _ => parseName(lexer)\n  }\n\nand parseFragment = (lexer: Lexer.t) => {\n  let%Result _ = expect(lexer, Spread);\n  let%Result hasTypeCondition = skipKeyword(lexer, \"on\");\n\n  switch (lexer.curr.token) {\n  | Name(_) when !hasTypeCondition =>\n    let%Result name = parseFragmentName(lexer);\n    let%Result directives = parseDirectives(lexer, ~isConst=false);\n    Ok(FragmentSpread({name, directives}));\n  | _ =>\n    let typeCondition =\n      hasTypeCondition\n        ? switch (parseName(lexer)) {\n          | Ok(name) => Some(name)\n          | _ => None\n          }\n        : None;\n    let%Result directives = parseDirectives(lexer, ~isConst=false);\n    let%Result selectionSet = parseSelectionSet(lexer);\n    Ok(InlineFragment({typeCondition, directives, selectionSet}));\n  };\n}\n\nand parseField = (lexer: Lexer.t) => {\n  let%Result name = parseName(lexer);\n\n  let%Result (alias, name) = {\n    let%Result skipped = skip(lexer, Colon);\n    if (skipped) {\n      let%Result name2 = parseName(lexer);\n      Ok((Some(name), name2));\n    } else {\n      Ok((None, name));\n    };\n  };\n\n  let%Result arguments = parseArguments(lexer, ~isConst=false);\n  let%Result directives = parseDirectives(lexer, ~isConst=false);\n  let%Result selectionSet =\n    switch (lexer.curr.token) {\n    | BraceOpen => parseSelectionSet(lexer)\n    | _ => Ok([])\n    };\n\n  Ok(Field({name, alias, arguments, directives, selectionSet}));\n};\n\nlet parseOperationDefinition = (lexer: Lexer.t) =>\n  switch (lexer.curr.token) {\n  | BraceOpen =>\n    let%Result selectionSet = parseSelectionSet(lexer);\n    Ok(\n      Operation({\n        operationType: Query,\n        name: None,\n        variableDefinition: [],\n        directives: [],\n        selectionSet,\n      }),\n    );\n  | _ =>\n    let%Result operationType = parseOperationType(lexer);\n    let%Result _ = Lexer.advance(lexer);\n    let%Result name =\n      switch (lexer.curr.token) {\n      | Name(name) => Lexer.advance(lexer)->Result.map(_ => Some(name))\n      | _ => Ok(None)\n      };\n\n    let%Result variableDefinition = parseVariableDefinitions(lexer);\n    let%Result directives = parseDirectives(lexer, ~isConst=false);\n    let%Result selectionSet = parseSelectionSet(lexer);\n\n    Ok(Operation({operationType, name, variableDefinition, directives, selectionSet}));\n  };\n\nlet parseFragmentDefinition = (lexer: Lexer.t) => {\n  let%Result () = expectKeyword(lexer, \"fragment\");\n  let%Result name = parseFragmentName(lexer);\n  let%Result () = expectKeyword(lexer, \"on\");\n\n  let%Result typeCondition = parseName(lexer);\n  let%Result selectionSet = parseSelectionSet(lexer);\n  let%Result directives = parseDirectives(lexer, ~isConst=false);\n\n  Ok(Fragment({typeCondition, name, selectionSet, directives}));\n};\n\nlet parseExecutableDefinition = (lexer: Lexer.t) =>\n  switch (lexer.curr.token) {\n  | Name(\"query\" | \"mutation\" | \"subscription\")\n  | BraceOpen => parseOperationDefinition(lexer)\n  | Name(\"fragment\") => parseFragmentDefinition(lexer)\n  | _ => unexpected(lexer)\n  };\n\nlet parseDocument = (lexer: Lexer.t): result(document) => {\n  let%Result definitions = many(lexer, StartOfFile, parseExecutableDefinition, EndOfFile);\n  Ok({definitions: definitions});\n};\n\nlet parse = (body: string) => {\n  let lexer = Lexer.make(body);\n  parseDocument(lexer);\n};"
  },
  {
    "path": "reason-graphql/src/language/Graphql_Language_Printer.re",
    "content": "open Graphql_Language_Ast;\n\nlet join = (list, seperator) => Belt.List.keep(list, x => x !== \"\") |> String.concat(seperator);\n\nlet wrap = (left, str, right) => str === \"\" ? \"\" : left ++ str ++ right;\n\nlet indent =\n  fun\n  | \"\" => \"\"\n  | str => \"  \" ++ (str |> Js.String.replaceByRe([%bs.re \"/\\\\n/g\"], \"\\n  \"));\n\nlet block =\n  fun\n  | [] => \"\"\n  | list => \"{\\n\" ++ indent(join(list, \"\\n\")) ++ \"\\n}\";\n\nlet rec printValue: value => string =\n  fun\n  | `Int(int) => Js.Int.toString(int)\n  | `Float(float) => Js.Float.toString(float)\n  | `String(string) => string->Js.Json.string->Js.Json.stringify\n  | `Boolean(bool) => string_of_bool(bool)\n  | `Null => \"null\"\n  | `Variable(string) => \"$\" ++ string\n  | `Enum(enum) => enum\n  | `List(values) => \"[\" ++ join(values |> Belt.List.map(_, printValue), \", \") ++ \"]\"\n  | `Object(fields) => \"{\" ++ printObjectFields(fields) ++ \"}\"\n\nand printObjectFields = fields => fields |> Belt.List.map(_, printObjectField) |> join(_, \", \")\n\nand printObjectField = ((k, v)) => k ++ \": \" ++ printValue(v);\n\nlet rec printType =\n  fun\n  | NamedType(string) => string\n  | ListType(typ) => \"[\" ++ printType(typ) ++ \"]\"\n  | NonNullType(typ) => printType(typ) ++ \"!\";\n\nlet printVariableDef = ({variable, typ}: variableDefinition) =>\n  printValue((variable :> value)) ++ \": \" ++ printType(typ);\nlet printVariables = vars => vars->Belt.List.map(printVariableDef)->join(\", \");\n\nlet printArgument = ((name, value)) => name ++ \": \" ++ printValue(value);\nlet printArguments = (args: list((string, value))) =>\n  args->Belt.List.map(printArgument)->join(\", \");\n\nlet printDirective = ({name, arguments}: directive) =>\n  \"@\" ++ name ++ wrap(\"(\", printArguments(arguments), \")\");\n\nlet printDirectives = directives => directives->Belt.List.map(printDirective)->join(\" \");\n\nlet printOpt =\n  fun\n  | Some(v) => v\n  | None => \"\";\n\nlet rec printSelectionSet = selectionSet =>\n  selectionSet |> Belt.List.map(_, printSelection) |> block\n\nand printSelection =\n  fun\n  | Field(field) => printField(field)\n  | FragmentSpread(fragmentSpread) => printFragmentSpread(fragmentSpread)\n  | InlineFragment(inlineFragmentDefinition) =>\n    printInlineFragmentDefinition(inlineFragmentDefinition)\n\nand printField = ({alias, name, arguments, directives, selectionSet}) =>\n  join(\n    [\n      printAlias(alias) ++ name ++ wrap(\"(\", printArguments(arguments), \")\"),\n      printDirectives(directives),\n      printSelectionSet(selectionSet),\n    ],\n    \" \",\n  )\n\nand printAlias =\n  fun\n  | Some(alias) => alias ++ \": \"\n  | None => \"\"\n\nand printFragmentSpread = ({name, directives}) =>\n  \"...\" ++ name ++ wrap(\" \", printDirectives(directives), \"\")\n\nand printInlineFragmentDefinition = ({typeCondition, selectionSet, directives}) =>\n  join(\n    [\n      \"...\",\n      switch (typeCondition) {\n      | Some(condition) => wrap(\"on \", condition, \"\")\n      | None => \"\"\n      },\n      printDirectives(directives),\n      printSelectionSet(selectionSet),\n    ],\n    \" \",\n  );\n\nlet printOperationDef =\n    ({operationType, variableDefinition, directives, selectionSet} as operationDef) => {\n  let operationTypeStr =\n    switch (operationType) {\n    | Query => \"query\"\n    | Subscription => \"subscription\"\n    | Mutation => \"mutation\"\n    };\n  let varDefs = \"(\" ++ printVariables(variableDefinition) ++ \")\";\n  let directives = printDirectives(directives);\n  let selectionSet = printSelectionSet(selectionSet);\n\n  switch (operationDef) {\n  | {operationType: Query, name: None, directives: [], variableDefinition: []} => selectionSet\n  | {name} =>\n    join(\n      [operationTypeStr, join([printOpt(name), varDefs], \"\"), directives, selectionSet],\n      \" \",\n    )\n  };\n};\n\nlet printFragmentDef = ({name, typeCondition, directives, selectionSet}) =>\n  \"fragment \"\n  ++ name\n  ++ \" on \"\n  ++ typeCondition\n  ++ \" \"\n  ++ wrap(\"\", printDirectives(directives), \" \")\n  ++ printSelectionSet(selectionSet);\n\nlet printDefinition = definition =>\n  switch (definition) {\n  | Operation(operationDef) => printOperationDef(operationDef)\n  | Fragment(fragmentDef) => printFragmentDef(fragmentDef)\n  };\n\nlet print = ({definitions}: document) =>\n  definitions |> Belt.List.map(_, printDefinition) |> join(_, \"\\n\\n\");\n"
  },
  {
    "path": "reason-graphql-bs-express/bsconfig.json",
    "content": "{\n  \"name\": \"reason-graphql-bs-express\",\n  \"version\": \"0.6.0\",\n  \"sources\": [\n    {\n      \"dir\": \"src\",\n      \"subdirs\": true\n    },\n    {\n      \"dir\": \"examples\",\n      \"type\" : \"dev\"\n    }\n  ],\n  \"package-specs\": {\n    \"module\": \"commonjs\",\n    \"in-source\": true\n  },\n  \"suffix\": \".bs.js\",\n  \"warnings\": {\n    \"number\": \"-45-44\",\n    \"error\": \"+101\"\n  },\n  \"bs-dependencies\": [\"reason-graphql\", \"bs-express\", \"reason-future\"],\n  \"namespace\": false,\n  \"refmt\": 3\n}\n"
  },
  {
    "path": "reason-graphql-bs-express/examples/server.re",
    "content": "type ctx = {userIP: string};\n\nmodule HelloWorldSchema = {\n  open GraphqlJsPromise;\n\n  let rootQuery =\n    Schema.(\n      query([\n        field(\n          \"hello\",\n          nonnull(string),\n          ~args=Arg.[defaultArg(\"name\", string, ~default=\"world\")],\n          ~resolve=(ctx, (), name) =>\n          name ++ \" (\" ++ ctx.userIP ++ \")\"\n        ),\n        async_field(\n          \"helloAsync\",\n          nonnull(string),\n          ~args=Arg.[defaultArg(\"name\", string, ~default=\"world\")],\n          ~resolve=(ctx, (), name) =>\n          Js.Promise.resolve(\n            Belt.Result.Ok(name ++ \" (\" ++ ctx.userIP ++ \")\"),\n          )\n        ),\n      ])\n    );\n\n  let schema = Schema.create(rootQuery);\n};\n\nopen Express;\n\nlet app = express();\n\nApp.use(app, Middleware.json(~limit=ByteLimit.mb(5.0), ()));\n\nApp.useOnPath(app, ~path=\"/graphql\") @@\nGraphqlExpress.middleware(\n  HelloWorldSchema.schema,\n  ~provideCtx=(req, _res) => {userIP: Request.ip(req)},\n  ~graphiql=true,\n);\n\nlet onListen = e =>\n  switch (e) {\n  | exception (Js.Exn.Error(e)) =>\n    Js.log(e);\n    Node.Process.exit(1);\n  | _ => Js.log(\"Listening at http://127.0.0.1:3000\")\n  };\n\nApp.listen(app, ~port=3000, ~onListen, ());"
  },
  {
    "path": "reason-graphql-bs-express/package.json",
    "content": "{\n  \"name\": \"reason-graphql-bs-express\",\n  \"version\": \"0.6.0\",\n  \"author\": \"Sikan He\",\n  \"license\": \"MIT\",\n  \"repository\": \"https://github.com/sikanhe/reason-graphql/reason-graphql-bs-express\",\n  \"homepage\": \"https://github.com/sikanhe/reason-graphql/reason-graphql-bs-express#readme\",\n  \"keywords\": [\n    \"BuckleScript\",\n    \"GraphQL\",\n    \"Express\",\n    \"Reason\",\n    \"ReasonML\"\n  ],\n  \"scripts\": {\n    \"build\": \"bsb -make-world\",\n    \"start\": \"bsb -make-world -w\",\n    \"clean\": \"bsb -clean-world\",\n    \"test\": \"yarn build && jest\"\n  },\n  \"files\": [\n    \"src/\",\n    \"bsconfig.json\"\n  ],\n  \"devDependencies\": {\n    \"bs-platform\": \"^7.0.0\",\n    \"reason-graphql\": \"^0.6.0\",\n    \"bs-express\": \"^0.12.0\",\n    \"reason-future\": \"^2.4.0\"\n  },\n  \"peerDependencies\": {\n    \"reason-graphql\": \"^0.6.0\",\n    \"bs-express\": \"^0.12.0\",\n    \"reason-future\": \"^2.4.0\",\n    \"bs-platform\": \">= 7.0.0\"\n  }\n}\n"
  },
  {
    "path": "reason-graphql-bs-express/src/Graphiql.re",
    "content": "let html = {j|\n<!--\nThe request to this GraphQL server provided the header \"Accept: text/html\"\nand as a result has been presented GraphiQL - an in-browser IDE for\nexploring GraphQL.\nIf you wish to receive JSON, provide the header \"Accept: application/json\" or\nadd \"&raw\" to the end of the URL within a browser.\n-->\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\" />\n  <title>GraphiQL</title>\n  <meta name=\"robots\" content=\"noindex\" />\n  <meta name=\"referrer\" content=\"origin\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <style>\n    body {\n      margin: 0;\n      overflow: hidden;\n    }\n    #graphiql {\n      height: 100vh;\n    }\n  </style>\n  <link href=\"//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.css\" rel=\"stylesheet\" />\n  <script src=\"//cdn.jsdelivr.net/es6-promise/4.0.5/es6-promise.auto.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/react/15.4.2/react.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js\"></script>\n  <script src=\"//cdn.jsdelivr.net/npm/graphiql@0.12.0/graphiql.min.js\"></script>\n</head>\n<body>\n  <div id=\"graphiql\">Loading...</div>\n  <script>\n    // Collect the URL parameters\n    var parameters = {};\n    window.location.search.substr(1).split('&').forEach(function (entry) {\n      var eq = entry.indexOf('=');\n      if (eq >= 0) {\n        parameters[decodeURIComponent(entry.slice(0, eq))] =\n          decodeURIComponent(entry.slice(eq + 1));\n      }\n    });\n    // Produce a Location query string from a parameter object.\n    function locationQuery(params) {\n      return '?' + Object.keys(params).filter(function (key) {\n        return Boolean(params[key]);\n      }).map(function (key) {\n        return encodeURIComponent(key) + '=' +\n          encodeURIComponent(params[key]);\n      }).join('&');\n    }\n    // Derive a fetch URL from the current URL, sans the GraphQL parameters.\n    var graphqlParamNames = {\n      query: true,\n      variables: true,\n      operationName: true\n    };\n    var otherParams = {};\n    for (var k in parameters) {\n      if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) {\n        otherParams[k] = parameters[k];\n      }\n    }\n    var fetchURL = locationQuery(otherParams);\n    // Defines a GraphQL fetcher using the fetch API.\n    function graphQLFetcher(graphQLParams) {\n      return fetch(fetchURL, {\n        method: 'post',\n        headers: {\n          'Accept': 'application/json',\n          'Content-Type': 'application/json'\n        },\n        body: JSON.stringify(graphQLParams),\n        credentials: 'include',\n      }).then(function (response) {\n        return response.json();\n      });\n    }\n    // When the query and variables string is edited, update the URL bar so\n    // that it can be easily shared.\n    function onEditQuery(newQuery) {\n      parameters.query = newQuery;\n      updateURL();\n    }\n    function onEditVariables(newVariables) {\n      parameters.variables = newVariables;\n      updateURL();\n    }\n    function onEditOperationName(newOperationName) {\n      parameters.operationName = newOperationName;\n      updateURL();\n    }\n    function updateURL() {\n      history.replaceState(null, null, locationQuery(parameters));\n    }\n    // Render <GraphiQL /> into the body.\n    ReactDOM.render(\n      React.createElement(GraphiQL, {\n        fetcher: graphQLFetcher,\n        onEditQuery: onEditQuery,\n        onEditVariables: onEditVariables,\n        onEditOperationName: onEditOperationName\n      }),\n      document.getElementById('graphiql')\n    );\n  </script>\n</body>\n</html>\n|j};"
  },
  {
    "path": "reason-graphql-bs-express/src/GraphqlExpress.re",
    "content": "open Express;\n\nlet parseBodyIntoDocumentAndVariables = req => {\n  switch (Request.bodyJSON(req)) {\n  | Some(body) =>\n    switch (Js.Json.decodeObject(body)) {\n    | Some(body) =>\n      switch (Js.Dict.get(body, \"query\")) {\n      | Some(query) =>\n        switch (Js.Json.decodeString(query)) {\n        | Some(queryString) =>\n          switch (Graphql.Language.Parser.parse(queryString)) {\n          | Ok(document) =>\n            switch (Js.Dict.get(body, \"variables\")) {\n            | Some(variablesJson) =>\n              switch (Graphql.Json.toVariables(variablesJson)) {\n              | Ok(variables) => Belt.Result.Ok((document, Some(variables)))\n              | Error(_) => Ok((document, None))\n              }\n            | None => Ok((document, None))\n            }\n          | Error(SyntaxError(s)) => Error(\"GraphQL Syntax Error: \" ++ s)\n          }\n        | None => Error(\"Query must be a string\")\n        }\n      | None => Error(\"Must provide Query string\")\n      }\n    | None => Error(\"body must be an JSON object\")\n    }\n  | None => Error(\"no body found\")\n  };\n};\n\nlet middleware = (~provideCtx, ~graphiql=false, schema) =>\n  PromiseMiddleware.from((next, req, res) =>\n    switch (Request.methodRaw(req)) {\n    | \"GET\" when graphiql =>\n      res\n      |> Response.status(Response.StatusCode.Ok)\n      |> Response.sendString(Graphiql.html)\n      |> Js.Promise.resolve\n    | \"POST\" =>\n      switch (parseBodyIntoDocumentAndVariables(req)) {\n      | Ok((document, variables)) =>\n        GraphqlJsPromise.Schema.execute(\n          schema,\n          ~document,\n          ~variables?,\n          ~ctx=provideCtx(req, res),\n        )\n        |> Js.Promise.(\n             then_(const => resolve(Graphql.Json.fromConstValue(const)))\n           )\n        |> Js.Promise.(then_(json => resolve(Response.sendJson(json, res))))\n      | Error(error) =>\n        res\n        |> Response.status(Response.StatusCode.BadRequest)\n        |> Response.sendString(error)\n        |> Js.Promise.resolve\n      }\n    | _ => Js.Promise.resolve(next(Next.route, res))\n    }\n  );"
  }
]