├── .changeset └── config.json ├── .github └── workflows │ ├── main.yaml │ └── pr.yaml ├── .gitignore ├── .node-version ├── .prettierignore ├── .vscode └── launch.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __tests__ ├── ast.spec.ts ├── composition.spec.ts ├── context.spec.ts ├── cost.spec.ts ├── fixtures │ ├── dgs │ │ ├── aside397.graphql │ │ ├── blink5ab.graphql │ │ ├── cower3fc.graphql │ │ ├── fooey584.graphql │ │ ├── houndd92.graphql │ │ ├── index.ts │ │ ├── light7e6.graphql │ │ ├── pedaladf.graphql │ │ ├── roughb27.graphql │ │ ├── truly859.graphql │ │ ├── yahoob90.graphql │ │ └── yowza9a2.graphql │ ├── huge-schema │ │ ├── abaft153.graphql │ │ ├── abaft8d7.graphql │ │ ├── aboutb1b.graphql │ │ ├── aboutd91.graphql │ │ ├── above94b.graphql │ │ ├── abovedd1.graphql │ │ ├── afore2c3.graphql │ │ ├── afore5e4.graphql │ │ ├── after472.graphql │ │ ├── after83a.graphql │ │ ├── after980.graphql │ │ ├── afterd2d.graphql │ │ ├── afterd8f.graphql │ │ ├── along16c.graphql │ │ ├── along863.graphql │ │ ├── aside675.graphql │ │ ├── awful36b.graphql │ │ ├── awfule02.graphql │ │ ├── badlycf7.graphql │ │ ├── barge35d.graphql │ │ ├── basic2c5.graphql │ │ ├── blastcfe.graphql │ │ ├── bleak694.graphql │ │ ├── briskd12.graphql │ │ ├── brown286.graphql │ │ ├── bumpy9b4.graphql │ │ ├── cable842.graphql │ │ ├── cachec31.graphql │ │ ├── cadetd21.graphql │ │ ├── calve743.graphql │ │ ├── caulk096.graphql │ │ ├── chaincad.graphql │ │ ├── clear16f.graphql │ │ ├── crazy511.graphql │ │ ├── crick357.graphql │ │ ├── crisp90e.graphql │ │ ├── dairyda2.graphql │ │ ├── demura89.graphql │ │ ├── dimly0fe.graphql │ │ ├── elopee3c.graphql │ │ ├── empty2e8.graphql │ │ ├── empty5de.graphql │ │ ├── fatalca0.graphql │ │ ├── fooey02f.graphql │ │ ├── fooey461.graphql │ │ ├── fooey518.graphql │ │ ├── fooey770.graphql │ │ ├── fooey80a.graphql │ │ ├── fooeya02.graphql │ │ ├── fooeyb81.graphql │ │ ├── fooeyb9c.graphql │ │ ├── fooeybdb.graphql │ │ ├── fooeydd7.graphql │ │ ├── fruit721.graphql │ │ ├── fully0b0.graphql │ │ ├── fully3d9.graphql │ │ ├── fullya44.graphql │ │ ├── fullyc09.graphql │ │ ├── funny080.graphql │ │ ├── ghostf0d.graphql │ │ ├── given37c.graphql │ │ ├── gooseaf0.graphql │ │ ├── grand2ef.graphql │ │ ├── grape597.graphql │ │ ├── greenf15.graphql │ │ ├── hence24f.graphql │ │ ├── hence36a.graphql │ │ ├── hence3ff.graphql │ │ ├── hence5bd.graphql │ │ ├── hencec8e.graphql │ │ ├── horde104.graphql │ │ ├── inboxe70.graphql │ │ ├── index.ts │ │ ├── laborf54.graphql │ │ ├── lemurfc5.graphql │ │ ├── light4ff.graphql │ │ ├── loyalb06.graphql │ │ ├── lucky89a.graphql │ │ ├── madly1a2.graphql │ │ ├── madly4dc.graphql │ │ ├── madly561.graphql │ │ ├── madly868.graphql │ │ ├── midstaf0.graphql │ │ ├── minus163.graphql │ │ ├── minusb54.graphql │ │ ├── misty6fc.graphql │ │ ├── mutedc95.graphql │ │ ├── never613.graphql │ │ ├── never804.graphql │ │ ├── neverde7.graphql │ │ ├── nifty88a.graphql │ │ ├── ninja145.graphql │ │ ├── nudge7d0.graphql │ │ ├── oddly7d3.graphql │ │ ├── oddlye05.graphql │ │ ├── oftenee9.graphql │ │ ├── paneld05.graphql │ │ ├── panic018.graphql │ │ ├── pearlb19.graphql │ │ ├── petty951.graphql │ │ ├── pettydce.graphql │ │ ├── phase03c.graphql │ │ ├── plant5f3.graphql │ │ ├── plier64f.graphql │ │ ├── prangd95.graphql │ │ ├── proudd53.graphql │ │ ├── prove4b5.graphql │ │ ├── prowl499.graphql │ │ ├── quieta6f.graphql │ │ ├── rayon4de.graphql │ │ ├── round642.graphql │ │ ├── round69d.graphql │ │ ├── round8c6.graphql │ │ ├── roundd33.graphql │ │ ├── rumor620.graphql │ │ ├── runnyd80.graphql │ │ ├── rustyf69.graphql │ │ ├── sadly5f8.graphql │ │ ├── scowla5e.graphql │ │ ├── shadeb17.graphql │ │ ├── short4ee.graphql │ │ ├── shortb6d.graphql │ │ ├── shyly267.graphql │ │ ├── silky0a2.graphql │ │ ├── since6fe.graphql │ │ ├── since846.graphql │ │ ├── since924.graphql │ │ ├── sincebab.graphql │ │ ├── sincec84.graphql │ │ ├── sinced9c.graphql │ │ ├── skate1dc.graphql │ │ ├── skulk70a.graphql │ │ ├── southcc8.graphql │ │ ├── stack077.graphql │ │ ├── stage087.graphql │ │ ├── stain45f.graphql │ │ ├── statef41.graphql │ │ ├── steak823.graphql │ │ ├── steer4fc.graphql │ │ ├── stock2e0.graphql │ │ ├── straw54b.graphql │ │ ├── swing58c.graphql │ │ ├── tempt308.graphql │ │ ├── tensed9c.graphql │ │ ├── these6e8.graphql │ │ ├── thirdee4.graphql │ │ ├── tight863.graphql │ │ ├── times42f.graphql │ │ ├── total5a8.graphql │ │ ├── tough36b.graphql │ │ ├── trump9a5.graphql │ │ ├── undera5c.graphql │ │ ├── unify1d7.graphql │ │ ├── until434.graphql │ │ ├── untilcd9.graphql │ │ ├── valid7f8.graphql │ │ ├── violaaf7.graphql │ │ ├── weepy585.graphql │ │ ├── weird481.graphql │ │ ├── wetly057.graphql │ │ ├── wetly4cd.graphql │ │ ├── wetly78d.graphql │ │ ├── where2d0.graphql │ │ ├── whereaca.graphql │ │ ├── which499.graphql │ │ ├── while25f.graphql │ │ ├── while467.graphql │ │ ├── while7b3.graphql │ │ ├── while9ec.graphql │ │ ├── whose503.graphql │ │ ├── whose655.graphql │ │ ├── whosef42.graphql │ │ ├── yahoo0d7.graphql │ │ ├── yahoo6e1.graphql │ │ ├── yahoo790.graphql │ │ ├── yahoo851.graphql │ │ ├── yahoo9aa.graphql │ │ ├── yahood2a.graphql │ │ ├── yahood94.graphql │ │ ├── yahooeb6.graphql │ │ ├── young08b.graphql │ │ ├── yowza1c7.graphql │ │ ├── yowza842.graphql │ │ ├── yowza9c4.graphql │ │ ├── yowzaa01.graphql │ │ ├── yowzacf7.graphql │ │ ├── yowzad5f.graphql │ │ ├── zowie226.graphql │ │ ├── zowie2fa.graphql │ │ ├── zowieb75.graphql │ │ ├── zowiebe0.graphql │ │ └── zowied65.graphql │ └── stars-stuff.ts ├── graphql │ ├── sort-sdl.spec.ts │ └── transform-supergraph-to-public-schema.spec.ts ├── interface-object-composition.spec.ts ├── override-with-label.spec.ts ├── shared │ ├── setup.ts │ ├── test.d.ts │ ├── testkit.ts │ └── utils.ts ├── subgraph-validation-and-compositon-root-query.spec.ts ├── subgraph │ ├── errors │ │ ├── DIRECTIVE_COMPOSITION_ERROR.spec.ts │ │ ├── DIRECTIVE_DEFINITION_INVALID.spec.ts │ │ ├── EXTERNAL_UNUSED.spec.ts │ │ ├── INTERFACE_KEY_NOT_ON_IMPLEMENTATION.spec.ts │ │ ├── INVALID_GRAPHQL.spec.ts │ │ ├── INVALID_SHAREABLE_USAGE.spec.ts │ │ ├── INVALID_SUBGRAPH_NAME.spec.ts │ │ ├── KEY_DIRECTIVE_IN_FIELDS_ARG.spec.ts │ │ ├── KEY_FIELDS_HAS_ARGS.spec.ts │ │ ├── KEY_FIELDS_SELECT_INVALID_TYPE.spec.ts │ │ ├── KEY_INVALID_FIELDS.spec.ts │ │ ├── KEY_INVALID_FIELDS_TYPE.spec.ts │ │ ├── KEY_UNSUPPORTED_ON_INTERFACE.spec.ts │ │ ├── MERGED_DIRECTIVE_APPLICATION_ON_EXTERNAL.spec.ts │ │ ├── OVERRIDE_FROM_SELF_ERROR.spec.ts │ │ ├── OVERRIDE_ON_INTERFACE.spec.ts │ │ ├── PROVIDES_DIRECTIVE_IN_FIELDS_ARG.spec.ts │ │ ├── PROVIDES_FIELDS_HAS_ARGS.spec.ts │ │ ├── PROVIDES_FIELDS_MISSING_EXTERNAL.spec.ts │ │ ├── PROVIDES_INVALID_FIELDS.spec.ts │ │ ├── PROVIDES_INVALID_FIELDS_TYPE.spec.ts │ │ ├── PROVIDES_ON_NON_OBJECT_FIELD.spec.ts │ │ ├── PROVIDES_UNSUPPORTED_ON_INTERFACE.spec.ts │ │ ├── QUERY_ROOT_TYPE_INACCESSIBLE.spec.ts │ │ ├── REQUIRES_DIRECTIVE_IN_FIELDS_ARG.spec.ts │ │ ├── REQUIRES_FIELDS_MISSING_EXTERNAL.spec.ts │ │ ├── REQUIRES_INVALID_FIELDS.spec.ts │ │ ├── REQUIRES_INVALID_FIELDS_TYPE.spec.ts │ │ ├── REQUIRES_UNSUPPORTED_ON_INTERFACE.spec.ts │ │ ├── ROOT_MUTATION_USED.spec.ts │ │ ├── ROOT_QUERY_USED.spec.ts │ │ ├── ROOT_SUBSCRIPTION_USED.spec.ts │ │ └── TYPE_DEFINITION_INVALID.spec.ts │ ├── federation-directives.spec.ts │ ├── key-fields.spec.ts │ ├── link-directive.spec.ts │ └── to-categorize.spec.ts ├── supergraph-composition.spec.ts ├── supergraph │ ├── base.spec.ts │ ├── errors │ │ ├── DEFAULT_VALUE_USES_INACCESSIBLE.spec.ts │ │ ├── EMPTY_MERGED_ENUM_TYPE.spec.ts │ │ ├── EMPTY_MERGED_INPUT_TYPE.spec.ts │ │ ├── ENUM_VALUE_MISMATCH.spec.ts │ │ ├── EXTENSION_WITH_NO_BASE.spec.ts │ │ ├── EXTERNAL_ARGUMENT_MISSING.spec.ts │ │ ├── EXTERNAL_MISSING_ON_BASE.spec.ts │ │ ├── EXTERNAL_TYPE_MISMATCH.spec.ts │ │ ├── FIELD_ARGUMENT_DEFAULT_MISMATCH.spec.ts │ │ ├── FIELD_ARGUMENT_TYPE_MISMATCH.spec.ts │ │ ├── FIELD_TYPE_MISMATCH.spec.ts │ │ ├── IMPLEMENTED_BY_INACCESSIBLE.spec.ts │ │ ├── INPUT_FIELD_DEFAULT_MISMATCH.spec.ts │ │ ├── INTERFACE_FIELD_NO_IMPLEM.spec.ts │ │ ├── INTERFACE_KEY_MISSING_IMPLEMENTATION_TYPE.spec.ts │ │ ├── INTERFACE_OBJECT_USAGE_ERROR.spec.ts │ │ ├── INVALID-GRAPHQL.spec.ts │ │ ├── INVALID_FIELD_SHARING.spec.ts │ │ ├── NO_QUERIES.spec.ts │ │ ├── ONLY_INACCESSIBLE_CHILDREN.spec.ts │ │ ├── OVERRIDE_COLLISION_WITH_ANOTHER_DIRECTIVE.spec.ts │ │ ├── OVERRIDE_SOURCE_HAS_OVERRIDE.spec.ts │ │ ├── REFERENCED_INACCESSIBLE.spec.ts │ │ ├── REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH.spec.ts │ │ ├── REQUIRED_INACCESSIBLE.spec.ts │ │ ├── REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH.spec.ts │ │ ├── SATISFIABILITY_ERROR.spec.ts │ │ └── TYPE_KIND_MISMATCH.spec.ts │ ├── join.spec.ts │ └── link.spec.ts ├── todo.spec.ts └── utils │ ├── extract-link.spec.ts │ ├── link-url.spec.ts │ └── link.spec.ts ├── benchmark.ts ├── compose.ts ├── package.json ├── pnpm-lock.yaml ├── renovate.json ├── src ├── compose.ts ├── graphql │ ├── contains-supergraph-spec.ts │ ├── helpers.ts │ ├── printer.ts │ ├── sort-sdl.ts │ ├── supergraph-spec.ts │ ├── transform-supergraph-to-public-schema.ts │ └── type-node-info.ts ├── index.ts ├── specifications │ ├── authenticated.ts │ ├── cost.ts │ ├── federation.ts │ ├── inaccessible.ts │ ├── join.ts │ ├── link.spec.ts │ ├── link.ts │ ├── policy.ts │ ├── requires-scopes.ts │ └── tag.ts ├── subgraph │ ├── helpers.ts │ ├── state.ts │ └── validation │ │ ├── rules │ │ ├── elements │ │ │ ├── authenticated.ts │ │ │ ├── compose-directive.ts │ │ │ ├── context.ts │ │ │ ├── cost.ts │ │ │ ├── extends.ts │ │ │ ├── external.ts │ │ │ ├── field-set.ts │ │ │ ├── from-context.ts │ │ │ ├── inaccessible.ts │ │ │ ├── interface-object.ts │ │ │ ├── key.ts │ │ │ ├── list-size.ts │ │ │ ├── override.ts │ │ │ ├── policy.ts │ │ │ ├── provides.ts │ │ │ ├── requires-scopes.ts │ │ │ ├── requires.ts │ │ │ ├── shareable.ts │ │ │ └── tag.ts │ │ ├── known-argument-names-on-directives-rule.ts │ │ ├── known-directives-rule.ts │ │ ├── known-federation-directive-rule.ts │ │ ├── known-root-type-rule.ts │ │ ├── known-type-names-rule.ts │ │ ├── lone-schema-definition-rule.ts │ │ ├── only-interface-implementation-rule.ts │ │ ├── provided-arguments-on-directives-rule.ts │ │ ├── provided-required-arguments-on-directives-rule.ts │ │ ├── query-root-type-inaccessible-rule.ts │ │ ├── reserved-subgraph-name-rule.ts │ │ ├── root-type-used-rule.ts │ │ ├── unique-argument-definition-names-rule.ts │ │ ├── unique-argument-names-rule.ts │ │ ├── unique-directive-names-rule.ts │ │ ├── unique-directives-per-location-rule.ts │ │ ├── unique-enum-value-names-rule.ts │ │ ├── unique-field-definition-names-rule.ts │ │ ├── unique-input-field-names-rule.ts │ │ ├── unique-operation-types-rule.ts │ │ └── unique-type-names-rule.ts │ │ ├── validate-state.ts │ │ ├── validate-subgraph.ts │ │ └── validation-context.ts ├── supergraph │ ├── composition │ │ ├── ast.ts │ │ ├── common.ts │ │ ├── directive.ts │ │ ├── enum-type.ts │ │ ├── input-object-type.ts │ │ ├── interface-type.ts │ │ ├── object-type.ts │ │ ├── scalar-type.ts │ │ ├── union-type.ts │ │ └── visitor.ts │ ├── state.ts │ └── validation │ │ ├── rules │ │ ├── default-value-uses-inaccessible-rule.ts │ │ ├── directive-composition-rule.ts │ │ ├── enum-values-rule.ts │ │ ├── extension-with-base.ts │ │ ├── external-argument-missing-rule.ts │ │ ├── external-missing-on-base-rule.ts │ │ ├── external-type-mismatch-rule.ts │ │ ├── field-argument-default-mismatch-rule.ts │ │ ├── field-arguments-of-the-same-type-rule.ts │ │ ├── fields-of-the-same-type-rule.ts │ │ ├── input-field-default-mismatch-rule.ts │ │ ├── input-object-values-rule.ts │ │ ├── interface-field-no-implementation-rule.ts │ │ ├── interface-key-missing-implementation-type.ts │ │ ├── interface-object-usage-error.ts │ │ ├── interface-subtype-rule.ts │ │ ├── invalid-field-sharing-rule.ts │ │ ├── link-import-name-mismatch-rule.ts │ │ ├── no-inaccessible-on-implemented-interface-fields-rule.ts │ │ ├── only-inaccessible-children-rule.ts │ │ ├── override-source-has-override.ts │ │ ├── referenced-inaccessible-rule.ts │ │ ├── required-argument-missing-in-some-subgraph-rule.ts │ │ ├── required-argument-or-field-is-not-inaccessible-rule.ts │ │ ├── required-input-field-missing-in-some-subgraph-rule.ts │ │ ├── required-query-rule.ts │ │ ├── satisfiablity-rule.ts │ │ ├── satisfiablity │ │ │ ├── constants.ts │ │ │ ├── edge.ts │ │ │ ├── errors.ts │ │ │ ├── finder.ts │ │ │ ├── graph.ts │ │ │ ├── helpers.ts │ │ │ ├── move-validator.ts │ │ │ ├── moves.ts │ │ │ ├── node.ts │ │ │ ├── notes.md │ │ │ ├── operation-path.ts │ │ │ ├── selection.ts │ │ │ ├── supergraph.ts │ │ │ └── walker.ts │ │ ├── subgraph-name-rule.ts │ │ └── types-of-the-same-kind-rule.ts │ │ ├── validate-supergraph.ts │ │ └── validation-context.ts ├── types.ts ├── utils │ ├── dependency-graph.ts │ ├── format.ts │ ├── helpers.ts │ ├── link │ │ ├── index.ts │ │ ├── link-import.ts │ │ ├── link-url.ts │ │ └── link.ts │ ├── logger.ts │ ├── state.ts │ └── version.ts └── validate.ts ├── tsconfig.build.json ├── tsconfig.json └── vitest.config.js /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.1.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { "repo": "graphql-hive/federation-composition" } 6 | ], 7 | "commit": false, 8 | "linked": [], 9 | "access": "restricted", 10 | "baseBranch": "main", 11 | "updateInternalDependencies": "patch", 12 | "snapshot": { 13 | "useCalculatedVersion": true, 14 | "prereleaseTemplate": "{tag}-{datetime}-{commit}" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | stable: 8 | uses: the-guild-org/shared-config/.github/workflows/release-stable.yml@main 9 | with: 10 | releaseScript: release 11 | nodeVersion: 21 12 | packageManager: "pnpm" 13 | secrets: 14 | githubToken: ${{ secrets.GITHUB_TOKEN }} 15 | npmToken: ${{ secrets.NPM_TOKEN }} 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | dist 5 | *.cpuprofile 6 | .bob 7 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 22 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | patches 2 | pnpm-lock.yaml 3 | dist 4 | .bob 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "Debug Current Test File", 8 | "autoAttachChildProcesses": true, 9 | "skipFiles": ["/**", "**/node_modules/**"], 10 | "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs", 11 | "args": ["run", "${relativeFile}"], 12 | "smartStep": true, 13 | "console": "integratedTerminal" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 The Guild 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 8 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial 12 | portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 15 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 17 | OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /__tests__/fixtures/dgs/aside397.graphql: -------------------------------------------------------------------------------- 1 | schema 2 | @link(url: "https://specs.apollo.dev/link/v1.0") 3 | @link( 4 | url: "https://specs.apollo.dev/federation/v2.0" 5 | import: [ 6 | "@key" 7 | "@external" 8 | "@provides" 9 | "@requires" 10 | "@extends" 11 | "@shareable" 12 | "@tag" 13 | "@inaccessible" 14 | ] 15 | ) { 16 | query: Query 17 | } 18 | 19 | directive @extends on INTERFACE | OBJECT 20 | 21 | directive @external(reason: String) on FIELD_DEFINITION | OBJECT 22 | 23 | directive @key( 24 | fields: federation__FieldSet! 25 | resolvable: Boolean = true 26 | ) repeatable on INTERFACE | OBJECT 27 | 28 | directive @link( 29 | as: String 30 | for: link__Purpose 31 | import: [link__Import] 32 | url: String 33 | ) repeatable on SCHEMA 34 | 35 | directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION 36 | 37 | directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION 38 | 39 | directive @shareable on FIELD_DEFINITION | OBJECT 40 | 41 | directive @tag( 42 | name: String! 43 | ) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION 44 | 45 | enum whosec2c { 46 | first056 47 | slicee5f 48 | } 49 | 50 | type plate86e @extends @key(fields: "adornea4") { 51 | adornea4: smalld4d! @external 52 | attic76e(afteread: String, clamp48d: merry98b): haunte5e 53 | } 54 | 55 | scalar smalld4d 56 | 57 | type haunte5e { 58 | swiftbdc: Boolean 59 | } 60 | 61 | enum yahoo73c { 62 | whose4aa 63 | alive170 64 | crickebd 65 | } 66 | 67 | type Query 68 | 69 | input merry98b { 70 | rigid037: Float! 71 | along562: yahoo73c! 72 | } 73 | 74 | scalar roundd32 75 | 76 | scalar federation__FieldSet 77 | 78 | scalar link__Import 79 | 80 | enum link__Purpose { 81 | EXECUTION 82 | SECURITY 83 | } 84 | -------------------------------------------------------------------------------- /__tests__/fixtures/dgs/fooey584.graphql: -------------------------------------------------------------------------------- 1 | schema 2 | @link(url: "https://specs.apollo.dev/link/v1.0") 3 | @link( 4 | url: "https://specs.apollo.dev/federation/v2.0" 5 | import: [ 6 | "@key" 7 | "@external" 8 | "@provides" 9 | "@requires" 10 | "@extends" 11 | "@shareable" 12 | "@tag" 13 | "@inaccessible" 14 | ] 15 | ) { 16 | query: Query 17 | } 18 | 19 | directive @extends on INTERFACE | OBJECT 20 | 21 | directive @external(reason: String) on FIELD_DEFINITION | OBJECT 22 | 23 | directive @key( 24 | fields: federation__FieldSet! 25 | resolvable: Boolean = true 26 | ) repeatable on INTERFACE | OBJECT 27 | 28 | directive @link( 29 | as: String 30 | for: link__Purpose 31 | import: [link__Import] 32 | url: String 33 | ) repeatable on SCHEMA 34 | 35 | directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION 36 | 37 | directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION 38 | 39 | directive @shareable on FIELD_DEFINITION | OBJECT 40 | 41 | directive @tag( 42 | name: String! 43 | ) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION 44 | 45 | enum whosec2c { 46 | first056 47 | slicee5f 48 | } 49 | 50 | type plate86e @key(fields: "adornea4") { 51 | adornea4: smalld4d! 52 | } 53 | 54 | scalar smalld4d 55 | 56 | type Query { 57 | fullyd8a(straw54a: Float!): glass5d1! 58 | abaft1ac(horse812: String): glass5d1! @deprecated(reason: "") 59 | spark92e(afore878: String!): glass5d1! 60 | stoved9e(dolor352: String!): glass5d1! 61 | } 62 | 63 | type glass5d1 @key(fields: "dolor352 straw54a") { 64 | fooeyfc9: plate86e! @shareable 65 | straw54a: String! 66 | until22e: String @shareable 67 | dolor352: String! 68 | } 69 | 70 | scalar roundd32 71 | 72 | scalar federation__FieldSet 73 | 74 | scalar link__Import 75 | 76 | enum link__Purpose { 77 | EXECUTION 78 | SECURITY 79 | } 80 | -------------------------------------------------------------------------------- /__tests__/fixtures/dgs/index.ts: -------------------------------------------------------------------------------- 1 | import { readdir, readFile } from "node:fs/promises"; 2 | import { DocumentNode, parse } from "graphql"; 3 | 4 | const __dirname = new URL(".", import.meta.url).pathname; 5 | 6 | export async function getSubgraphs() { 7 | const files = await readdir(`${__dirname}`); 8 | const subgraphs: Array<{ 9 | name: string; 10 | typeDefs: DocumentNode; 11 | }> = []; 12 | 13 | for await (const file of files) { 14 | if (file.endsWith(".graphql")) { 15 | const schema = await readFile(`${__dirname}/${file}`, "utf8"); 16 | const parsedSchema = parse(schema, { 17 | noLocation: true, 18 | }); 19 | 20 | subgraphs.push({ 21 | name: file.replace(".graphql", ""), 22 | typeDefs: parsedSchema, 23 | }); 24 | } 25 | } 26 | 27 | return subgraphs; 28 | } 29 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/abaft8d7.graphql: -------------------------------------------------------------------------------- 1 | scalar timesabb 2 | 3 | scalar dimlyf7b 4 | 5 | scalar until598 6 | 7 | enum blanka08 { 8 | dimly030 9 | yahoo2a4 10 | times43c 11 | } 12 | 13 | type dramacc4 @key(fields: "slinkcdd") @extends { 14 | slinkcdd: ID @external 15 | circabb9(zowie2b5: String!, shylyf5a: String!): zowie8ef 16 | } 17 | 18 | type zowie8ef { 19 | still876: after466! 20 | } 21 | 22 | type badlycc1 { 23 | yahoo03d: dimlyf7b! 24 | humor476: dimlyf7b! 25 | zowie085: dimlyf7b! 26 | south0a6: dimlyf7b! 27 | hence000: [dimlyf7b!]! 28 | sadly8fc: dimlyf7b! 29 | while48e: bogus3d9! 30 | } 31 | 32 | type bogus3d9 { 33 | shacke74: dimlyf7b! 34 | chiefea7: timesabb! 35 | } 36 | 37 | type midstcb8 { 38 | yowza299: String! 39 | yowza2d5: String 40 | } 41 | 42 | type torsobbe { 43 | chiefea7: timesabb! 44 | hence6ce: badlycc1! 45 | yowza32d: badlycc1! 46 | clerk946: badlycc1! 47 | circae68: badlycc1! 48 | } 49 | 50 | type yowza466 { 51 | until71d: dimlyf7b! 52 | silky80a: dimlyf7b! 53 | hedge1d2: dimlyf7b! 54 | shylyf5a: until598 55 | sushi483: Boolean! 56 | which888: bogus3d9! 57 | abovef1c: dimlyf7b! 58 | truly5ca: [torsobbe!]! 59 | given9d8: dimlyf7b! 60 | shyly0eb: dimlyf7b! 61 | zowie2b5: until598! 62 | yowza66e: dimlyf7b! 63 | yummy209: blanka08! 64 | madlyad1: [midstcb8!]! 65 | } 66 | 67 | type after466 { 68 | jaded171: [yowza466!]! 69 | } 70 | 71 | input yowza01c { 72 | times73f: String! 73 | yahoo05e: [String!]! 74 | } 75 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/aboutb1b.graphql: -------------------------------------------------------------------------------- 1 | type wetly2f5 { 2 | yowza43c: [spoondfa!]! 3 | } 4 | 5 | type spoondfa { 6 | emcee2fe: String! 7 | oddlycbe: dimlyf7b 8 | yowza42b: dimlyf7b 9 | } 10 | 11 | input above208 { 12 | wrong873: hasty109 13 | decay64d: horse462 14 | } 15 | 16 | input hasty109 { 17 | yowzad72: ID! 18 | timesf9f: String! 19 | murky1a1: ID 20 | minus147: yahooe4f! 21 | float85b: Int 22 | } 23 | 24 | input horse462 { 25 | yowzad72: ID! 26 | draft286: String 27 | timesf9f: String! 28 | murky1a1: ID 29 | sinced6b: ID 30 | minus147: yahooe4f! 31 | float85b: Int 32 | } 33 | 34 | enum yahooe4f { 35 | wetly82a 36 | score860 37 | } 38 | 39 | type abaftbf9 { 40 | yowza394: String 41 | } 42 | 43 | type trulycac { 44 | sadlybf4: [front2ad!]! 45 | rusty683: fooey1b7! 46 | worthfad: [livid7d3!]! 47 | } 48 | 49 | type front2ad { 50 | noisy502: livid7d3 51 | fooey14d: String! 52 | } 53 | 54 | type fooey1b7 { 55 | rapid0c3: Boolean! 56 | circa33d: Boolean! 57 | oddlyf24: String 58 | alongd72: String 59 | } 60 | 61 | type livid7d3 { 62 | midst81a: ID! 63 | emcee2fe: String! 64 | murky1a1: ID! 65 | drool984: String! 66 | timesf9f: String! 67 | quilt5d8: String 68 | often518: String 69 | buddy6ff: String 70 | clampc17: String 71 | fooey435: Int! 72 | circa5da: whose437! 73 | yowzad72: String! 74 | } 75 | 76 | type whose437 { 77 | whose2cc: String! 78 | plait3d6: Boolean! 79 | yahoodab: Boolean! 80 | yahoodb0: rough80b! 81 | minus557: Int! 82 | } 83 | 84 | scalar dimlyf7b 85 | 86 | scalar rough80b 87 | 88 | type Query { 89 | sadly833: wetly2f5 90 | stockb1c(fooey052: Int, madly2ba: String): trulycac 91 | } 92 | 93 | type Mutation { 94 | where1a8(worth668: above208!): abaftbf9 95 | } 96 | 97 | input yowza01c { 98 | times73f: String! 99 | yahoo05e: [String!]! 100 | } 101 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/above94b.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | blanda64(unban677: ID!): fooey56e 3 | afore695(sadly3fe: ID!): alias6e6 4 | where489(unban677: ID!, zowie14f: ID!): grill67b 5 | } 6 | 7 | type Mutation { 8 | undera32(worth668: growne4e!): shyly5ec 9 | } 10 | 11 | enum amonga65 { 12 | madly328 13 | tough88e 14 | } 15 | 16 | type fooey56e { 17 | thiefe2e: [dimly71d!]! 18 | perkyaf5: [dimly71d!]! 19 | dailyff4: [knock5ba!]! 20 | } 21 | 22 | type alias6e6 { 23 | wheel24a: [after646!]! 24 | } 25 | 26 | type grill67b { 27 | where489: Boolean! 28 | } 29 | 30 | type dimly71d { 31 | slump373: String! 32 | yowza2d5: String! 33 | title7b1: String! 34 | } 35 | 36 | type knock5ba { 37 | sadly3fe: String! 38 | snail999: [dimly71d!]! 39 | } 40 | 41 | input growne4e { 42 | unban677: ID! 43 | perkyaf5: [abaft3ab!]! 44 | } 45 | 46 | input abaft3ab { 47 | slump373: String! 48 | yowza2d5: String! 49 | circad06: amonga65! 50 | } 51 | 52 | type shyly5ec { 53 | still876: Boolean! 54 | } 55 | 56 | type stallb7e { 57 | slump373: String! 58 | yowza2d5: String! 59 | } 60 | 61 | type after646 { 62 | slump373: String! 63 | yowza2d5: String! 64 | title7b1: String! 65 | still876: Boolean! 66 | } 67 | 68 | input yowza01c { 69 | times73f: String! 70 | yahoo05e: [String!]! 71 | } 72 | 73 | input where645 { 74 | times73f: String! 75 | hence01b: String! 76 | } 77 | 78 | input aforeae4 { 79 | after943: String! 80 | chaind08: String! 81 | truly17d: String! 82 | } 83 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/abovedd1.graphql: -------------------------------------------------------------------------------- 1 | type state2c1 implements might27e @key(fields: "yahoo844") @extends { 2 | yahoo844: ID! @external 3 | court492: String! 4 | } 5 | 6 | type abovee05 @key(fields: "midst81a") @extends { 7 | midst81a: ID! @external 8 | misty59e: [String!]! 9 | } 10 | 11 | input yowza01c { 12 | times73f: String! 13 | yahoo05e: [String!]! 14 | } 15 | 16 | interface might27e { 17 | yahoo844: ID! 18 | } 19 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/afore2c3.graphql: -------------------------------------------------------------------------------- 1 | type woozye7b { 2 | aside118: String 3 | } 4 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/afore5e4.graphql: -------------------------------------------------------------------------------- 1 | scalar timesabb 2 | 3 | scalar dimlyf7b 4 | 5 | scalar until598 6 | 7 | type Query { 8 | staff0d8(worth668: until31b!): zowied44 9 | } 10 | 11 | input until31b { 12 | yowza995: [ID!]! 13 | } 14 | 15 | type zowied44 { 16 | often25e: [badly1ea!]! 17 | } 18 | 19 | type badly1ea { 20 | midst81a: ID! 21 | sadly3fe: ID! 22 | yahoodda: which9a9 23 | truly689: jelly78a 24 | yahoo7f1: until598 25 | patch419: until598 26 | } 27 | 28 | enum jelly78a { 29 | yahoode8 30 | shyly5a7 31 | adminef8 32 | still4fe 33 | superd67 34 | sword844 35 | badlybb6 36 | sight217 37 | } 38 | 39 | type Mutation { 40 | zowiec0c(worth668: zowie89c!): minusae3 41 | } 42 | 43 | input zowie89c { 44 | sadly3fe: ID! 45 | } 46 | 47 | type minusae3 { 48 | large4e0: badly1ea 49 | } 50 | 51 | input yowza01c { 52 | times73f: String! 53 | yahoo05e: [String!]! 54 | } 55 | 56 | type which9a9 { 57 | sadly44d: dimlyf7b! 58 | chiefea7: timesabb! 59 | } 60 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/after472.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | awful89a(worth668: worth842!): madly6bf 3 | } 4 | 5 | type Mutation { 6 | oddlycc9(worth668: quiltd0c!): oddly167 7 | } 8 | 9 | input canoe5cd { 10 | since45e: String! 11 | ratioe42: [String!]! 12 | } 13 | 14 | type henceb25 { 15 | since45e: String! 16 | yowza299: String! 17 | lumpy5d2: trulye0f 18 | title7b1: String! 19 | loyal812: String! 20 | madly6f9: Boolean! 21 | muddy856: Boolean! 22 | fooey8dc: String! 23 | worthfff: [oddly9d3!]! 24 | zowie317: [String!]! 25 | whose069: Boolean 26 | winch3bb: Int 27 | shame571: Int 28 | } 29 | 30 | type trulye0f { 31 | stale240: String! 32 | where8c2: String! 33 | } 34 | 35 | type oddly9d3 { 36 | title7b1: String! 37 | yowza2d5: String! 38 | } 39 | 40 | type madly6bf { 41 | small22e: [henceb25!]! 42 | } 43 | 44 | type oddly167 { 45 | small22e: [henceb25!]! 46 | } 47 | 48 | input worth842 { 49 | after77b: String! 50 | yahoo92e: String! 51 | dimlyaaf: String 52 | } 53 | 54 | input quiltd0c { 55 | after77b: String! 56 | yahoo92e: String! 57 | times2bf: String 58 | widow119: String! 59 | aboute6c: [canoe5cd!]! 60 | } 61 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/after83a.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | scalar chafeb78 6 | 7 | type Query { 8 | snuckdb5(worth668: basicfee): hencefa4 9 | } 10 | 11 | input shyly71a { 12 | yowza299: [String!] 13 | bleakb01: [chafeb78!] 14 | } 15 | 16 | type falseb2a { 17 | yowza299: String! 18 | oddly248: Float 19 | regala71: Int 20 | neverec6: Boolean 21 | bleakb01: chafeb78! 22 | } 23 | 24 | input basicfee { 25 | zowie06b: shyly71a 26 | } 27 | 28 | type hencefa4 implements oddlybcf @key(fields: "midst81a") { 29 | midst81a: ID! 30 | snuckdb5: [falseb2a!]! 31 | } 32 | 33 | input yowza01c { 34 | times73f: String! 35 | yahoo05e: [String!]! 36 | } 37 | 38 | interface oddlybcf { 39 | midst81a: ID! 40 | } 41 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/afterd2d.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | disco6cb(flare450: [ID!]!): [madlybfa]! 3 | } 4 | 5 | type madlybfa @key(fields: "scary40c") { 6 | scary40c: ID! 7 | fooeya82: String 8 | thongce2: String 9 | while89e: while596 10 | sadlyed0: String 11 | fully8be: swampcf3 12 | } 13 | 14 | type swampcf3 { 15 | fooeya82: String 16 | thongce2: String 17 | while89e: while596 18 | } 19 | 20 | type given92c { 21 | greetbc5: Float! 22 | cruel83f: Float! 23 | } 24 | 25 | type since0ef { 26 | yowza2d5: Float! 27 | } 28 | 29 | type grassa25 { 30 | greetbc5: Float! 31 | } 32 | 33 | type oftenb41 { 34 | cruel83f: Float! 35 | } 36 | 37 | union zowief06 = given92c | since0ef | grassa25 | oftenb41 38 | 39 | enum wittyd9d { 40 | yahoo6c6 41 | badly092 42 | rapid6b0 43 | yahoo293 44 | worst07c 45 | yowzad26 46 | truly8c7 47 | } 48 | 49 | type while596 { 50 | award04c: wittyd9d 51 | repay348: zowief06 52 | } 53 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/afterd8f.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query { 6 | daily715( 7 | worth668: trusse6d 8 | fooey052: Int 9 | madly2ba: String 10 | never2e5: Int 11 | while53c: String 12 | ): aforeb7a 13 | } 14 | 15 | input trusse6d { 16 | zowie06b: shrug062 17 | } 18 | 19 | input shrug062 { 20 | lever836: [while5dd!] 21 | grout3e3: String 22 | } 23 | 24 | input while5dd { 25 | whose7a5: String 26 | } 27 | 28 | type aforeb7a { 29 | sadlybf4: [neverb1c!]! 30 | rusty683: fooey1b7! 31 | yowzabf0: [short52b!]! 32 | blank09a: crook7a1! @deprecated(reason: "") 33 | } 34 | 35 | type neverb1c { 36 | noisy502: short52b 37 | fooey14d: String! 38 | } 39 | 40 | type short52b { 41 | decay64d: freak945! 42 | } 43 | 44 | type crook7a1 { 45 | lever836(yahoo463: Int): [fooeyf7a!]! 46 | after0e8: wheree72! 47 | } 48 | 49 | type wheree72 { 50 | roostf11(yahoo463: Int): [silly1d1!]! 51 | badly54a(yahoo463: Int, abaft763: String): [sadlyfc1!]! 52 | } 53 | 54 | type fooeyf7a { 55 | soggyf9e: Int! 56 | whose7a5: String! 57 | yowza299: String! 58 | } 59 | 60 | type silly1d1 { 61 | soggyf9e: Int! 62 | yowza299: String! 63 | } 64 | 65 | type sadlyfc1 { 66 | soggyf9e: Int! 67 | abaft763: String! 68 | yowza299: String! 69 | } 70 | 71 | type freak945 @key(fields: "scary40c") @extends { 72 | scary40c: ID! @external 73 | } 74 | 75 | type fooey1b7 { 76 | alongd72: String 77 | rapid0c3: Boolean! 78 | circa33d: Boolean! 79 | oddlyf24: String 80 | } 81 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/along16c.graphql: -------------------------------------------------------------------------------- 1 | input fooey2e2 { 2 | midst81a: ID! 3 | } 4 | 5 | type whilece1 { 6 | midst81a: ID! 7 | } 8 | 9 | type Query @extends { 10 | ruralbac(worth668: fooey2e2!): whilece1 11 | } 12 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/awful36b.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | truly66c(worth668: count762!): regal7c2 3 | } 4 | 5 | type regal7c2 { 6 | yahoo92e: String! 7 | owner5f4: Boolean! 8 | zowie160: String 9 | } 10 | 11 | input count762 { 12 | yahooccb: String 13 | afterebf: often26a 14 | zowiec19: String 15 | which975: Boolean 16 | wetly44f: petty954 17 | vivid2ee: String 18 | circacfa: String 19 | drool984: String 20 | short77b: String 21 | zowie608: String 22 | zowiea48: String 23 | } 24 | 25 | enum often26a { 26 | while1c2 27 | yowza352 28 | zowie8ef 29 | fooey5dc 30 | while6db 31 | madlyff5 32 | yahoo3a4 33 | yowza7de 34 | } 35 | 36 | enum petty954 { 37 | oddlyc2b 38 | legal199 39 | jaded2ec 40 | clash476 41 | whichb0a 42 | below068 43 | } 44 | 45 | interface oddlybcf { 46 | midst81a: ID! 47 | } 48 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/awfule02.graphql: -------------------------------------------------------------------------------- 1 | scalar until598 2 | 3 | type Query { 4 | bleat1ec(worth668: hefty7d3!): yowzacfb 5 | } 6 | 7 | type Mutation { 8 | pupil486(worth668: since0a7!): yahoo774 9 | } 10 | 11 | type yowza322 { 12 | unban677: String! 13 | sadly3fe: String! 14 | hencec0d: [zowieed8!]! 15 | timesfdc: aside41e 16 | } 17 | 18 | type zowieed8 { 19 | scary40c: String! 20 | poise183: equal608 21 | } 22 | 23 | type aside41e { 24 | yowza2d5: String 25 | canoe7c0: until598 26 | } 27 | 28 | enum equal608 { 29 | fooeyd8a 30 | which6d3 31 | loads42f 32 | abovebdf 33 | } 34 | 35 | input hefty7d3 { 36 | unban677: String 37 | sadly3fe: String 38 | } 39 | 40 | input since0a7 { 41 | unban677: String 42 | sadly3fe: String! 43 | scary40c: String! 44 | yowza2d5: String! 45 | } 46 | 47 | type yowzacfb { 48 | yowzabf0: [yowza322!]! 49 | } 50 | 51 | type yahoo774 { 52 | still876: Boolean! 53 | } 54 | 55 | input yowza01c { 56 | times73f: String! 57 | yahoo05e: [String!]! 58 | } 59 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/blastcfe.graphql: -------------------------------------------------------------------------------- 1 | scalar until598 2 | 3 | type Query @extends { 4 | drive3e7(zowie9dc: front43f!, yahoo616: clearcdf): until879 5 | @deprecated(reason: "") 6 | minus453(flume0d1: [front43f!]!, yahoo616: clearcdf): until879 7 | knowna21(flare450: [ID!]!): [cycle927] 8 | } 9 | 10 | type Mutation @extends { 11 | round847(worth668: fooey250!): yowza5aa 12 | } 13 | 14 | type until879 { 15 | abovea30: Int! 16 | drive3e7: [cycle927] 17 | whered5a: String 18 | } 19 | 20 | type cycle927 @key(fields: "murky1a1") { 21 | murky1a1: ID! @deprecated(reason: "") 22 | zowie9dc: front43f! 23 | whose6ae: until598! 24 | aside838: until598 25 | zowie857: until598 26 | rabbi80f: hence9b2! 27 | } 28 | 29 | input clearcdf { 30 | whered5a: String 31 | midsta2d: Int 32 | } 33 | 34 | input fooey250 { 35 | murky1a1: ID! 36 | zowie9dc: front43f! 37 | } 38 | 39 | type yowza5aa { 40 | wheref28: cycle927! 41 | } 42 | 43 | enum front43f { 44 | spikeb9b @deprecated(reason: "") 45 | swank1c4 46 | zowie561 47 | times7ca 48 | which7fb 49 | hence0a8 @deprecated(reason: "") 50 | hence4c2 51 | white050 @deprecated(reason: "") 52 | shyly22b 53 | adminef8 54 | } 55 | 56 | type hence9b2 @key(fields: "scary40c") @extends { 57 | scary40c: ID! @external 58 | wheref28: cycle927 59 | } 60 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/cable842.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | type freak945 @key(fields: "scary40c") @extends { 4 | scary40c: ID! @external 5 | quote2b1(worth668: yowzaf59!): zowieb83 6 | whose241: cabin58d 7 | } 8 | 9 | type zowieb83 { 10 | yahoo5d9: [plane9c2!]! 11 | } 12 | 13 | input yowzaf59 { 14 | zowie06b: yahoo114! 15 | midsta2d: Int 16 | } 17 | 18 | input yahoo114 { 19 | aside2ed: wortha6f! 20 | badlyf22: [String!] 21 | } 22 | 23 | type plane9c2 { 24 | ripene14: String! 25 | title7b1: String! 26 | soggyf9e: Int 27 | } 28 | 29 | type cabin58d { 30 | cause5d0: chalkcbb 31 | } 32 | 33 | type chalkcbb implements yowza17d { 34 | troveb53: dailydde! 35 | } 36 | 37 | interface yowza17d { 38 | troveb53: dailydde! 39 | } 40 | 41 | type dailydde { 42 | yahoo6f8: whose962! 43 | above976: whose962 44 | fooeyec9: whose962 45 | } 46 | 47 | type whose962 { 48 | extola0d: String! 49 | loyala8c: spout38d! 50 | given290: Float! 51 | } 52 | 53 | type spout38d { 54 | labor66f: Float! 55 | } 56 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/calve743.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query { 6 | daily340(worth668: about985): whereb72 7 | } 8 | 9 | input about985 { 10 | whose803: ID 11 | } 12 | 13 | type whereb72 { 14 | shyly70a: [yowza868!]! 15 | } 16 | 17 | type yowza868 @key(fields: "scary40c") { 18 | scary40c: ID! 19 | yowza299: String! 20 | dailyfbf: String! 21 | freshf07: Boolean! 22 | } 23 | 24 | input yowza01c { 25 | times73f: String! 26 | yahoo05e: [String!]! 27 | } 28 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/chaincad.graphql: -------------------------------------------------------------------------------- 1 | type crowded4 { 2 | grimy387: [prize9aa!]! 3 | } 4 | 5 | type prize9aa implements madly3ec { 6 | tunicc8f: snipeee9! 7 | often9a5: until012! 8 | } 9 | 10 | input yowza01c { 11 | times73f: String! 12 | yahoo05e: [String!]! 13 | } 14 | 15 | type round2e8 @key(fields: "midst81a") @extends { 16 | midst81a: ID! @external 17 | } 18 | 19 | type which577 @key(fields: "midst81a") @extends { 20 | midst81a: ID! @external 21 | } 22 | 23 | type punch8ce 24 | @key(fields: "noisy502 { midst81a } troll394 { midst81a }") 25 | @extends { 26 | troll394: round2e8! @external 27 | noisy502: which577! @external 28 | yahoo34f: ID @external 29 | smilecdf: crowded4 @requires(fields: "yahoo34f") 30 | } 31 | 32 | interface madly3ec { 33 | tunicc8f: snipeee9! 34 | often9a5: until012! 35 | } 36 | 37 | enum snipeee9 { 38 | which6d3 39 | abovebdf 40 | grain079 41 | kookyadb 42 | } 43 | 44 | type until012 { 45 | shyly3a8: String! 46 | } 47 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/crazy511.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | shoot784(worth668: whose403!): zowie851 3 | blind75c(worth668: often136!): since149 4 | } 5 | 6 | input whose403 { 7 | about13f: String! 8 | short97b: String! 9 | brief00e: String! 10 | hairyc8d: aside6bb! 11 | photo122: slink30e 12 | urbanf04: Int 13 | basicf38: String 14 | } 15 | 16 | enum aside6bb { 17 | cower39d 18 | hencec4c 19 | sadly00c 20 | } 21 | 22 | enum slink30e { 23 | fooey68a 24 | womanaed 25 | framebc1 26 | daily36d 27 | prowl311 28 | alongbda 29 | } 30 | 31 | type zowie851 { 32 | hairyc8d: aside6bb! 33 | } 34 | 35 | input often136 { 36 | flirt459: hence8f3! 37 | rumordfb: String! 38 | nevera33: yahoo7c9 39 | range3f2: String 40 | sincec5d: String 41 | close425: [String] 42 | hoist674: [String] 43 | worth81e: String 44 | basicf38: String 45 | } 46 | 47 | enum hence8f3 { 48 | zowiec0f 49 | stunt5e4 50 | along489 51 | above4fd 52 | } 53 | 54 | enum since86d { 55 | tangoe96 56 | front43e 57 | minusa3c 58 | after61a 59 | round802 60 | prize6f4 61 | whoseb61 62 | yodel393 63 | } 64 | 65 | input yahoo7c9 { 66 | minus3d8: String 67 | preen0cd: String 68 | roostf11: String 69 | wetlyca9: String 70 | madly3b3: String 71 | emcee2ca: String 72 | clampc17: String 73 | aside2ed: String 74 | hairye5d: String! 75 | tired70f: String 76 | } 77 | 78 | type since149 { 79 | flirt459: hence8f3! 80 | } 81 | 82 | interface oddlybcf { 83 | midst81a: ID! 84 | } 85 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/crick357.graphql: -------------------------------------------------------------------------------- 1 | type wetly0bd @key(fields: "scary40c") @extends { 2 | scary40c: ID @external 3 | spreea11: abaft390 4 | } 5 | 6 | type abaft390 { 7 | blond7d1: given0a6 8 | circaf13: madly109 9 | whose669: great9ab 10 | hence842: where0b9 11 | closec74: yowza7f5 12 | } 13 | 14 | interface zowie3ab { 15 | abovedf7: Boolean! 16 | } 17 | 18 | type given0a6 implements zowie3ab { 19 | abovedf7: Boolean! 20 | } 21 | 22 | type madly109 implements zowie3ab { 23 | abovedf7: Boolean! 24 | sinceb49: Int! 25 | utter20e: Int! 26 | } 27 | 28 | type great9ab implements zowie3ab { 29 | abovedf7: Boolean! 30 | yahoo90f: [tricke94!]! 31 | } 32 | 33 | type tricke94 { 34 | yowza299: String! 35 | midst81a: String! 36 | noisy978: Int 37 | } 38 | 39 | type where0b9 implements zowie3ab { 40 | abovedf7: Boolean! 41 | } 42 | 43 | type yowza7f5 implements zowie3ab { 44 | abovedf7: Boolean! 45 | } 46 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/crisp90e.graphql: -------------------------------------------------------------------------------- 1 | scalar chafeb78 2 | 3 | type Query { 4 | yowza5bb(worth668: until8c2!): until18c 5 | } 6 | 7 | input until8c2 { 8 | witty6b7: ID! 9 | murky1a1: ID! 10 | zowiea48: String! 11 | aside2ed: String! 12 | weirddd0: String! 13 | yahoo92e: String! 14 | yahoo5e0: ID 15 | } 16 | 17 | type until18c { 18 | serum1eb: whileb0f! 19 | quill085: round3ff! 20 | } 21 | 22 | type whileb0f { 23 | sincedb9: Boolean! 24 | cheap4e7: Boolean! 25 | sincebc4: [often567!]! 26 | } 27 | 28 | type round3ff { 29 | where343: Boolean! 30 | virus57d: Boolean! 31 | bastea0c: Int 32 | zowie2b5: chafeb78 33 | shylyf5a: chafeb78 34 | } 35 | 36 | type often567 { 37 | sincea4e: String 38 | beechb50: String 39 | oddlyb4f: String 40 | munch8d1: chafeb78! 41 | after5a7: chafeb78! 42 | sinceace: String 43 | aboutbd5: String 44 | glassa9c: String 45 | whichf83: chafeb78 46 | thosec7f: chafeb78 47 | minus401: Int! 48 | sinced42: Boolean! 49 | } 50 | 51 | input yowza01c { 52 | times73f: String! 53 | yahoo05e: [String!]! 54 | } 55 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/demura89.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | peachf2a(worth668: yahoofcf!): jumpy0f4 3 | } 4 | 5 | input yahoofcf { 6 | below7e5: [dailyc8a!]! 7 | } 8 | 9 | type jumpy0f4 { 10 | dream50e: leavec93! 11 | salsaf44: unify0b1 12 | } 13 | 14 | enum dailyc8a { 15 | novel108 16 | which6ce 17 | wetly159 18 | hence186 19 | yowzaef5 20 | fooeyed5 21 | } 22 | 23 | enum leavec93 { 24 | yahoo9ef 25 | wetlya8e 26 | curvyd5d 27 | where5d4 28 | } 29 | 30 | scalar unify0b1 31 | 32 | input yowza01c { 33 | times73f: String! 34 | yahoo05e: [String!]! 35 | } 36 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/elopee3c.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | abovebfb(yowza299: String!): above644! 3 | } 4 | 5 | type above644 { 6 | zowie160: String! 7 | } 8 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/empty5de.graphql: -------------------------------------------------------------------------------- 1 | scalar timesabb 2 | 3 | scalar rough80b 4 | 5 | scalar unify0b1 6 | 7 | scalar dimlyf7b 8 | 9 | type Query { 10 | yahoof27( 11 | worth668: route1ce! 12 | fooey052: Int 13 | never2e5: Int 14 | madly2ba: String 15 | while53c: String 16 | ): fuzzy63a 17 | } 18 | 19 | input route1ce { 20 | whole382: String! 21 | } 22 | 23 | type fuzzy63a { 24 | sadlybf4: [yowza4ef!]! 25 | hence213: [while3f1!]! 26 | rusty683: fooey1b7! 27 | } 28 | 29 | type yowza4ef { 30 | noisy502: while3f1 31 | fooey14d: String! 32 | } 33 | 34 | type while3f1 implements oddlybcf @key(fields: "midst81a") { 35 | midst81a: ID! 36 | rabbi80f: hence9b2 37 | aside782: String! 38 | fooey304: punch103! 39 | daily5db: twist1e3! 40 | wrong059: sugar3f6! 41 | } 42 | 43 | type punch103 { 44 | nasal0be: after816! 45 | jolly824: after816 46 | } 47 | 48 | type after816 { 49 | sadly44d: String! 50 | chiefea7: timesabb! 51 | } 52 | 53 | type twist1e3 { 54 | socks507: unify0b1! 55 | cabine91: unify0b1 56 | } 57 | 58 | type sugar3f6 { 59 | never3f4: rough80b! 60 | which27f: rough80b! 61 | } 62 | 63 | type hence9b2 @key(fields: "scary40c") @extends { 64 | scary40c: ID! @external 65 | } 66 | 67 | input yowza01c { 68 | times73f: String! 69 | yahoo05e: [String!]! 70 | } 71 | 72 | type fooey1b7 { 73 | alongd72: String 74 | rapid0c3: Boolean! 75 | circa33d: Boolean! 76 | oddlyf24: String 77 | } 78 | 79 | interface might27e { 80 | yahoo844: ID! 81 | } 82 | 83 | interface oddlybcf { 84 | midst81a: ID! 85 | } 86 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fatalca0.graphql: -------------------------------------------------------------------------------- 1 | input aboutdbc { 2 | rally1ff: ID! 3 | small9f5: offer357! 4 | where335: [forgo15d!]! 5 | dread810: rough80b! 6 | lankyc69: rough80b! 7 | yowza1bb: yahoo570! 8 | manor701: String! 9 | afterec9: String 10 | grout3e3: shylyad2 11 | } 12 | 13 | type young046 { 14 | forgo53d: moralaf0 15 | } 16 | 17 | extend type Mutation { 18 | brood991(worth668: aboutdbc!): young046 19 | } 20 | 21 | input close248 { 22 | rally1ff: ID! 23 | small9f5: offer357! 24 | where335: [forgo15d!]! 25 | } 26 | 27 | type yowza5fd { 28 | forgo53d: moralaf0 29 | } 30 | 31 | type Mutation { 32 | until856(worth668: close248!): yowza5fd 33 | } 34 | 35 | input offer357 { 36 | times2bf: ID 37 | zowie608: fooeya96 38 | } 39 | 40 | input forgo15d { 41 | zowie608: fooeya96! 42 | } 43 | 44 | input shylyad2 { 45 | afterec9: String 46 | occur1db: whose5ae 47 | } 48 | 49 | input whose5ae { 50 | while04b: Float! 51 | omega6be: Float! 52 | } 53 | 54 | type moralaf0 { 55 | oddlydb5: String! 56 | } 57 | 58 | scalar rough80b 59 | 60 | scalar yahoo570 61 | 62 | scalar fooeya96 63 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooey02f.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | ferryf4d(worth668: whose06a!): yowza402 3 | } 4 | 5 | input whose06a { 6 | yummy209: nifty356! 7 | about022: daily3a0! 8 | } 9 | 10 | enum nifty356 { 11 | asidee54 12 | humorbaf 13 | } 14 | 15 | input daily3a0 { 16 | which165: [afterc64!]! 17 | shame1ef: Boolean 18 | } 19 | 20 | input afterc64 { 21 | focusbb7: fresh1aa! 22 | short86e: String! 23 | } 24 | 25 | type yowza402 { 26 | yahoo92e: String! 27 | yahoo641: String! 28 | } 29 | 30 | enum fresh1aa { 31 | among97e 32 | stufff46 33 | hence992 34 | unclef15 35 | } 36 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooey518.graphql: -------------------------------------------------------------------------------- 1 | enum forgede5 { 2 | erasea8a 3 | zowieac9 4 | yahood1e 5 | } 6 | 7 | type Query { 8 | among7df(worth668: sweetf34!): yowza04a 9 | } 10 | 11 | input yahoo5c6 { 12 | tight639: ID! 13 | unban677: ID! 14 | } 15 | 16 | input sweetf34 { 17 | shylybc4: [yahoo5c6!]! 18 | } 19 | 20 | type yowza04a { 21 | yowzabf0: [round0c6!]! 22 | } 23 | 24 | type round0c6 { 25 | tight639: ID! 26 | truly689: String 27 | never118: resetfb2 28 | } 29 | 30 | type resetfb2 { 31 | kebab10c: String 32 | emcee2fe: String 33 | scentdef: forgede5 34 | rigid3b7: chafeb78 35 | } 36 | 37 | scalar chafeb78 38 | 39 | input yowza01c { 40 | times73f: String! 41 | yahoo05e: [String!]! 42 | } 43 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooey770.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | whosedb2(worth668: debit464!): yowza500 3 | grand9f5(worth668: dimlyc93!): fooey041 4 | } 5 | 6 | enum given7e4 { 7 | brief66e 8 | daily8b1 9 | } 10 | 11 | input debit464 { 12 | yahoo92e: ID! 13 | zowie1c7: ID! 14 | among55f: given7e4! 15 | } 16 | 17 | type yowza500 { 18 | yahoo92e: ID! 19 | zowie1c7: ID! 20 | among55f: given7e4! 21 | } 22 | 23 | input dimlyc93 { 24 | zowie1c7: ID! 25 | } 26 | 27 | type fooey041 { 28 | zowie1c7: ID! 29 | } 30 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooey80a.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | tepidd2f(worth668: vivid0a1!): award7e9 3 | } 4 | 5 | input vivid0a1 { 6 | times2bf: ID! 7 | whose4f1: ID! 8 | } 9 | 10 | type award7e9 { 11 | fluid4da: rider6bd 12 | } 13 | 14 | type rider6bd { 15 | exultbf7(fooey052: Int, madly2ba: String): sleet0bb 16 | } 17 | 18 | type sleet0bb { 19 | sadlybf4: [timesa66!]! 20 | rusty683: fooey1b7! 21 | yahoobd9: [whose723!]! 22 | } 23 | 24 | type timesa66 { 25 | noisy502: whose723 26 | fooey14d: String! 27 | } 28 | 29 | type whose723 @key(fields: "midst81a wring55c { midst81a }") @extends { 30 | midst81a: ID! 31 | wring55c: fooey0da! @external 32 | under6b3: [offera3f!]! 33 | } 34 | 35 | type fooey0da @extends { 36 | midst81a: ID! 37 | } 38 | 39 | union offera3f = judgef40 40 | 41 | type judgef40 { 42 | midst81a: ID! 43 | point40c: until598 44 | yowzaa9e: whosefc7 45 | } 46 | 47 | type whosefc7 { 48 | whichbdc: String 49 | } 50 | 51 | scalar until598 52 | 53 | interface oddlybcf { 54 | midst81a: ID! 55 | } 56 | 57 | type fooey1b7 { 58 | alongd72: String 59 | rapid0c3: Boolean! 60 | circa33d: Boolean! 61 | oddlyf24: String 62 | } 63 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooeyb81.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | type Query { 4 | ramend11(worth668: zowie5bc!, fooey052: Int, madly2ba: String): satin7b8 5 | wetly181(worth668: midst24a!, fooey052: Int, madly2ba: String): until3a3 6 | utter54b(worth668: wetlyf2b!, fooey052: Int, madly2ba: String): agonybca 7 | } 8 | 9 | input zowie5bc { 10 | above032: wortha6f! 11 | round1ea: ID 12 | worstceb: Int 13 | } 14 | 15 | type satin7b8 { 16 | sadlybf4: [thoseb76!]! 17 | rusty683: fooey1b7! 18 | after0e8: [often0a7!]! 19 | abovea30: Int! 20 | } 21 | 22 | type thoseb76 { 23 | noisy502: often0a7! 24 | fooey14d: String! 25 | } 26 | 27 | input midst24a { 28 | above032: wortha6f! 29 | round1ea: ID 30 | sleep650: [ID!] 31 | } 32 | 33 | type until3a3 { 34 | sadlybf4: [brakefae!]! 35 | rusty683: fooey1b7! 36 | loosedf7: [dailyc44]! 37 | abovea30: Int! 38 | } 39 | 40 | type brakefae { 41 | noisy502: dailyc44 42 | fooey14d: String! 43 | } 44 | 45 | input wetlyf2b { 46 | above032: wortha6f! 47 | plead5c5: [ID!]! 48 | } 49 | 50 | type agonybca { 51 | sadlybf4: [giddy357!]! 52 | rusty683: fooey1b7! 53 | yowza975: [badly50d]! 54 | abovea30: Int! 55 | } 56 | 57 | type giddy357 { 58 | noisy502: badly50d 59 | fooey14d: String! 60 | } 61 | 62 | type often0a7 @key(fields: "midst81a") { 63 | midst81a: ID! 64 | oftenb86: ID 65 | yowza299: String! 66 | } 67 | 68 | type dailyc44 @key(fields: "midst81a") { 69 | midst81a: ID! 70 | untilf01: worthfb6! 71 | yowza299: String! 72 | yowza975: [badly50d!]! 73 | } 74 | 75 | type worthfb6 @key(fields: "midst81a") { 76 | midst81a: ID! 77 | yowza299: String! 78 | } 79 | 80 | type badly50d @key(fields: "midst81a") { 81 | midst81a: ID! 82 | yowza299: String! 83 | round1ea: ID! 84 | } 85 | 86 | type fooey1b7 { 87 | alongd72: String 88 | rapid0c3: Boolean! 89 | circa33d: Boolean! 90 | oddlyf24: String 91 | } 92 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooeyb9c.graphql: -------------------------------------------------------------------------------- 1 | type round2e8 @key(fields: "midst81a") @extends { 2 | midst81a: ID! @external 3 | } 4 | 5 | type which577 @key(fields: "midst81a") @extends { 6 | midst81a: ID! @external 7 | } 8 | 9 | type punch8ce 10 | @key(fields: "noisy502 { midst81a } troll394 { midst81a }") 11 | @extends { 12 | troll394: round2e8! @external 13 | noisy502: which577! @external 14 | yahoo34f: ID @external 15 | afore466: which88d @requires(fields: "yahoo34f") 16 | } 17 | 18 | type which88d { 19 | hencec43(midsta2d: Int): [yahoodd5!]! 20 | yowza281: [bossy20c!]! 21 | } 22 | 23 | type yahoodd5 { 24 | drool984: String! 25 | yowza880: String! 26 | } 27 | 28 | type bossy20c { 29 | madlyd77: while018 30 | fooey9e9: until381 31 | chiefcf5: String! 32 | } 33 | 34 | enum until381 { 35 | which6d3 36 | abovebdf 37 | grain079 38 | } 39 | 40 | enum while018 { 41 | murky41c 42 | zowie9d2 43 | often010 44 | fooeyb98 45 | yahooe32 46 | } 47 | 48 | input yowza01c { 49 | times73f: String! 50 | yahoo05e: [String!]! 51 | } 52 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooeybdb.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | scalar oddly29e 4 | 5 | scalar rough80b 6 | 7 | type Query { 8 | amongab5: midsta6a 9 | horse322: often8d9 10 | } 11 | 12 | type Mutation { 13 | sharpb4b(worth668: yowza86a!): debug459 14 | truly3ad: after7fe 15 | sadlye88(worth668: knowne40!): meatyccb 16 | } 17 | 18 | type midsta6a { 19 | yowzabf0: rumor4ee! 20 | } 21 | 22 | type often8d9 { 23 | yowzabf0: amongcce! 24 | } 25 | 26 | type rumor4ee { 27 | yahoo068: String 28 | ankle22d: crazy89d 29 | shylyd4d: [times1bc!]! 30 | yowza299: badly3d3 31 | } 32 | 33 | input yowza86a { 34 | yahoo068: String 35 | ankle22d: sunny3b3 36 | shylyd4d: [couch4fe!] 37 | yowza299: while2bc 38 | } 39 | 40 | type badly3d3 { 41 | fooey052: String 42 | never2e5: String 43 | } 44 | 45 | input while2bc { 46 | fooey052: String 47 | never2e5: String 48 | } 49 | 50 | type crazy89d { 51 | widen2c3: String 52 | adult6a7: String 53 | which798: String 54 | abbey611: String 55 | above032: wortha6f! 56 | tired70f: String 57 | } 58 | 59 | input sunny3b3 { 60 | widen2c3: String 61 | adult6a7: String 62 | which798: String 63 | abbey611: String 64 | above032: wortha6f! 65 | tired70f: String 66 | } 67 | 68 | input knowne40 { 69 | after305: Boolean! 70 | think81d: Boolean 71 | } 72 | 73 | type debug459 { 74 | yowzabf0: Boolean! 75 | } 76 | 77 | type after7fe { 78 | yowzabf0: Boolean! 79 | } 80 | 81 | type meatyccb { 82 | yowzabf0: Boolean! 83 | } 84 | 85 | type amongcce { 86 | shylyd4d: [fully265!]! 87 | } 88 | 89 | type fully265 { 90 | midst81a: String! 91 | quake984: oddly29e! 92 | } 93 | 94 | enum teaseb06 { 95 | daily620 96 | cloakfb2 97 | } 98 | 99 | input couch4fe { 100 | midst81a: String! 101 | clear35c: String 102 | truly689: teaseb06! 103 | } 104 | 105 | type times1bc { 106 | midst81a: String! 107 | clear35c: String! 108 | } 109 | 110 | input yowza01c { 111 | times73f: String! 112 | yahoo05e: [String!]! 113 | } 114 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fooeydd7.graphql: -------------------------------------------------------------------------------- 1 | type reignb20 implements might27e @key(fields: "yahoo844") { 2 | yahoo844: ID! 3 | } 4 | 5 | type zowieb68 implements might27e @key(fields: "yahoo844") { 6 | yahoo844: ID! 7 | } 8 | 9 | scalar _FieldSet 10 | 11 | directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE 12 | 13 | type since9a4 implements might27e @key(fields: "yahoo844") { 14 | yahoo844: ID! 15 | } 16 | 17 | type rough4f1 implements might27e @key(fields: "yahoo844") { 18 | yahoo844: ID! 19 | } 20 | 21 | type Query { 22 | badlyd23: since9a4 23 | pilotcb1: reignb20 24 | } 25 | 26 | type Mutation { 27 | badlyd23: rough4f1 28 | pilotcb1: zowieb68 29 | } 30 | 31 | input yowza01c { 32 | times73f: String! 33 | yahoo05e: [String!]! 34 | } 35 | 36 | interface might27e { 37 | yahoo844: ID! 38 | } 39 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/fullya44.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | wherebb1(worth668: yahoo630): [zowiea36!] 3 | } 4 | 5 | input yahoo630 { 6 | taste7e0: [whose864!] 7 | henceb58: blank1b3 8 | } 9 | 10 | interface zowiea36 { 11 | midst81a: ID! 12 | burstc92: afore9b6 13 | } 14 | 15 | enum afore9b6 { 16 | purse812 17 | hence8e6 18 | daily25e 19 | } 20 | 21 | enum whose864 { 22 | zowie1d8 23 | since133 24 | } 25 | 26 | input blank1b3 { 27 | abovefa4: Boolean 28 | sadly4ec: [String!] 29 | beast91f: String 30 | craneec2: yahooabf 31 | shawl07c: yahoocbb 32 | } 33 | 34 | type afterb5b implements zowiea36 { 35 | midst81a: ID! 36 | burstc92: afore9b6 37 | shyly059: String 38 | small71a: String 39 | } 40 | 41 | input yahooabf { 42 | small71a: String 43 | } 44 | 45 | type sinced79 implements zowiea36 46 | @key(fields: "midst81a abovefa4 aside2ed circad7b") 47 | @extends { 48 | midst81a: ID! @external 49 | burstc92: afore9b6 @external 50 | abovefa4: Boolean @external 51 | aside2ed: String @external 52 | circad7b: String @external 53 | } 54 | 55 | input yahoocbb { 56 | aside2ed: String 57 | circad7b: String 58 | } 59 | 60 | enum grown4c3 { 61 | zowie1d8 62 | } 63 | 64 | type glory99e implements moulte83 @key(fields: "midst81a") { 65 | midst81a: ID! 66 | pandaee7: Boolean 67 | afterec9: String 68 | } 69 | 70 | type which577 @key(fields: "midst81a") @extends { 71 | midst81a: ID! @external 72 | regal334(worth668: circa787): [moulte83!] 73 | } 74 | 75 | interface moulte83 { 76 | midst81a: ID! 77 | pandaee7: Boolean 78 | } 79 | 80 | input circa787 { 81 | taste7e0: [grown4c3!] 82 | } 83 | 84 | input yowza01c { 85 | times73f: String! 86 | yahoo05e: [String!]! 87 | } 88 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/funny080.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | skirt9b1(worth668: weird863): fully98e 3 | after85d(worth668: yowzaed7): fully98e 4 | } 5 | 6 | input weird863 { 7 | unban677: ID 8 | sadly3fe: ID 9 | truly794: ID 10 | } 11 | 12 | input yowzaed7 { 13 | yowzaefe: dimlyf7b! 14 | afore3f4: dimlyf7b! 15 | } 16 | 17 | type fully98e { 18 | badly087: [yahoo872!]! 19 | } 20 | 21 | type yahoo872 { 22 | afterc75: ID! 23 | troll394: fieldf34! 24 | } 25 | 26 | type cable1d0 { 27 | quilt5d8: String 28 | often518: String 29 | rainyb57: String! 30 | } 31 | 32 | type fieldf34 { 33 | sadly3fe: ID! 34 | truly794: ID! 35 | yowzaefe: dimlyf7b! 36 | blurt1c6: String! 37 | yowza299: cable1d0! 38 | dailya25: until598! 39 | yahoo87e: fullydea 40 | } 41 | 42 | scalar until598 43 | 44 | scalar dimlyf7b 45 | 46 | type Mutation { 47 | fancyfc8(worth668: vaguee86): untild97 48 | asideafa(worth668: doughfc6): while975 49 | } 50 | 51 | input vaguee86 { 52 | afterc75: ID! 53 | zowie344: zowie647! 54 | } 55 | 56 | input doughfc6 { 57 | truly794: ID! 58 | afore3f4: dimlyf7b! 59 | fully01f: ID! 60 | zowie14f: Int! 61 | } 62 | 63 | type untild97 { 64 | afterc75: ID! 65 | yahoo87e: fullydea! 66 | } 67 | 68 | type while975 { 69 | truly794: ID! 70 | yahoo87e: fullydea! 71 | } 72 | 73 | type flash553 { 74 | shylybf3: ID! 75 | aside782: zowie647! 76 | } 77 | 78 | enum zowie647 { 79 | minusb83 80 | trulyd77 81 | spoolc6a 82 | fullyd5d 83 | aside64f 84 | shyly22b 85 | adminef8 86 | } 87 | 88 | type fullydea { 89 | yahoo87e: flash553! 90 | dread810: until598 91 | } 92 | 93 | input yowza01c { 94 | times73f: String! 95 | yahoo05e: [String!]! 96 | } 97 | 98 | interface oddlybcf { 99 | midst81a: ID! 100 | } 101 | 102 | type fooey1b7 { 103 | alongd72: String 104 | rapid0c3: Boolean! 105 | circa33d: Boolean! 106 | oddlyf24: String 107 | } 108 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/ghostf0d.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | scalar unify0b1 6 | 7 | scalar wortha6f 8 | 9 | type minusa61 { 10 | yowza299: String! 11 | quake984: unify0b1! 12 | } 13 | 14 | type worth524 { 15 | yowza2d5: String! 16 | yummy209: truly951 17 | } 18 | 19 | enum truly951 { 20 | given846 21 | among57a 22 | repay2f3 23 | yowza0e1 24 | aside89d 25 | yahooba5 26 | where112 27 | while263 28 | } 29 | 30 | type yowza746 { 31 | yowza299: String! 32 | yowza2d5: Int! 33 | blindea7: worth524 34 | afterec9: String 35 | } 36 | 37 | type below142 { 38 | until24d: String! 39 | demobbc6: yowza746! 40 | } 41 | 42 | type truly186 { 43 | yowza8ba: Int! 44 | deterf15: String! 45 | mealy6b7: [below142!]! 46 | month9b2: ID! 47 | fooeyb47: [String!] 48 | yahoo520: String! 49 | } 50 | 51 | type hence8b5 { 52 | yahoo92e: ID 53 | couch398: [minusa61!]! 54 | minus501: truly186! 55 | glass2b6: wortha6f 56 | mixerb9a: wortha6f 57 | } 58 | 59 | enum until4f2 { 60 | zowie896 61 | crookebe 62 | irony185 63 | } 64 | 65 | enum whichec2 { 66 | zowiea04 67 | nevere73 68 | } 69 | 70 | input stake4fd { 71 | yahoo998: until4f2! 72 | stake5c3: String! 73 | abaft6c7: String! 74 | month9b2: ID 75 | truth863: Boolean! 76 | whilef7f: whichec2! 77 | canon167: [String!]! 78 | couch398: [String!]! 79 | } 80 | 81 | type Query { 82 | zowieb3a(worth668: stake4fd): hence8b5 83 | } 84 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/gooseaf0.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | fullyddb(worth668: alertd27!): preen536 3 | } 4 | 5 | input alertd27 { 6 | givenba6: String! 7 | } 8 | 9 | type preen536 { 10 | still876: untilc82 11 | } 12 | 13 | type untilc82 { 14 | ripene14: String! 15 | yowza2d5: Int 16 | chiefea7: timesabb 17 | } 18 | 19 | scalar timesabb 20 | 21 | type Query { 22 | swampbcf: choke108 23 | } 24 | 25 | type choke108 { 26 | knock2fe: drain7c4 27 | } 28 | 29 | type drain7c4 { 30 | aside522: String! 31 | afoul8e6: Int 32 | outdo385: String 33 | chiefea7: String! 34 | relay9c3: String! 35 | } 36 | 37 | input yowza01c { 38 | times73f: String! 39 | yahoo05e: [String!]! 40 | } 41 | 42 | interface oddlybcf { 43 | midst81a: ID! 44 | } 45 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/hence3ff.graphql: -------------------------------------------------------------------------------- 1 | type crowded4 { 2 | until923: [often4ae!] 3 | throw612: [circa76b!] 4 | timese95: [where153!] 5 | } 6 | 7 | type often4ae implements madly3ec { 8 | tunicc8f: snipeee9! 9 | often9a5: until012! 10 | } 11 | 12 | type circa76b implements madly3ec { 13 | tunicc8f: snipeee9! 14 | often9a5: until012! 15 | } 16 | 17 | type where153 implements madly3ec { 18 | tunicc8f: snipeee9! 19 | often9a5: until012! 20 | } 21 | 22 | input yowza01c { 23 | times73f: String! 24 | yahoo05e: [String!]! 25 | } 26 | 27 | type round2e8 @key(fields: "midst81a") @extends { 28 | midst81a: ID! @external 29 | } 30 | 31 | type which577 @key(fields: "midst81a") @extends { 32 | midst81a: ID! @external 33 | } 34 | 35 | type punch8ce 36 | @key(fields: "noisy502 { midst81a } troll394 { midst81a }") 37 | @extends { 38 | troll394: round2e8! @external 39 | noisy502: which577! @external 40 | yahoo34f: ID @external 41 | smilecdf: crowded4 @requires(fields: "yahoo34f") 42 | } 43 | 44 | interface madly3ec { 45 | tunicc8f: snipeee9! 46 | often9a5: until012! 47 | } 48 | 49 | enum snipeee9 { 50 | which6d3 51 | abovebdf 52 | grain079 53 | kookyadb 54 | } 55 | 56 | type until012 { 57 | shyly3a8: String! 58 | } 59 | 60 | interface oddlybcf { 61 | midst81a: ID! 62 | } 63 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/hence5bd.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | scalar until598 6 | 7 | type Query { 8 | alpha686(worth668: scope508!): yowza987 9 | sinceaa0( 10 | worth668: under658! 11 | fooey052: Int 12 | madly2ba: String 13 | never2e5: Int 14 | while53c: String 15 | ): fooey5af 16 | } 17 | 18 | input scope508 { 19 | witty6b7: ID! 20 | zowie06b: worthb8d 21 | } 22 | 23 | input worthb8d { 24 | wheree35: [ID!] 25 | messy33f: [ID!] 26 | yahoo234: Boolean 27 | faint4a0: until598 28 | beret026: after6a4 29 | } 30 | 31 | input under658 { 32 | limitadb: until598 33 | lumpy192: Boolean 34 | aware0ad: Boolean 35 | } 36 | 37 | type yowza987 { 38 | yowzabf0: [sinceab2!]! 39 | } 40 | 41 | type sinceab2 { 42 | bogusd82: ID 43 | afore3f4: ID 44 | zowie14f: ID 45 | chant2b0: Int 46 | sadly3fe: Int 47 | witty6b7: ID 48 | aside2ed: String 49 | minus147: String 50 | impel5a2: String 51 | zowie857: until598! 52 | which85e: priore26 53 | exalt9f5: [after6a4!]! 54 | } 55 | 56 | type priore26 { 57 | fooey614: Boolean 58 | slime099: until598 59 | mushyd4b: [since2f7!]! 60 | } 61 | 62 | type since2f7 { 63 | quickdd2: String 64 | which85e: String 65 | after686: until598 66 | minus147: String 67 | } 68 | 69 | enum after6a4 { 70 | nutty357 71 | prizecde 72 | } 73 | 74 | type fooey5af { 75 | sadlybf4: [venueb38!]! 76 | rusty683: fooey1b7! 77 | essayc27: [henced60!]! 78 | } 79 | 80 | type venueb38 { 81 | noisy502: henced60 82 | fooey14d: String! 83 | } 84 | 85 | type henced60 { 86 | salad9d3: until598! 87 | rabbi80f: hence9b2 88 | badly474: String 89 | } 90 | 91 | type hence9b2 @key(fields: "scary40c") @extends { 92 | scary40c: ID! @external 93 | } 94 | 95 | type fooey1b7 { 96 | alongd72: String 97 | rapid0c3: Boolean! 98 | circa33d: Boolean! 99 | oddlyf24: String 100 | } 101 | 102 | interface oddlybcf { 103 | midst81a: ID! 104 | } 105 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/hencec8e.graphql: -------------------------------------------------------------------------------- 1 | enum dallycfc { 2 | zowieddf 3 | morala5e 4 | cloakd97 5 | fully8f7 6 | } 7 | 8 | type Query { 9 | lumpyd26: dallycfc 10 | } 11 | 12 | scalar dimlyf7b 13 | 14 | scalar until598 15 | 16 | input yowza01c { 17 | times73f: String! 18 | yahoo05e: [String!]! 19 | } 20 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/index.ts: -------------------------------------------------------------------------------- 1 | import { readdir, readFile } from "node:fs/promises"; 2 | import { DocumentNode, parse } from "graphql"; 3 | 4 | const __dirname = new URL(".", import.meta.url).pathname; 5 | 6 | export async function getSubgraphs() { 7 | const files = await readdir(`${__dirname}`); 8 | const subgraphs: Array<{ 9 | name: string; 10 | typeDefs: DocumentNode; 11 | }> = []; 12 | 13 | for await (const file of files) { 14 | if (file.endsWith(".graphql")) { 15 | const schema = await readFile(`${__dirname}/${file}`, "utf8"); 16 | const parsedSchema = parse(schema, { 17 | noLocation: true, 18 | }); 19 | 20 | subgraphs.push({ 21 | name: file.replace(".graphql", ""), 22 | typeDefs: parsedSchema, 23 | }); 24 | } 25 | } 26 | 27 | return subgraphs; 28 | } 29 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/lucky89a.graphql: -------------------------------------------------------------------------------- 1 | type since9a4 implements might27e @key(fields: "yahoo844") @extends { 2 | yahoo844: ID! @external 3 | linede5f: sincec45! 4 | } 5 | 6 | type sincec45 implements might27e @key(fields: "yahoo844") { 7 | yahoo844: ID! 8 | badlyd23: String! 9 | brief90c: String 10 | } 11 | 12 | input yowza01c { 13 | times73f: String! 14 | yahoo05e: [String!]! 15 | } 16 | 17 | interface might27e { 18 | yahoo844: ID! 19 | } 20 | 21 | interface oddlybcf { 22 | midst81a: ID! 23 | } 24 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/madly868.graphql: -------------------------------------------------------------------------------- 1 | scalar unify0b1 2 | 3 | type Query { 4 | scuff36c(worth668: adobe0fa!): whoseb63 5 | } 6 | 7 | type Mutation { 8 | heavy18d(worth668: while87b!): brown46e 9 | } 10 | 11 | input adobe0fa { 12 | after74b: zowie958! 13 | } 14 | 15 | type whoseb63 { 16 | clearb3a: [badly236!]! 17 | } 18 | 19 | type badly236 { 20 | midst81a: ID! 21 | split666: candye69! 22 | truly689: belowdbe! 23 | worst202: String! 24 | madly6af: String! 25 | sadlyc31: String! 26 | arrowe45: String! 27 | zowie82e: unify0b1 28 | admin8aa: sinced23 29 | yowzadb6: truly35f 30 | } 31 | 32 | type sinced23 { 33 | yowza62b: String! 34 | alonge81: String! 35 | } 36 | 37 | input while87b { 38 | midst81a: ID! 39 | after74b: zowie958! 40 | truly689: belowdbe! 41 | } 42 | 43 | type brown46e { 44 | plush7ef: badly236! 45 | } 46 | 47 | enum zowie958 { 48 | sadlycf9 49 | wound1dd 50 | oddlya3d 51 | yowza6af 52 | } 53 | 54 | enum candye69 { 55 | fussy4d0 56 | where04e 57 | zowiebf1 58 | thief948 59 | roundc02 60 | which616 61 | about995 62 | oddly8b3 63 | vividaf3 64 | } 65 | 66 | enum belowdbe { 67 | sweat2de 68 | hence9f2 69 | madly9b9 70 | often89d 71 | } 72 | 73 | enum truly35f { 74 | about995 75 | thief948 76 | madly031 77 | grand589 78 | zowiebf1 79 | which616 80 | oddly8b3 81 | vividaf3 82 | } 83 | 84 | input yowza01c { 85 | times73f: String! 86 | yahoo05e: [String!]! 87 | } 88 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/midstaf0.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | messy272(worth668: sadly47f!): while03c 3 | abaft488(worth668: agile785): paintd73 4 | } 5 | 6 | type Mutation { 7 | grasp51c(worth668: whosed24!): wetlye77 8 | } 9 | 10 | input sadly47f { 11 | midst81a: String! 12 | yowza6d4: String 13 | zowiea48: String 14 | until7fb: [under0d8!] 15 | } 16 | 17 | input under0d8 { 18 | zowiecb6: dailyd42! 19 | yowza751: String! 20 | fooeyf1c: String 21 | wetly166: String 22 | front857: untile09 23 | yowzafe1: [String!] 24 | } 25 | 26 | input agile785 { 27 | taste7e0: [String!] 28 | } 29 | 30 | enum dailyd42 { 31 | truly5a7 32 | whose09c 33 | yowzae18 34 | whilee4e 35 | otterb8d 36 | } 37 | 38 | enum untile09 { 39 | barge7bf 40 | above251 41 | thumb8d6 42 | among3f2 43 | rough91e 44 | while50f 45 | } 46 | 47 | type while03c { 48 | faintc36: String! 49 | } 50 | 51 | type paintd73 { 52 | where5a4: [String!]! 53 | } 54 | 55 | input whosed24 { 56 | midst81a: String! 57 | madly50c: ID! 58 | title7b1: shylyf90! 59 | midst9db: whichff0! 60 | belchba0: shylyf90 61 | lankyecd: shylyf90 62 | madly6f9: Boolean 63 | afterec9: String! 64 | incur653: [ID] 65 | } 66 | 67 | input shylyf90 { 68 | zowie160: String! 69 | round61b: String 70 | filth9a6: String 71 | fooeya70: Int 72 | oddlyca8: [String!] 73 | } 74 | 75 | enum whichff0 { 76 | henceaa6 77 | minus86c 78 | after3f2 79 | whose92b 80 | sadly4cb 81 | flaref5a 82 | curve152 83 | abaftcf6 84 | } 85 | 86 | type wetlye77 { 87 | midst81a: String! 88 | madly50c: ID! 89 | title7b1: growna7c! 90 | midst9db: whichff0! 91 | belchba0: growna7c 92 | lankyecd: growna7c 93 | madly6f9: Boolean 94 | afterec9: String! 95 | incur653: [ID] 96 | } 97 | 98 | type growna7c { 99 | zowie160: String! 100 | round61b: String 101 | filth9a6: String 102 | fooeya70: Int 103 | oddlyca8: [String!] 104 | } 105 | 106 | interface oddlybcf { 107 | midst81a: ID! 108 | } 109 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/never613.graphql: -------------------------------------------------------------------------------- 1 | scalar unify0b1 2 | 3 | scalar fooeya96 4 | 5 | type Mutation { 6 | never2dd(worth668: fully356!): prize6a7 7 | } 8 | 9 | type Query { 10 | since72e: scrime95 11 | } 12 | 13 | enum fooey4b7 { 14 | fooey17f 15 | fully98d 16 | means738 17 | grimy433 18 | about311 19 | } 20 | 21 | input fully356 { 22 | fooey471: fooey4b7! 23 | yowza299: String! 24 | where4ff: Boolean 25 | equal5e6: String 26 | zowie855: fooeya96! 27 | yowza880: String! 28 | fooeye3c: String! 29 | since200: String 30 | whose41d: unify0b1 31 | zowie350: String 32 | } 33 | 34 | type minusce9 { 35 | fooey471: fooey4b7! 36 | yowza299: String! 37 | where4ff: Boolean 38 | equal5e6: String 39 | zowie855: fooeya96! 40 | yowza880: String! 41 | fooeye3c: String! 42 | since200: String 43 | whose41d: unify0b1 44 | zowie350: String 45 | } 46 | 47 | type month6de { 48 | zowie160: String! 49 | quake984: unify0b1 50 | } 51 | 52 | type wetly1bf { 53 | yahooa3f: minusce9 54 | jolly71d: month6de 55 | } 56 | 57 | type mushy6e2 { 58 | payeece6: Boolean! 59 | } 60 | 61 | type prize6a7 { 62 | yowzabf0: wetly1bf! 63 | } 64 | 65 | type scrime95 { 66 | yowzabf0: mushy6e2! 67 | } 68 | 69 | input yowza01c { 70 | times73f: String! 71 | yahoo05e: [String!]! 72 | } 73 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/neverde7.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | scalar timesabb 4 | 5 | scalar fooeya96 6 | 7 | scalar dimly631 8 | 9 | scalar until598 10 | 11 | type Mutation { 12 | wetly09a(worth668: tired8ff!): oddlyd82 13 | } 14 | 15 | input tired8ff { 16 | wherec95: String 17 | whose4f1: String 18 | yowzada5: String 19 | shacke74: Float 20 | daily423: String 21 | forge190: String 22 | bleakb01: until598 23 | yahoo90f: String 24 | scary3f9: Boolean 25 | zowie608: fooeya96 26 | yowza299: String 27 | video759: String 28 | starkc30: fooeya96 29 | yahoo415: String 30 | zowiea48: zestyadb 31 | tarrye2f: Boolean 32 | } 33 | 34 | input zestyadb { 35 | abaft80b: dimly631 36 | aside2ed: wortha6f 37 | } 38 | 39 | type oddlyd82 { 40 | truly689: abafte1b! 41 | zowie160: String! 42 | video759: String 43 | yowza299: String 44 | zowie2b5: until598 45 | chiefea7: timesabb 46 | yowzaeef: Float 47 | white084: Float 48 | } 49 | 50 | enum abafte1b { 51 | yowzaed5 52 | flute58c 53 | fluid254 54 | } 55 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/nudge7d0.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | circa933(worth668: given13f!): among937 3 | yahooff6( 4 | fooey052: Int 5 | madly2ba: String 6 | never2e5: Int 7 | while53c: String 8 | worth668: mourn20b! 9 | ): venti3f0 10 | } 11 | 12 | input given13f { 13 | shoot643: ID! 14 | } 15 | 16 | input mourn20b { 17 | zowie06b: sincee8f! 18 | } 19 | 20 | input sincee8f { 21 | dread810: until598! 22 | lankyc69: until598! 23 | asideab5: Boolean 24 | } 25 | 26 | type among937 { 27 | midst81a: ID! 28 | truly794: String! 29 | zowiec43: String! 30 | allow1b3: String! 31 | oddlydb5: String! 32 | alertcf9: String 33 | floora99: until598! 34 | } 35 | 36 | type venti3f0 { 37 | sadlybf4: [while7dc!]! 38 | about339: [among937!]! 39 | rusty683: fooey1b7! 40 | } 41 | 42 | type while7dc { 43 | noisy502: among937! 44 | fooey14d: String! 45 | } 46 | 47 | type Mutation { 48 | brood5e6(worth668: othere71!): alive715 49 | } 50 | 51 | type alive715 { 52 | shoot643: ID! 53 | } 54 | 55 | input othere71 { 56 | truly794: ID! 57 | zowiec43: ID! 58 | allow1b3: ID! 59 | oddlydb5: String! 60 | alertcf9: String 61 | } 62 | 63 | scalar fooeya96 64 | 65 | scalar until598 66 | 67 | input yowza01c { 68 | times73f: String! 69 | yahoo05e: [String!]! 70 | } 71 | 72 | type fooey1b7 { 73 | alongd72: String 74 | rapid0c3: Boolean! 75 | circa33d: Boolean! 76 | oddlyf24: String 77 | } 78 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/oftenee9.graphql: -------------------------------------------------------------------------------- 1 | type which577 @key(fields: "midst81a") @extends { 2 | midst81a: ID! @external 3 | loosec18: cheekac0 4 | } 5 | 6 | type cheekac0 { 7 | alertadd: roundb17 8 | unity0e9: [virusd68!]! 9 | } 10 | 11 | type virusd68 { 12 | circad13: ID! 13 | crook2d2: Boolean! 14 | times39e: Boolean! 15 | frankbc7: Boolean! 16 | theseee1: Boolean! 17 | crudef58: Boolean 18 | } 19 | 20 | type Query { 21 | pushy651(worth668: until0ac!): fresh98c! 22 | } 23 | 24 | input until0ac { 25 | eagerbe3: [fooey24c!] 26 | starkbad: [ID!] 27 | } 28 | 29 | input fooey24c { 30 | midst81a: ID! 31 | covetc9e: String! 32 | } 33 | 34 | type fresh98c { 35 | yowzabf0: [pinot35a!]! 36 | } 37 | 38 | type pinot35a { 39 | fully54f: oddly06f 40 | nasal85c: ID 41 | loosec18: cheekac0 42 | } 43 | 44 | type oddly06f { 45 | midst81a: ID! 46 | covetc9e: String! 47 | } 48 | 49 | type roundb17 { 50 | fooey943: fooey51e! 51 | waivea30: Boolean! 52 | oddly613: Boolean! 53 | } 54 | 55 | enum fooey51e { 56 | winch801 57 | which2a8 58 | until67c 59 | rallyccd 60 | kookyadb 61 | } 62 | 63 | input yowza01c { 64 | times73f: String! 65 | yahoo05e: [String!]! 66 | } 67 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/paneld05.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | trust8c8(worth668: basinc9c!): hencee59 3 | } 4 | 5 | type Mutation { 6 | rowdy404(worth668: sound052!): worth986 7 | } 8 | 9 | input sound052 { 10 | plush7ef: String! 11 | truly679: String! 12 | heavycc1: String! 13 | joint687: String! 14 | faith0cd: String! 15 | tenseb03: String! 16 | wetlyeca: String 17 | } 18 | 19 | input basinc9c { 20 | truly679: String! 21 | above60a: String! 22 | blindea7: String! 23 | } 24 | 25 | enum which17e { 26 | yowzaed5 27 | crazycef 28 | } 29 | 30 | type worth986 { 31 | truly689: which17e! 32 | fooeyb47: [String!]! 33 | } 34 | 35 | type hencee59 { 36 | blindea7: String! 37 | fooeyb47: [String!]! 38 | } 39 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/panic018.graphql: -------------------------------------------------------------------------------- 1 | scalar dimlyf7b 2 | 3 | scalar until598 4 | 5 | type Query { 6 | yahoo67a(sadly3fe: ID!): graveef6 7 | circa3eb: henceaef 8 | pushy373( 9 | fooey052: Int 10 | never2e5: Int 11 | while53c: String 12 | madly2ba: String 13 | sadly3fe: ID! 14 | ): midste3a 15 | } 16 | 17 | type Mutation { 18 | above429(worth668: wetly222!): amongee2 19 | } 20 | 21 | type graveef6 { 22 | pandaee7: Boolean 23 | } 24 | 25 | type henceaef { 26 | pandaee7: Boolean 27 | whereecc: String 28 | } 29 | 30 | type amongee2 { 31 | hairyc8d: Boolean 32 | emcee2fe: String 33 | } 34 | 35 | input wetly222 { 36 | hairyc8d: Boolean 37 | emcee2fe: String 38 | } 39 | 40 | type midste3a { 41 | sadlybf4: [smartd14!]! 42 | rusty683: fooey1b7! 43 | impel821: [trulyecd!]! 44 | abovea30: Int! 45 | } 46 | 47 | type smartd14 { 48 | noisy502: trulyecd! 49 | fooey14d: String! 50 | } 51 | 52 | type trulyecd { 53 | bloop0a1: until598! 54 | pauseb03: while6b4 55 | } 56 | 57 | type while6b4 { 58 | flakyed5: dimlyf7b! 59 | } 60 | 61 | input yowza01c { 62 | times73f: String! 63 | yahoo05e: [String!]! 64 | } 65 | 66 | type fooey1b7 { 67 | alongd72: String 68 | rapid0c3: Boolean! 69 | circa33d: Boolean! 70 | oddlyf24: String 71 | } 72 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/petty951.graphql: -------------------------------------------------------------------------------- 1 | type hyenaa5e @key(fields: "midst81a") @extends { 2 | midst81a: ID! @external 3 | majorf3f: oftene37! 4 | } 5 | 6 | type tepid4ab { 7 | omegaa59: hazele3d! 8 | yahoo05e: [milkye46!]! 9 | } 10 | 11 | type oftene37 { 12 | topic930: [tepid4ab!]! 13 | } 14 | 15 | scalar hazele3d 16 | 17 | scalar milkye46 18 | 19 | input yowza01c { 20 | times73f: String! 21 | yahoo05e: [String!]! 22 | } 23 | 24 | interface oddlybcf { 25 | midst81a: ID! 26 | } 27 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/phase03c.graphql: -------------------------------------------------------------------------------- 1 | scalar unify0b1 2 | 3 | type Query { 4 | hencef89: afterd82 5 | } 6 | 7 | type afterd82 { 8 | yowzabf0: [mouse0ab!]! 9 | } 10 | 11 | type mouse0ab { 12 | blond7d1: stage100 13 | asidec42: unify0b1! 14 | } 15 | 16 | type stage100 @key(fields: "midst81a times2bf") @extends { 17 | midst81a: ID! @external 18 | times2bf: String @external 19 | } 20 | 21 | input yowza01c { 22 | times73f: String! 23 | yahoo05e: [String!]! 24 | } 25 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/plier64f.graphql: -------------------------------------------------------------------------------- 1 | scalar rough80b 2 | 3 | input fooey3cd { 4 | murky1a1: ID! 5 | bumpyc9e: String! 6 | dimly201: Boolean! 7 | pesky68b: rough80b! 8 | carolb39: Boolean! 9 | } 10 | 11 | type strutc1b { 12 | zowie62d: Boolean! 13 | } 14 | 15 | type beachc97 { 16 | still876: strutc1b! 17 | } 18 | 19 | type Mutation { 20 | whichc21(worth668: fooey3cd!): beachc97 21 | } 22 | 23 | input yowza01c { 24 | times73f: String! 25 | yahoo05e: [String!]! 26 | } 27 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/prangd95.graphql: -------------------------------------------------------------------------------- 1 | input since85b { 2 | fully27f: String 3 | small22e: [haunt51e!]! 4 | } 5 | 6 | type yowza4a9 { 7 | about931: decry78c 8 | fully27f: String 9 | } 10 | 11 | type decry78c { 12 | burly29b: Boolean! 13 | worth85b: String 14 | daily5d8: String 15 | viola589: String 16 | sadly461: above3b5 17 | total5e6: Boolean! 18 | afterec9: String 19 | noisy978: Int 20 | merry0cf(minusaaa: String): unify0b1 21 | midst81a: ID! 22 | fresh597: String 23 | provebb7: String 24 | oddly33e: decry78c 25 | yowza299: String 26 | price091( 27 | madly2ba: String 28 | while53c: String 29 | fooey052: Int 30 | never2e5: Int 31 | ): hyena34f! 32 | small22e( 33 | madly2ba: String 34 | while53c: String 35 | fooey052: Int 36 | never2e5: Int 37 | ): hyena34f! @deprecated(reason: "") 38 | hence177: Boolean! 39 | shylyf6e: Boolean! 40 | vivid71d: String 41 | whilee32: String 42 | shell7b0: Boolean! 43 | } 44 | 45 | type above3b5 { 46 | today571: [String!]! 47 | ripene14: String! 48 | yowza299: String! 49 | } 50 | 51 | type yahoo635 implements oddlybcf @key(fields: "midst81a") { 52 | oddlydb5: String! 53 | midst81a: ID! 54 | } 55 | 56 | type hyena34f { 57 | sadlybf4: [badly821!]! 58 | below597: [yahoo635!]! 59 | rusty683: fooey1b7! 60 | abovea30: Int! 61 | quiet69b: Int! 62 | } 63 | 64 | type badly821 { 65 | fooey14d: String! 66 | noisy502: yahoo635 67 | } 68 | 69 | input haunt51e { 70 | oddlydb5: String! 71 | } 72 | 73 | type Mutation { 74 | gravy2c9(worth668: since85b!): yowza4a9 75 | } 76 | 77 | interface oddlybcf { 78 | midst81a: ID! 79 | } 80 | 81 | type fooey1b7 { 82 | alongd72: String 83 | rapid0c3: Boolean! 84 | circa33d: Boolean! 85 | oddlyf24: String 86 | } 87 | 88 | type Query { 89 | shylyc50(yahoo651: [String!]!): [decry78c!] 90 | } 91 | 92 | scalar unify0b1 93 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/prove4b5.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | scened47: amongf59 3 | } 4 | 5 | type amongf59 { 6 | daily431: String! 7 | hence79e: String 8 | } 9 | 10 | input yowza01c { 11 | times73f: String! 12 | yahoo05e: [String!]! 13 | } 14 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/prowl499.graphql: -------------------------------------------------------------------------------- 1 | input block66f { 2 | pilotc7f: spooka39 3 | roundc75: muted8fe 4 | } 5 | 6 | input spooka39 { 7 | zowiea48: String 8 | yahoo6c8: String 9 | under77f: [String!] 10 | } 11 | 12 | input muted8fe { 13 | zowiea48: String 14 | under77f: [String!] 15 | } 16 | 17 | scalar unify0b1 18 | 19 | type kazoo515 { 20 | sadlybf4: [given014!]! 21 | rusty683: fooey1b7! 22 | untilee6: [fooeyf5f!]! 23 | } 24 | 25 | type given014 { 26 | noisy502: fooeyf5f 27 | fooey14d: String! 28 | } 29 | 30 | type shady4fa { 31 | sadlybf4: [brick854!]! 32 | untilee6: [fooeyf5f!]! 33 | } 34 | 35 | type brick854 { 36 | noisy502: fooeyf5f 37 | } 38 | 39 | type fooeyf5f { 40 | while09f: String 41 | worst202: String 42 | madlyaf2: unify0b1 43 | under77f: String 44 | abaft80b: String 45 | worse908: String 46 | } 47 | 48 | type fooey1b7 { 49 | rapid0c3: Boolean! 50 | circa33d: Boolean! 51 | oddlyf24: String 52 | alongd72: String 53 | } 54 | 55 | extend type Query { 56 | along1a6( 57 | worth668: block66f 58 | fooey052: Int 59 | madly2ba: String 60 | never2e5: Int 61 | while53c: String 62 | ): kazoo515 63 | madlyf4a(badly17c: [ID!]!): shady4fa 64 | untilcdf(climb33e: [ID!]!, minus7f8: Int): shady4fa 65 | } 66 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/round69d.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | scalar rough80b 4 | 5 | type Query { 6 | hence59d: trial5c2 7 | } 8 | 9 | type Mutation { 10 | coverc7d(worth668: zowie78e!): circab4f 11 | } 12 | 13 | type trial5c2 { 14 | yowzabf0: hence658! 15 | } 16 | 17 | enum hence658 { 18 | wetly5e9 19 | muted7aa 20 | untilc41 21 | whosed6b 22 | clink88a 23 | green536 24 | } 25 | 26 | input zowie78e { 27 | pulse7cb: rough80b! 28 | fooey1b4: wortha6f! 29 | widow119: wortha6f! 30 | dailyd19: Boolean! 31 | neveraf6: Boolean! 32 | } 33 | 34 | type circab4f { 35 | yowzabf0: hence001! 36 | } 37 | 38 | type hence001 { 39 | where63c: Boolean! 40 | hencee81: stale247 41 | } 42 | 43 | enum stale247 { 44 | midst0ad 45 | untilc41 46 | repel969 47 | } 48 | 49 | input yowza01c { 50 | times73f: String! 51 | yahoo05e: [String!]! 52 | } 53 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/roundd33.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | beard445(worth668: dimlyf2b!): floora09 3 | } 4 | 5 | input dimlyf2b { 6 | worth612: [ID!]! 7 | third0a3: Boolean 8 | } 9 | 10 | type floora09 { 11 | yowzabf0: [since137]! 12 | } 13 | 14 | type since137 { 15 | amongd02: ID! 16 | otter4f2: badly606! 17 | augurd89: while1d9! 18 | round9f5: String 19 | } 20 | 21 | type badly606 { 22 | whose00a: ID 23 | miter03b: ID 24 | yahoo701: until598 25 | zowiea48: String 26 | rabbi80f: sadly328 27 | plane8a9: quietad1! 28 | wound7d8: whose651 29 | fully4f6: exileadf 30 | yowzafe3: wetly1f1 31 | } 32 | 33 | type wetly1f1 { 34 | while285: String 35 | gianta29: String 36 | } 37 | 38 | type sadly328 { 39 | zowie14f: ID 40 | chant2b0: ID 41 | afore3f4: dimlyf7b 42 | murky1a1: ID 43 | heist3b5: ID 44 | } 45 | 46 | type quietad1 { 47 | yahooc5b: String! 48 | larva4e0: String! 49 | } 50 | 51 | type whose651 { 52 | truly9ad: String 53 | emcee2fe: String 54 | zowie608: fooeya96 55 | yowza363: String 56 | witty6b7: ID 57 | above032: wortha6f @deprecated(reason: "") 58 | scentdef: String 59 | rigid3b7: chafeb78 60 | kebab10c: String 61 | } 62 | 63 | type exileadf { 64 | heist3b5: ID 65 | } 66 | 67 | type while1d9 { 68 | truly689: worth3fd! 69 | } 70 | 71 | enum worth3fd { 72 | truly422 73 | shadyb8f 74 | scent3ca 75 | } 76 | 77 | schema { 78 | query: Query 79 | } 80 | 81 | scalar wortha6f 82 | 83 | scalar fooeya96 84 | 85 | scalar dimlyf7b 86 | 87 | scalar until598 88 | 89 | scalar chafeb78 90 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/rumor620.graphql: -------------------------------------------------------------------------------- 1 | interface oddlybcf { 2 | midst81a: ID! 3 | } 4 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/scowla5e.graphql: -------------------------------------------------------------------------------- 1 | type hyenaa5e @key(fields: "midst81a") @extends { 2 | midst81a: ID! @external 3 | } 4 | 5 | extend type hyenaa5e { 6 | baggy484: [yowza52e!]! 7 | } 8 | 9 | type Query { 10 | afterd7c: madlyada 11 | } 12 | 13 | type Mutation { 14 | untilc4f(worth668: dimly450!): sadlya6a 15 | offer0ce(worth668: alongc2d!): green326 16 | sadly348(worth668: below9b1!): hence182 17 | } 18 | 19 | union yowza52e = oddly521 20 | 21 | type madlyada { 22 | still876: [yowza52e!]! 23 | } 24 | 25 | type hence182 { 26 | still876: [yowza52e!]! 27 | } 28 | 29 | type sadlya6a { 30 | still876: [yowza52e!]! 31 | } 32 | 33 | type green326 { 34 | still876: [ID!]! 35 | } 36 | 37 | enum givend4c { 38 | roast75f 39 | image5ab 40 | pricefa8 41 | } 42 | 43 | enum start32f { 44 | belch132 45 | aspiccbb 46 | } 47 | 48 | type oddly521 { 49 | midst81a: ID! 50 | yummy209: start32f! 51 | spicy766: String! 52 | fooeyec6: givend4c! 53 | quilte88: Boolean! 54 | } 55 | 56 | input dimly450 { 57 | until966: octeta0d 58 | } 59 | 60 | input alongc2d { 61 | until966: quiltc76 62 | } 63 | 64 | input below9b1 { 65 | underbed: wrestcfd 66 | zowiee97: below2cb 67 | fooey6d9: wreck7e4 68 | aboutacf: midstd84 69 | where8fd: worth6b0 70 | } 71 | 72 | input octeta0d { 73 | spicy766: String! 74 | yummy209: start32f! 75 | fooeyec6: givend4c! 76 | yowza995: [String!]! 77 | } 78 | 79 | input wrestcfd { 80 | midst81a: String! 81 | spicy766: String! 82 | fooeyec6: givend4c! 83 | } 84 | 85 | input quiltc76 { 86 | midst81a: String! 87 | } 88 | 89 | input midstd84 { 90 | midst81a: String! 91 | } 92 | 93 | input worth6b0 { 94 | midst81a: String! 95 | } 96 | 97 | input below2cb { 98 | midst81a: String! 99 | yowza995: [String!]! 100 | } 101 | 102 | input wreck7e4 { 103 | midst81a: String! 104 | yowza995: [String!]! 105 | } 106 | 107 | input yowza01c { 108 | times73f: String! 109 | yahoo05e: [String!]! 110 | } 111 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/short4ee.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | troop980: round57a 3 | } 4 | 5 | type Mutation { 6 | zowie3b7(wetly54e: String!): scene292 7 | bijoube2(wetly54e: String!): roundb26 8 | } 9 | 10 | type roundb26 { 11 | often896: String 12 | } 13 | 14 | type scene292 { 15 | often896: String 16 | } 17 | 18 | type after9bd { 19 | blisse8b: String 20 | until3c7: String 21 | } 22 | 23 | type round516 { 24 | afterf65: String 25 | } 26 | 27 | type round57a { 28 | until2d9( 29 | fooey052: Int 30 | madly2ba: String 31 | never2e5: Int 32 | while53c: String 33 | ): cheapcef 34 | hovel932( 35 | hence249: String! 36 | fully8af: String! 37 | abaft80b: String! 38 | madly17c: String! 39 | awfula2e: String 40 | ): after9bd 41 | unfit3b4: String 42 | after08c: round516 43 | } 44 | 45 | type cheapcef { 46 | sadlybf4: [dimlyb9f!]! 47 | rusty683: fooey1b7! 48 | } 49 | 50 | type dimlyb9f { 51 | noisy502: lodge83d! 52 | fooey14d: String! 53 | } 54 | 55 | type lodge83d { 56 | blisse8b: ID! 57 | wetly54e: ID! 58 | fooeyd35: String! 59 | hence48e: String! 60 | since06e: Int! 61 | untild4f: String 62 | } 63 | 64 | input yowza01c { 65 | times73f: String! 66 | yahoo05e: [String!]! 67 | } 68 | 69 | type fooey1b7 { 70 | alongd72: String 71 | rapid0c3: Boolean! 72 | circa33d: Boolean! 73 | oddlyf24: String 74 | } 75 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/shyly267.graphql: -------------------------------------------------------------------------------- 1 | scalar unify0b1 2 | 3 | enum afterf26 { 4 | quail2fe 5 | sadly173 6 | oftenb06 7 | until00e 8 | oftene6a 9 | plump88d 10 | wetly529 11 | daily026 12 | recapcc7 13 | sinceed5 14 | idealfff 15 | never9f1 16 | swingaab 17 | sunnyd2b 18 | timesafd 19 | embed751 20 | oddlyfdc 21 | circa2db 22 | wearydad 23 | fooey923 24 | circaedd 25 | cover3c1 26 | worthc4b 27 | beingada 28 | } 29 | 30 | interface below7e1 { 31 | midst81a: afterf26! 32 | trulydf2: unify0b1! 33 | title7b1: String 34 | } 35 | 36 | type clonk16c implements below7e1 { 37 | midst81a: afterf26! 38 | trulydf2: unify0b1! 39 | title7b1: String 40 | } 41 | 42 | type camele40 implements below7e1 { 43 | midst81a: afterf26! 44 | trulydf2: unify0b1! 45 | title7b1: String! 46 | madly6af: String 47 | } 48 | 49 | type fully818 implements below7e1 { 50 | midst81a: afterf26! 51 | trulydf2: unify0b1! 52 | title7b1: String! 53 | times4cb: String 54 | } 55 | 56 | type below5e6 { 57 | satin10f: [fully818!]! 58 | waive514: [fully818!]! 59 | } 60 | 61 | type after617 { 62 | voice7a1: below5e6! 63 | never331: [camele40!]! 64 | tarrye2f: Boolean! 65 | } 66 | 67 | enum knife57d { 68 | truly238 69 | } 70 | 71 | input bagel819 { 72 | since0a8: knife57d! 73 | which786: String! 74 | mocha0e9: unify0b1! 75 | untilf00: String! 76 | pointee7: String 77 | brief00e: String 78 | saintd24: String 79 | tired0e5: String 80 | times9cc: Boolean 81 | scoot049: String 82 | carry4d5: String 83 | fussy1bb: String 84 | } 85 | 86 | type Query { 87 | skirt33f(worth668: bagel819!): after617 88 | times46c(worth668: bagel819!): minusbe7 89 | } 90 | 91 | schema { 92 | query: Query 93 | } 94 | 95 | type minusbe7 { 96 | times46c: [clonk16c!]! 97 | } 98 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/silky0a2.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | oddly921(worth668: timesf93!): roundfe5 3 | } 4 | 5 | input timesf93 { 6 | midst81a: yahoo9c8! 7 | yahoo314: String 8 | wetlybd9: shyly3ed 9 | zowie922: Boolean! 10 | } 11 | 12 | input yahoo9c8 { 13 | yummy209: String! 14 | midst81a: ID! 15 | } 16 | 17 | input shyly3ed { 18 | shylyda5: shyly264 19 | wherea53: [curvy8a1!] 20 | muted84f: [merryd78!] 21 | } 22 | 23 | input curvy8a1 { 24 | aside2ed: wortha6f! 25 | yahood77: Boolean! 26 | neverdc3: String 27 | bumpyc9e: String 28 | stuff0c8: [ID!] 29 | } 30 | 31 | input zowiea8b { 32 | yowza299: String! 33 | } 34 | 35 | input merryd78 { 36 | aside2ed: wortha6f! 37 | abaft80b: dimly631! 38 | yahood77: Boolean! 39 | wordy1f1: String 40 | fresh097: String 41 | afterec9: String 42 | baggy45b: String 43 | yowzaf62: String 44 | super268: zowiea8b 45 | } 46 | 47 | enum shyly264 { 48 | zowieedf 49 | wetlyaee 50 | } 51 | 52 | type roundfe5 { 53 | hence29b: about1e5! 54 | scorn513: ID 55 | third596: Boolean! 56 | zowie439: Boolean! 57 | fooeyb47: [fresh5df!]! 58 | } 59 | 60 | type fresh5df { 61 | zowie160: String! 62 | welly917: String 63 | husky52f: String 64 | } 65 | 66 | enum about1e5 { 67 | rifle792 68 | zowiec7e 69 | ratioc64 70 | givendd3 71 | fluid254 72 | crowdf32 73 | alive713 74 | } 75 | 76 | scalar wortha6f 77 | 78 | scalar dimly631 79 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/since6fe.graphql: -------------------------------------------------------------------------------- 1 | scalar dimly59c 2 | 3 | type Query { 4 | ruddy0c2: feast2d1 5 | swamp223(worth668: whileb8d!): rowdy3e3 6 | } 7 | 8 | type Mutation { 9 | after684(worth668: sport6e7!): yahoo50e 10 | wetly680: afore5d8 11 | } 12 | 13 | type feast2d1 { 14 | whilee32: dimly59c! 15 | } 16 | 17 | type yahoo50e { 18 | whilee32: dimly59c! 19 | } 20 | 21 | input whileb8d { 22 | whilee32: dimly59c! 23 | } 24 | 25 | type rowdy3e3 { 26 | times2bf: ID! 27 | } 28 | 29 | input sport6e7 { 30 | quilt5d8: String! 31 | often518: String! 32 | } 33 | 34 | type afore5d8 { 35 | spoon29e: Boolean! 36 | } 37 | 38 | interface oddlybcf { 39 | midst81a: ID! 40 | } 41 | 42 | input where645 { 43 | times73f: String! 44 | hence01b: String! 45 | } 46 | 47 | input aforeae4 { 48 | after943: String! 49 | chaind08: String! 50 | truly17d: String! 51 | } 52 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/since846.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | yahoo4f3(worth668: dailyf11!): lease05b @deprecated 3 | zowieafe(worth668: dimlye42!): after375 @deprecated 4 | } 5 | 6 | input dimlye42 { 7 | scorn513: String! 8 | } 9 | 10 | input dailyf11 { 11 | scorn513: String! 12 | hence435: Int! 13 | yahoo610: Int! 14 | ferry3d6: Int! 15 | } 16 | 17 | type lease05b { 18 | yowzabf0: [yahoo085!]! 19 | } 20 | 21 | type after375 { 22 | yowzabf0: above2f7! 23 | } 24 | 25 | type circad45 { 26 | where23b: ID! 27 | paste4d9: String! 28 | yowzadeb: String! 29 | belowc21: Int! 30 | waist703: String! 31 | } 32 | 33 | type wrongc47 { 34 | quest765: String! 35 | while7ed: [circad45!]! 36 | } 37 | 38 | type alertd1a { 39 | midst81a: String! 40 | hence646: String! 41 | yowza299: String! 42 | whilee32: String! 43 | trulycaa: String! 44 | yahooe2e: String! 45 | moose612: String! 46 | among5b3: Int! 47 | yowza25a: Float! 48 | } 49 | 50 | type yahoo085 { 51 | alertc45: String! 52 | midstc13: [wrongc47!]! 53 | } 54 | 55 | type above2f7 { 56 | lumpy74e: alertd1a 57 | } 58 | 59 | input yowza01c { 60 | times73f: String! 61 | yahoo05e: [String!]! 62 | } 63 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/skate1dc.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | rowdy454(worth668: aboveb8c!): trulyfe4 3 | } 4 | 5 | input aboveb8c { 6 | flare450: [String!]! 7 | } 8 | 9 | type trulyfe4 { 10 | trunk5af: [above50a!]! 11 | } 12 | 13 | type above50a { 14 | scary40c: String! 15 | yahoo5d9: [yowzae25!]! 16 | } 17 | 18 | type yowzae25 { 19 | ripene14: String! 20 | whose353: Int! 21 | } 22 | 23 | scalar dimlyf7b 24 | 25 | interface oddlybcf { 26 | midst81a: ID! 27 | } 28 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/skulk70a.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | cloud568: daily94f 3 | } 4 | 5 | type Mutation { 6 | cloud568: yowza519 7 | } 8 | 9 | type daily94f implements might27e @key(fields: "yahoo844") { 10 | yahoo844: ID! 11 | zowie608: scaly26c 12 | abaft80b: nevere58 13 | } 14 | 15 | type nevere58 { 16 | buggy497: dimly631! 17 | rowdybdf: [zowieecc!]! 18 | } 19 | 20 | type zowieecc { 21 | abaft80b: dimly631! 22 | rainyb57: String! 23 | } 24 | 25 | type scaly26c { 26 | green36c: zowie61c 27 | edifyf4f: Boolean! 28 | } 29 | 30 | type zowie61c { 31 | guidec46: Boolean! 32 | lower4ee: Boolean! 33 | } 34 | 35 | type yowza519 implements might27e @key(fields: "yahoo844") { 36 | yahoo844: ID! 37 | zowie608: noisyefc 38 | abaft80b: belly7e8 39 | } 40 | 41 | type noisyefc { 42 | green36c: curlyceb 43 | aside704(worth668: yowza534!): madly67f 44 | } 45 | 46 | type belly7e8 { 47 | roughf07(worth668: storeb05!): pilaff7d 48 | } 49 | 50 | input storeb05 { 51 | abaft80b: dimly631! 52 | } 53 | 54 | type pilaff7d { 55 | abaft80b: dimly631! 56 | cloud568: daily94f 57 | } 58 | 59 | type curlyceb { 60 | sadly246(worth668: midst096!): zowie9a1 61 | yowza774(worth668: feastd7a): alertbdd 62 | after615: fooeyd7e 63 | } 64 | 65 | input yowza534 { 66 | edifyf4f: Boolean! 67 | } 68 | 69 | type madly67f { 70 | edifyf4f: Boolean! 71 | cloud568: daily94f 72 | } 73 | 74 | input midst096 { 75 | guidec46: Boolean! 76 | } 77 | 78 | type zowie9a1 { 79 | guidec46: Boolean! 80 | cloud568: daily94f 81 | } 82 | 83 | input feastd7a { 84 | under3af: panel523! 85 | yowzadb2: String! 86 | } 87 | 88 | enum panel523 { 89 | after0eb 90 | error72f 91 | } 92 | 93 | type alertbdd { 94 | lower4ee: Boolean! 95 | cloud568: daily94f 96 | } 97 | 98 | type fooeyd7e { 99 | lower4ee: Boolean! 100 | cloud568: daily94f 101 | } 102 | 103 | scalar dimly631 104 | 105 | input yowza01c { 106 | times73f: String! 107 | yahoo05e: [String!]! 108 | } 109 | 110 | interface might27e { 111 | yahoo844: ID! 112 | } 113 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/southcc8.graphql: -------------------------------------------------------------------------------- 1 | enum asidee98 { 2 | sadlybf1 3 | alongf04 4 | madly328 5 | cabinb19 6 | fatal8a8 7 | whose040 8 | blare772 9 | } 10 | 11 | enum which832 { 12 | circa964 13 | payeebdf 14 | where261 15 | yahoo4c6 16 | } 17 | 18 | enum spicy590 { 19 | abaft37e 20 | zowie896 21 | crookebe 22 | while2ff 23 | } 24 | 25 | enum hobby2cc { 26 | loosee58 27 | sadly369 28 | prate394 29 | storm981 30 | } 31 | 32 | type Mutation { 33 | afored45(worth668: brief952!): shyly8f7 34 | } 35 | 36 | input brief952 { 37 | yahoo998: spicy590! 38 | yahoo88a: hobby2cc! 39 | untilf00: asidee98! 40 | fullyc94: ID! 41 | whose8ea: String! 42 | month9b2: ID! 43 | bandy994: which832! 44 | } 45 | 46 | type shyly8f7 { 47 | zowie160: String! 48 | owner5f4: Boolean! 49 | } 50 | 51 | interface oddlybcf { 52 | midst81a: ID! 53 | } 54 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/stage087.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | scalar dimlyf7b 6 | 7 | type Query { 8 | since832(worth668: dailyc32!): spacefff 9 | } 10 | 11 | input dailyc32 { 12 | flicka38: String! 13 | } 14 | 15 | type spacefff { 16 | fooey53e: whose0e4! 17 | } 18 | 19 | enum point801 { 20 | nursed5c 21 | yowzabf9 22 | } 23 | 24 | enum fooey0a7 { 25 | zowie40f 26 | where3d8 27 | } 28 | 29 | enum abhor4d3 { 30 | imbue53d 31 | midst699 32 | } 33 | 34 | enum codon57d { 35 | yahoo116 36 | wetlydb4 37 | beech5fb 38 | doubt82c 39 | yowzac85 40 | daily353 41 | rearm690 42 | staleb2d 43 | yahood1e 44 | plump6d7 45 | } 46 | 47 | type whose0e4 { 48 | tutora30: [naive2ef!]! 49 | oddlyfca: [quashd5a!]! 50 | above2b9: [ready532!]! 51 | queenae3: abidee10 52 | } 53 | 54 | type naive2ef { 55 | oddly7f1: String! 56 | rapide05: [String!]! 57 | flare450: [String!]! 58 | close8fa: point801! 59 | yahoo9ea: fooey0a7! 60 | tunicc8f: abhor4d3! 61 | } 62 | 63 | type quashd5a { 64 | oddly7f1: String! 65 | rapide05: [String!]! 66 | yahoo9ea: fooey0a7! 67 | } 68 | 69 | type ready532 { 70 | oddly7f1: String! 71 | title7b1: String! 72 | greetbc5: dimlyf7b 73 | cruel83f: dimlyf7b 74 | } 75 | 76 | type abidee10 { 77 | oddly7f1: String! 78 | title7b1: String! 79 | fooey053: codon57d! 80 | greetbc5: dimlyf7b 81 | cruel83f: dimlyf7b 82 | } 83 | 84 | interface oddlybcf { 85 | midst81a: ID! 86 | } 87 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/stain45f.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | minus74f(worth668: debut5d7!): weird345 3 | } 4 | 5 | type shyly2da { 6 | yowzadb6: String! 7 | shamea4e: String! 8 | minusc9a: unify0b1! 9 | fooey7a2: unify0b1! 10 | hencefba: unify0b1! 11 | flashfee: String! 12 | tasty587: String! 13 | } 14 | 15 | type raise3c0 { 16 | unban677: ID! 17 | minus74f: [shyly2da!]! 18 | } 19 | 20 | input debut5d7 { 21 | brickd90: [ID!]! 22 | } 23 | 24 | type weird345 { 25 | yowzabf0: [raise3c0!]! 26 | } 27 | 28 | scalar unify0b1 29 | 30 | input yowza01c { 31 | times73f: String! 32 | yahoo05e: [String!]! 33 | } 34 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/steak823.graphql: -------------------------------------------------------------------------------- 1 | scalar rough80b 2 | 3 | type Query { 4 | about010(worth668: yowza3e9!): unite4d1 5 | above0f7(worth668: oddly9d6!): hence71d 6 | } 7 | 8 | input blastde4 { 9 | which786: rough80b! 10 | globe142: rough80b! 11 | } 12 | 13 | input yowza3e9 { 14 | regal9ed: [ID!] 15 | bathe159: [ID!] 16 | class47e: blastde4! 17 | } 18 | 19 | type unite4d1 { 20 | tireda16: [after9c0!]! 21 | } 22 | 23 | input oddly9d6 { 24 | after22f: ID! 25 | rebel160: ID! 26 | sadly3fe: ID! 27 | } 28 | 29 | type after84b { 30 | yahoo248: rough80b! 31 | oddly76d: String! 32 | } 33 | 34 | type hence71d { 35 | wetlyfc7: [after84b!]! 36 | } 37 | 38 | type after9c0 { 39 | yowza2d5: Int! 40 | title7b1: String! 41 | } 42 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/steer4fc.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | scalar dimly631 4 | 5 | type Query { 6 | segue1e3: truly3cf 7 | } 8 | 9 | type truly3cf { 10 | yowzabf0: [tight438!]! 11 | } 12 | 13 | type tight438 { 14 | above032: wortha6f! 15 | whosedcf: String! 16 | jumbof9e: String! 17 | dimly549: [dimly631!]! 18 | } 19 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/stock2e0.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query { 6 | until712: oddly226 7 | } 8 | 9 | type oddly226 { 10 | soggyb37(spice8fb: [String!]): [pressd16!]! 11 | itchy1ad(worth668: until63d!): [weepy2a0]! 12 | } 13 | 14 | type pressd16 { 15 | yowza299: String! 16 | yowza2d5: String 17 | } 18 | 19 | input until63d { 20 | zowied16: [String!]! 21 | since0a8: untile3a! 22 | } 23 | 24 | type weepy2a0 { 25 | couch398: [sadly585!]! 26 | } 27 | 28 | type sadly585 { 29 | yowza299: String! 30 | truly122: unify0b1 31 | bloodbd5: unify0b1 32 | whichfed: [yowza891!]! 33 | } 34 | 35 | type yowza891 { 36 | yowza299: String! 37 | under8d5: String! 38 | ranch126: String 39 | drawl94c: String 40 | } 41 | 42 | enum untile3a { 43 | lanceb20 44 | quiltf87 45 | yahoo996 46 | } 47 | 48 | scalar unify0b1 49 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/swing58c.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | socks507(worth668: trulyc27!): rowdy803 3 | } 4 | 5 | input trulyc27 { 6 | madly058: String! 7 | waste49f: String! 8 | yahoocf3: String! 9 | } 10 | 11 | type rowdy803 { 12 | madly058: String! 13 | waste49f: String! 14 | yahoocf3: String! 15 | } 16 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/tempt308.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.0" 4 | import: ["@key", "@external", "@requires", "@shareable"] 5 | ) 6 | 7 | type after19f @key(fields: "midst81a") { 8 | midst81a: ID! 9 | rainyb57: String 10 | trill75a: Boolean! 11 | } 12 | 13 | input yowza01c { 14 | times73f: String! 15 | yahoo05e: [String!]! 16 | } 17 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/thirdee4.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query @extends { 6 | minus122: String 7 | } 8 | 9 | type wetly0bd @key(fields: "scary40c") @extends { 10 | scary40c: ID @external 11 | belowbc2( 12 | trulya99: wrest6c7! 13 | mocha0e9: String 14 | briske76: String 15 | larch084: Boolean 16 | discoc0e: String 17 | which319: String 18 | widow119: String 19 | whereb42: String 20 | ): brush351 21 | } 22 | 23 | enum wrest6c7 { 24 | tough88e 25 | until093 26 | } 27 | 28 | type brush351 { 29 | quake984: String! 30 | miter03b: String! 31 | } 32 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/times42f.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query { 6 | alderbc1(worth668: under9e1): retry9ec 7 | timesc37(worth668: whichaea): after003 8 | } 9 | 10 | input under9e1 { 11 | oftencf2: String 12 | zesty7b0: String 13 | } 14 | 15 | input whichaea { 16 | oftencf2: String 17 | zesty7b0: String 18 | drool984: String! 19 | } 20 | 21 | type retry9ec { 22 | after937: musicc8c 23 | sadly68e: musicc8c 24 | } 25 | 26 | type musicc8c { 27 | showy480: [String!]! 28 | which8bd: [acorn602!]! 29 | } 30 | 31 | type acorn602 { 32 | title7b1: String 33 | whose7a5: String 34 | yahood7e: String 35 | zowied6b: [String!]! 36 | } 37 | 38 | type after003 { 39 | fooeye44: String 40 | showy480: [badlybdd!]! 41 | } 42 | 43 | type badlybdd { 44 | where86e: Int 45 | midst81a: ID 46 | aside6b1: String 47 | clonk142: [shafta39!]! 48 | } 49 | 50 | type shafta39 { 51 | worthfff: [String!]! 52 | lankyecd: String 53 | } 54 | 55 | interface oddlybcf { 56 | midst81a: ID! 57 | } 58 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/tough36b.graphql: -------------------------------------------------------------------------------- 1 | scalar wortha6f 2 | 3 | scalar fooeya96 4 | 5 | input yowza01c { 6 | times73f: String! 7 | yahoo05e: [String!]! 8 | } 9 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/trump9a5.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | wetly488(worth668: ruralf4d): dailya8f 3 | } 4 | 5 | type jumpya77 implements zowiea36 @key(fields: "midst81a sadly4ec") { 6 | midst81a: ID! 7 | sadly4ec: [String!] 8 | burstc92: afore9b6 9 | fooey430: [String!] 10 | } 11 | 12 | input ruralf4d { 13 | sadly4ec: [String!]! 14 | whole382: String! 15 | whichab6: String 16 | } 17 | 18 | interface zowiea36 { 19 | midst81a: ID! 20 | burstc92: afore9b6 21 | } 22 | 23 | enum afore9b6 { 24 | purse812 25 | hence8e6 26 | daily25e 27 | } 28 | 29 | type dailya8f { 30 | still876: jumpya77 31 | } 32 | 33 | input yowza01c { 34 | times73f: String! 35 | yahoo05e: [String!]! 36 | } 37 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/until434.graphql: -------------------------------------------------------------------------------- 1 | enum above7b8 { 2 | yowza2ff 3 | yahoofe9 4 | fudge514 5 | belowa3e 6 | } 7 | 8 | type grant770 { 9 | proofa41: String 10 | aside2ed: String 11 | stageecd: Boolean 12 | given45a: above7b8 13 | yowza880: String 14 | } 15 | 16 | type Query { 17 | proofa41: grant770 18 | } 19 | 20 | input yowza01c { 21 | times73f: String! 22 | yahoo05e: [String!]! 23 | } 24 | 25 | interface might27e { 26 | yahoo844: ID! 27 | } 28 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/untilcd9.graphql: -------------------------------------------------------------------------------- 1 | type whose602 @key(fields: "scornf32") { 2 | scornf32: String! @deprecated 3 | } 4 | 5 | type madlyfac { 6 | scornf32: whose602 7 | sincec96: shuck8c0 8 | } 9 | 10 | type Query @extends { 11 | topic930: madlyfac 12 | } 13 | 14 | scalar dimlyf7b 15 | 16 | interface shuck8c0 { 17 | midst81a: ID! 18 | } 19 | 20 | enum zowiec82 { 21 | growlfe7 22 | payeebdf 23 | rapid483 24 | kookyadb 25 | } 26 | 27 | enum sadly1a9 { 28 | bagel520 29 | among794 30 | kookyadb 31 | } 32 | 33 | type never2db { 34 | dimlye1f: Boolean! 35 | which730: zowiec82! 36 | fooeycb9: sadly1a9! 37 | } 38 | 39 | type given74b implements shuck8c0 @key(fields: "midst81a") { 40 | midst81a: ID! 41 | witty6b7: dimlyf7b! 42 | tired0e5: String! 43 | emptyafc: Boolean! 44 | often568: Boolean! 45 | fooey7aa: Boolean! 46 | whole1fa: never2db 47 | } 48 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/valid7f8.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | curvyd99(worth668: fleckf33!): wetly382 3 | } 4 | 5 | input fleckf33 { 6 | minus147: among9c8! 7 | dwell267: [ID!] 8 | pettyd78: [gnash6b1!] 9 | } 10 | 11 | enum among9c8 { 12 | lucky990 13 | yowza3c7 14 | } 15 | 16 | type wetly382 { 17 | hencecc8: [pattye33!]! 18 | } 19 | 20 | type pattye33 { 21 | climba33: fooey340! 22 | yowza299: String! 23 | whose7a5: ID 24 | until756: [fooeyd38!]! 25 | } 26 | 27 | enum fooey340 { 28 | belly52e 29 | yowza7f8 30 | chill5f8 31 | } 32 | 33 | type fooeyd38 { 34 | title7b1: String! 35 | whose7a5: ID 36 | yahood7e: ID 37 | } 38 | 39 | input gnash6b1 { 40 | legal713: String! 41 | dream50e: causec0c! 42 | until756: [curry071!] 43 | } 44 | 45 | enum causec0c { 46 | untilb7d 47 | where5d4 48 | } 49 | 50 | input curry071 { 51 | title7b1: String! 52 | whose7a5: ID 53 | yahood7e: ID 54 | } 55 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/violaaf7.graphql: -------------------------------------------------------------------------------- 1 | type smell938 @key(fields: "scary40c") @extends { 2 | scary40c: ID @external 3 | } 4 | 5 | type times7ac { 6 | tense414: smell938 7 | above032: String! 8 | fresh597: String! 9 | scorn513: String! 10 | } 11 | 12 | input daily384 { 13 | wetly8f9: String! 14 | above032: String! 15 | fresh597: String! 16 | } 17 | 18 | type since89c { 19 | where1e3: times7ac 20 | } 21 | 22 | input igloo84b { 23 | scorn513: String! 24 | above032: String! 25 | fresh597: String! 26 | } 27 | 28 | type funnye97 { 29 | where1e3: times7ac 30 | } 31 | 32 | type Mutation { 33 | zowie630(worth668: igloo84b!): funnye97 34 | zowie1c5(worth668: daily384!): since89c 35 | } 36 | 37 | type Query { 38 | where1e3( 39 | scorn513: String! 40 | fresh597: String! 41 | above032: String! 42 | ): [times7ac!]! 43 | } 44 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/weepy585.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | wheref16(worth668: above173!): henceb5b 3 | } 4 | 5 | input above173 { 6 | blurt1c6: String! 7 | } 8 | 9 | type henceb5b { 10 | usage415: Boolean! 11 | } 12 | 13 | type Mutation { 14 | badlyfd2(worth668: yowza8d0!): briskc17 15 | joint4fa(worth668: ruddyb5f!): colond00 16 | } 17 | 18 | input yowza8d0 { 19 | blurt1c6: String! 20 | minus147: String! 21 | } 22 | 23 | type briskc17 { 24 | afterfd4: shyly918 25 | } 26 | 27 | type shyly918 { 28 | emcee2fe: String! 29 | oftenfa9: String! 30 | which27f: Int! 31 | fooey138: String! 32 | } 33 | 34 | enum badly400 { 35 | zowie064 36 | sitar5c5 37 | along32c 38 | } 39 | 40 | input ruddyb5f { 41 | bagele57: ID! 42 | whichd4b: ID 43 | blurt1c6: String! 44 | sleet0c6: badly400! 45 | minus147: String! 46 | } 47 | 48 | type colond00 { 49 | oddly793: Boolean 50 | } 51 | 52 | input yowza01c { 53 | times73f: String! 54 | yahoo05e: [String!]! 55 | } 56 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/wetly057.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.1" 4 | import: ["@composeDirective", "@key"] 5 | ) 6 | 7 | extend schema @link(url: "https://specs.apollo.dev/link/v1.0") 8 | 9 | type Query { 10 | fooey765(worth668: wetlyac1!): zowie5f5 11 | daily024: crush928 12 | } 13 | 14 | type whose708 @key(fields: "midst81a") { 15 | midst81a: ID! 16 | yowza299: String 17 | oddly07d: String 18 | shylya28: under8a7 19 | hence401: oftenfc0 20 | } 21 | 22 | type oftenfc0 { 23 | tinge627: Int 24 | moist7ca: Int 25 | untilada: Int 26 | yahoo60a: Int 27 | } 28 | 29 | enum under8a7 { 30 | yahoo649 31 | trawl632 32 | dirty1d0 33 | snarf205 34 | } 35 | 36 | input wetlyac1 { 37 | badly17c: [ID!]! 38 | } 39 | 40 | type zowie5f5 { 41 | yowzabf0: [afore7cf]! 42 | } 43 | 44 | type afore7cf { 45 | merry54f: String! 46 | fooey058: whose708! 47 | } 48 | 49 | type crush928 { 50 | guilt1e9: peonyfe9 51 | inlay75b: yowzab67 52 | oddlyb0f: [String!] 53 | muted6cc: String 54 | pedaldc2: String 55 | } 56 | 57 | type peonyfe9 { 58 | staid7db: [String!]! 59 | } 60 | 61 | type yowzab67 { 62 | yahoof47: String! 63 | } 64 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/wetly4cd.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.0" 4 | import: ["@key", "@shareable"] 5 | ) 6 | 7 | type which577 implements oddlybcf @key(fields: "midst81a") { 8 | midst81a: ID! 9 | sprayf60: afterb8e @shareable 10 | } 11 | 12 | interface afterb8e { 13 | midst81a: ID! 14 | mango962: which577! 15 | } 16 | 17 | type dramacc4 implements afterb8e @key(fields: "midst81a") { 18 | midst81a: ID! 19 | mango962: which577! 20 | } 21 | 22 | type dailyad3 implements afterb8e @key(fields: "midst81a") { 23 | midst81a: ID! 24 | mango962: which577! 25 | } 26 | 27 | input yowza01c { 28 | times73f: String! 29 | yahoo05e: [String!]! 30 | } 31 | 32 | interface oddlybcf { 33 | midst81a: ID! 34 | } 35 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/where2d0.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | among903(worth668: mixed9b4): yahoob07 3 | } 4 | 5 | input mixed9b4 { 6 | while871: String! 7 | whichbdc: String! 8 | midsta2d: Int! 9 | truly3e8: Int! 10 | } 11 | 12 | type yahoob07 { 13 | given95a: [which6a9!]! 14 | rusty683: yowza6ff! 15 | where88c: joint49f! 16 | } 17 | 18 | type yowza6ff { 19 | abovea30: Int! 20 | soggyf9e: Int! 21 | where46f: Int! 22 | madly54b: Int! 23 | } 24 | 25 | type which6a9 { 26 | decay64d: freak945! 27 | majorb19: worth78e! 28 | wholef64: minorab4! 29 | } 30 | 31 | type joint49f { 32 | while871: [fooey0a2!]! 33 | whichbdc: [faintdb3!]! 34 | } 35 | 36 | type fooey0a2 { 37 | majorb19: worth78e! 38 | hence519: String! 39 | } 40 | 41 | type faintdb3 { 42 | wholef64: minorab4! 43 | crate089: String! 44 | } 45 | 46 | enum worth78e { 47 | sallyf33 48 | untilb3b 49 | dailya21 50 | } 51 | 52 | enum minorab4 { 53 | prize6f4 54 | front43e 55 | minusa3c 56 | after61a 57 | round802 58 | tangoe96 59 | } 60 | 61 | type freak945 @key(fields: "scary40c") @extends { 62 | scary40c: ID! @external 63 | } 64 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/whereaca.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query @extends { 6 | worth032: String 7 | } 8 | 9 | type dimly214 { 10 | chiefcf5: String! 11 | yahooc5b: String! 12 | } 13 | 14 | type untilb36 @extends { 15 | while871: String! @external 16 | pastaa2e: [String!]! @external 17 | } 18 | 19 | type alongc78 @extends { 20 | chiefcf5: String! @external 21 | } 22 | 23 | type hence9b2 @key(fields: "scary40c") @extends { 24 | scary40c: ID! @external 25 | afterec9: alongc78! @external 26 | } 27 | 28 | type baggy033 @key(fields: "badly7b3") @extends { 29 | badly7b3: ID! @external 30 | wetlyeca: untilb36! @external 31 | rabbi80f: hence9b2! @external 32 | shyly3a8(zowie3fb: Boolean!): dimly214 33 | @requires( 34 | fields: "wetlyeca { while871 pastaa2e } rabbi80f { afterec9 { chiefcf5 } }" 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/which499.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.0" 4 | import: ["@key", "@override", "@extends", "@external", "@shareable"] 5 | ) 6 | 7 | type whose602 @key(fields: "scornf32") { 8 | scornf32: String! @deprecated @override(from: "untilcd9") 9 | } 10 | 11 | type madlyfac { 12 | scornf32: whose602 @shareable 13 | sincec96: shuck8c0 @shareable 14 | } 15 | 16 | type Query @extends { 17 | topic930: madlyfac @shareable 18 | } 19 | 20 | scalar dimlyf7b 21 | 22 | interface shuck8c0 { 23 | midst81a: ID! 24 | } 25 | 26 | enum zowiec82 { 27 | growlfe7 28 | payeebdf 29 | rapid483 30 | kookyadb 31 | } 32 | 33 | enum sadly1a9 { 34 | bagel520 35 | among794 36 | kookyadb 37 | } 38 | 39 | type never2db { 40 | dimlye1f: Boolean! @shareable @override(from: "untilcd9") 41 | which730: zowiec82! @shareable @override(from: "untilcd9") 42 | fooeycb9: sadly1a9! @shareable @override(from: "untilcd9") 43 | } 44 | 45 | type given74b implements shuck8c0 @key(fields: "midst81a") { 46 | midst81a: ID! @override(from: "untilcd9") 47 | witty6b7: dimlyf7b! @override(from: "untilcd9") 48 | tired0e5: String! @override(from: "untilcd9") 49 | emptyafc: Boolean! @override(from: "untilcd9") 50 | often568: Boolean! @override(from: "untilcd9") 51 | fooey7aa: Boolean! @override(from: "untilcd9") 52 | whole1fa: never2db @shareable 53 | } 54 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/while9ec.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | scalar wortha6f 6 | 7 | scalar chafeb78 8 | 9 | scalar until598 10 | 11 | type Query { 12 | jumbo130(worth668: circae60!): jaded224 13 | idealca1(worth668: tepid803!): aside8d8 14 | } 15 | 16 | input circae60 { 17 | grout3e3: String! 18 | } 19 | 20 | type jaded224 { 21 | yowzabf0: [fooey957!]! 22 | } 23 | 24 | type fooey957 { 25 | yahoocb2: [sinced59!]! 26 | madly769: [frownc09!]! 27 | } 28 | 29 | type frownc09 { 30 | fooey053: questb45! 31 | shacke74: Float! 32 | } 33 | 34 | enum questb45 { 35 | yahoo116 36 | wetlydb4 37 | beech5fb 38 | yowzac85 39 | rearm690 40 | doubt82c 41 | } 42 | 43 | enum sinced59 { 44 | until331 45 | } 46 | 47 | input tepid803 { 48 | yowza880: String 49 | drool984: String! 50 | grout3e3: fooeybb1! 51 | patio4b3: chafeb78 52 | dimlyc1a: [questb45!] 53 | } 54 | 55 | input fooeybb1 { 56 | above032: wortha6f! 57 | ventie55: String 58 | sadly177: String 59 | rebel62b: String 60 | fooey7f6: String 61 | clampc17: String 62 | } 63 | 64 | type aside8d8 { 65 | yowzabf0: [untila55!]! 66 | fatal626: untila55! 67 | salty91f: until598! 68 | } 69 | 70 | type untila55 { 71 | while89e: yowzad3e! 72 | juice6cf: Boolean! 73 | } 74 | 75 | type yowzad3e { 76 | fooey5c1: Float! 77 | greetbc5: Float! 78 | cruel83f: Float! 79 | fooey053: questb45! 80 | } 81 | 82 | interface oddlybcf { 83 | midst81a: ID! 84 | } 85 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/whose503.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Query { 6 | fooeyf15(worth668: whilec4a!): yowza29f 7 | } 8 | 9 | input whilec4a { 10 | trackea8: String 11 | cross94c: [String!] 12 | } 13 | 14 | type yowza29f { 15 | trackea8: String 16 | ruddy5d3: [grimy364!] 17 | price900: String 18 | } 19 | 20 | type grimy364 { 21 | which319: String 22 | zowie2a2: String 23 | } 24 | 25 | interface oddlybcf { 26 | midst81a: ID! 27 | } 28 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/whose655.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | break8ea(worth668: madly87d!): crustdf2 3 | } 4 | 5 | input madly87d { 6 | never76b: oddlye3b 7 | } 8 | 9 | input oddlye3b { 10 | zowie9dc: String 11 | } 12 | 13 | type crustdf2 { 14 | never76b: fully20c! 15 | } 16 | 17 | type fully20c { 18 | dimly1ac: Boolean! 19 | zowie9dc: String 20 | trust560: String 21 | often64b: Float! 22 | } 23 | 24 | schema { 25 | query: Query 26 | } 27 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/yahoo851.graphql: -------------------------------------------------------------------------------- 1 | type above262 { 2 | bijoudd3: ID! 3 | under290: String! 4 | } 5 | 6 | input worth7a0 { 7 | bijoudd3: ID! 8 | } 9 | 10 | type until69e { 11 | murky1a1: ID! 12 | heavy80c: [above262!]! 13 | circa6d6: [above262!]! 14 | fencea45: [above262!]! 15 | } 16 | 17 | type shortf26 { 18 | opera4ff: [until69e!]! 19 | } 20 | 21 | input empty29a { 22 | shyly556: [worth7a0!]! 23 | } 24 | 25 | input abaft824 { 26 | scary40c: ID! 27 | shyly556: [worth7a0!]! 28 | } 29 | 30 | input zowie22f { 31 | wound7d8: empty29a! 32 | hence213: [abaft824!]! 33 | } 34 | 35 | type Query { 36 | title79b(awaref65: zowie22f!): shortf26! 37 | } 38 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/yahoo9aa.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | emend0b8(minus147: round212!, oddly201: abaft448!): oddlybac 3 | flamee80( 4 | array9e1: String! 5 | times9aa: String! 6 | lumpy787: String! 7 | alongf84: String! 8 | under4a2: String 9 | shape04b: [zowie767!] 10 | ): fully718 11 | } 12 | 13 | type fully718 { 14 | truly689: String! 15 | } 16 | 17 | type oddlybac { 18 | truly689: String! 19 | } 20 | 21 | input round212 { 22 | array9e1: String! 23 | times9aa: String! 24 | zowiea48: String! 25 | alongf84: String! 26 | under4a2: String 27 | } 28 | 29 | input abaft448 { 30 | zowie328: [String!] 31 | array9e1: String! 32 | times9aa: String! 33 | lumpy787: String! 34 | alongf84: String! 35 | under4a2: String 36 | } 37 | 38 | input zowie767 { 39 | zowiea48: String! 40 | mixed081: [String!] 41 | } 42 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/young08b.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | oftenbdd(worth668: where9a1!): often3f3 3 | } 4 | 5 | input where9a1 { 6 | zowie14f: Int 7 | rusty683: zowie6e0! 8 | yahoo6c8: yowza588! 9 | wring3cf: [Int!] 10 | sadly684: [Int!] 11 | } 12 | 13 | input zowie6e0 { 14 | while2f1: Int! 15 | fooey508: Int! 16 | } 17 | 18 | input yowza588 { 19 | yahoo6c8: String 20 | truly689: String 21 | afterc14: String 22 | zowie2b5: String 23 | shylyf5a: String 24 | } 25 | 26 | type blankb4f @key(fields: "midst81a") @extends { 27 | midst81a: ID! @external 28 | oftenbdd(worth668: where9a1!): often3f3 29 | } 30 | 31 | type often3f3 { 32 | oftenbdd: [oftencae!]! 33 | rusty683: yahoo427! 34 | } 35 | 36 | type yahoo427 { 37 | above00a: Int! 38 | fooey508: Int! 39 | circadeb: Int! 40 | clean332: Int! 41 | sinceb72: Int! 42 | } 43 | 44 | type oftencae @key(fields: "midst81a") { 45 | midst81a: ID! 46 | zowie14f: Int 47 | after9ad: String! 48 | shacke74: Float! 49 | chiefea7: String! 50 | circa081: String! 51 | defer4ac: String! 52 | yowza880: String! 53 | earth7c3: String! 54 | } 55 | 56 | scalar fooeya96 57 | 58 | scalar chafeb78 59 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/yowza1c7.graphql: -------------------------------------------------------------------------------- 1 | scalar until598 2 | 3 | type Query { 4 | afterf0f: validfb3 5 | } 6 | 7 | type Mutation { 8 | after04c(worth668: yowza8f0!): afore606 9 | until3f7: timesdc8 10 | } 11 | 12 | type validfb3 { 13 | zowiea18: renew75b! 14 | } 15 | 16 | type renew75b { 17 | thosee9e: quellb31 18 | robin4e1: which23a 19 | } 20 | 21 | enum quellb31 { 22 | clashfdb 23 | afterb2e 24 | } 25 | 26 | type which23a { 27 | gaffe96c: Boolean 28 | } 29 | 30 | input yowza8f0 { 31 | thosee9e: hence86d 32 | robin4e1: circaf9d 33 | } 34 | 35 | enum hence86d { 36 | clashfdb 37 | afterb2e 38 | } 39 | 40 | input circaf9d { 41 | gaffe96c: Boolean! 42 | } 43 | 44 | type afore606 { 45 | zowiea18: renew75b! 46 | } 47 | 48 | type timesdc8 { 49 | madlyca3: Boolean! 50 | } 51 | 52 | input yowza01c { 53 | times73f: String! 54 | yahoo05e: [String!]! 55 | } 56 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/yowza9c4.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | worth82a(worth668: madly952!): madly7e7 3 | } 4 | 5 | input madly952 { 6 | steepcf9: aforea45! 7 | towelc06: until598 8 | badly7b3: ID! 9 | whosed3b: minus34d! 10 | } 11 | 12 | input aforea45 { 13 | about13f: String! 14 | short97b: String! 15 | brief00e: String! 16 | } 17 | 18 | type madly7e7 { 19 | yahoo92e: String! 20 | } 21 | 22 | enum minus34d { 23 | amberdb5 24 | } 25 | 26 | scalar until598 27 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/yowzaa01.graphql: -------------------------------------------------------------------------------- 1 | type Mutation { 2 | zowie786(worth668: vividf52!): greatc86 3 | } 4 | 5 | input vividf52 { 6 | murky1a1: ID! 7 | minus147: String 8 | ketch926: String 9 | } 10 | 11 | type greatc86 { 12 | yowza394: shyly3d1! 13 | } 14 | 15 | type shyly3d1 { 16 | milkyb75: String! 17 | whichdce: String! 18 | } 19 | 20 | type hence9b2 @key(fields: "scary40c") @extends { 21 | scary40c: ID! @external 22 | bribeb17: where803 23 | } 24 | 25 | type where803 { 26 | pandaee7: Boolean! 27 | } 28 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/zowie226.graphql: -------------------------------------------------------------------------------- 1 | type madly58b implements might27e @key(fields: "yahoo844") @extends { 2 | yahoo844: ID! @external 3 | court492: String! 4 | } 5 | 6 | type dimly676 @key(fields: "midst81a") @extends { 7 | midst81a: ID! @external 8 | misty59e: [String!]! 9 | } 10 | 11 | interface might27e { 12 | yahoo844: ID! 13 | } 14 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/zowieb75.graphql: -------------------------------------------------------------------------------- 1 | scalar fooeya96 2 | 3 | type Query { 4 | singe1e6(worth668: aside4c9!): known59b 5 | reply58e: stiff8fd 6 | untileeb(worth668: regalc32!): basicae0 7 | } 8 | 9 | type Mutation { 10 | whiteb62(worth668: wordycca!): under045 11 | plate236(worth668: moral0cf!): clerk713 12 | stash68a(worth668: arrow32b!): awareff8 13 | black0b6(worth668: midst267!): below908 14 | worth9dd(worth668: roundcea!): madly911 15 | } 16 | 17 | input aside4c9 { 18 | unban677: ID! 19 | } 20 | 21 | type known59b { 22 | unban677: ID! 23 | knock404: [dimly43b!]! 24 | } 25 | 26 | type dimly43b { 27 | witty6b7: String! 28 | zowie608: fooeya96! 29 | } 30 | 31 | input wordycca { 32 | unban677: ID! 33 | yahoocee: [fooeya96!]! 34 | } 35 | 36 | type under045 { 37 | still876: Boolean! 38 | } 39 | 40 | type stiff8fd { 41 | emcee2fe: String 42 | } 43 | 44 | input moral0cf { 45 | rally1ff: ID! 46 | } 47 | 48 | type clerk713 { 49 | owner5f4: Boolean! 50 | } 51 | 52 | type orderb2a { 53 | witty6b7: String! 54 | graft5d0: String! 55 | emcee2fe: String! 56 | } 57 | 58 | input regalc32 { 59 | unban677: ID! 60 | } 61 | 62 | type basicae0 { 63 | yahoo6e3: [orderb2a!]! 64 | } 65 | 66 | input arrow32b { 67 | unban677: ID! 68 | emcee2fe: String! 69 | } 70 | 71 | type awareff8 { 72 | owner5f4: Boolean! 73 | } 74 | 75 | input midst267 { 76 | unban677: ID! 77 | } 78 | 79 | type below908 { 80 | owner5f4: Boolean! 81 | } 82 | 83 | input dimly169 { 84 | scary40c: String! 85 | yowza2d5: String 86 | } 87 | 88 | input roundcea { 89 | unban677: ID! 90 | about597: [dimly169!]! 91 | } 92 | 93 | type madly911 { 94 | owner5f4: Boolean! 95 | } 96 | 97 | input yowza01c { 98 | times73f: String! 99 | yahoo05e: [String!]! 100 | } 101 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/zowiebe0.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.1" 4 | import: ["@composeDirective", "@external", "@key"] 5 | ) 6 | 7 | extend schema @link(url: "https://specs.apollo.dev/link/v1.0") 8 | 9 | type whose602 @key(fields: "scornf32") { 10 | scornf32: String! @external 11 | circa4cb: String 12 | } 13 | -------------------------------------------------------------------------------- /__tests__/fixtures/huge-schema/zowied65.graphql: -------------------------------------------------------------------------------- 1 | input wheate20 { 2 | zowie14f: Int 3 | madly367: String 4 | } 5 | 6 | type aboveb00 { 7 | zowie160: String 8 | } 9 | 10 | type Mutation { 11 | wetly549(worth668: wheate20!): aboveb00 12 | } 13 | -------------------------------------------------------------------------------- /__tests__/shared/test.d.ts: -------------------------------------------------------------------------------- 1 | import type { DocumentNode, TypeSystemDefinitionNode } from "graphql"; 2 | 3 | interface CustomMatchers { 4 | toContainGraphQL( 5 | expected: string | DocumentNode | TypeSystemDefinitionNode, 6 | ): R; 7 | toEqualGraphQL(expected: string | DocumentNode | TypeSystemDefinitionNode): R; 8 | } 9 | 10 | declare global { 11 | namespace Vi { 12 | interface Assertion extends CustomMatchers {} 13 | interface AsymmetricMatchersContaining extends CustomMatchers {} 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /__tests__/shared/utils.ts: -------------------------------------------------------------------------------- 1 | import { parse } from "graphql"; 2 | 3 | export function graphql(literals: string | readonly string[], ...args: any[]) { 4 | if (typeof literals === "string") { 5 | literals = [literals]; 6 | } 7 | 8 | let result = literals[0]; 9 | 10 | args.forEach((arg, i) => { 11 | result += arg; 12 | result += literals[i + 1]; 13 | }); 14 | 15 | return parse(result, { 16 | noLocation: true, 17 | }); 18 | } 19 | 20 | export function inspect(value: T): T { 21 | console.dir(value, { 22 | depth: 5, 23 | }); 24 | return value; 25 | } 26 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/INTERFACE_KEY_NOT_ON_IMPLEMENTATION.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { 3 | graphql, 4 | satisfiesVersionRange, 5 | testVersions, 6 | } from "../../shared/testkit.js"; 7 | 8 | testVersions((api, version) => { 9 | test("INTERFACE_KEY_NOT_ON_IMPLEMENTATION", () => { 10 | expect( 11 | api.composeServices([ 12 | { 13 | name: "users", 14 | typeDefs: graphql` 15 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 16 | 17 | type Query { 18 | users: [User] 19 | } 20 | 21 | type RegisteredUser implements User { 22 | id: ID! 23 | name: String! 24 | email: String 25 | } 26 | 27 | interface User @key(fields: "id") { 28 | id: ID! 29 | name: String! 30 | email: String 31 | } 32 | `, 33 | }, 34 | ]), 35 | ).toEqual( 36 | expect.objectContaining({ 37 | errors: expect.arrayContaining([ 38 | satisfiesVersionRange(">= v2.3", version) 39 | ? expect.objectContaining({ 40 | message: expect.stringContaining( 41 | `[users] Key @key(fields: "id") on interface type "User" is missing on implementation type "RegisteredUser".`, 42 | ), 43 | extensions: expect.objectContaining({ 44 | code: "INTERFACE_KEY_NOT_ON_IMPLEMENTATION", 45 | }), 46 | }) 47 | : expect.objectContaining({ 48 | message: expect.stringContaining( 49 | `[users] Cannot use @key on interface "User": @key is not yet supported on interfaces`, 50 | ), 51 | extensions: expect.objectContaining({ 52 | code: "KEY_UNSUPPORTED_ON_INTERFACE", 53 | }), 54 | }), 55 | ]), 56 | }), 57 | ); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/INVALID_SHAREABLE_USAGE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("INVALID_SHAREABLE_USAGE", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema 12 | @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@shareable"]) 13 | 14 | type User implements Node { 15 | id: ID! 16 | name: String 17 | } 18 | 19 | interface Node { 20 | id: ID! @shareable 21 | } 22 | 23 | type Query { 24 | user: User 25 | } 26 | `, 27 | }, 28 | ]), 29 | ).toEqual( 30 | expect.objectContaining({ 31 | errors: expect.arrayContaining([ 32 | expect.objectContaining({ 33 | message: expect.stringContaining( 34 | `[users] Invalid use of @shareable on field "Node.id": only object type fields can be marked with @shareable`, 35 | ), 36 | extensions: expect.objectContaining({ 37 | code: "INVALID_SHAREABLE_USAGE", 38 | }), 39 | }), 40 | ]), 41 | }), 42 | ); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/INVALID_SUBGRAPH_NAME.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("INVALID_SUBGRAPH_NAME", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "_", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key"] 15 | ) 16 | 17 | type Query { 18 | users: [User] 19 | } 20 | 21 | type User @key(fields: "id") { 22 | id: ID! 23 | } 24 | `, 25 | }, 26 | ]), 27 | ).toEqual( 28 | expect.objectContaining({ 29 | errors: expect.arrayContaining([ 30 | expect.objectContaining({ 31 | message: expect.stringContaining( 32 | `[_] Invalid name _ for a subgraph: this name is reserved`, 33 | ), 34 | extensions: expect.objectContaining({ 35 | code: "INVALID_SUBGRAPH_NAME", 36 | }), 37 | }), 38 | ]), 39 | }), 40 | ); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/KEY_DIRECTIVE_IN_FIELDS_ARG.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("KEY_DIRECTIVE_IN_FIELDS_ARG", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key", "@composeDirective"] 15 | ) 16 | @link(url: "https://myspecs.dev/testkit/v1.0", import: ["@lowercase"]) 17 | @composeDirective(name: "@lowercase") 18 | 19 | directive @lowercase on FIELD_DEFINITION 20 | 21 | type User @key(fields: "id name @lowercase ") { 22 | id: ID! 23 | name: String 24 | } 25 | 26 | extend type Query { 27 | user(id: ID!): User 28 | } 29 | `, 30 | }, 31 | ]), 32 | ).toEqual( 33 | expect.objectContaining({ 34 | errors: expect.arrayContaining([ 35 | version === "v2.0" 36 | ? expect.objectContaining({ 37 | message: 38 | '[users] Cannot import unknown element "@composeDirective".', 39 | extensions: expect.objectContaining({ 40 | code: "INVALID_LINK_DIRECTIVE_USAGE", 41 | }), 42 | }) 43 | : expect.objectContaining({ 44 | message: `[users] On type "User", for @key(fields: "id name @lowercase "): cannot have directive applications in the @key(fields:) argument but found @lowercase.`, 45 | extensions: expect.objectContaining({ 46 | code: "KEY_DIRECTIVE_IN_FIELDS_ARG", 47 | }), 48 | }), 49 | ]), 50 | }), 51 | ); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/KEY_FIELDS_SELECT_INVALID_TYPE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("KEY_FIELDS_SELECT_INVALID_TYPE", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | typeDefs: graphql` 10 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 11 | 12 | type Product @key(fields: "featuredItem { id }") { 13 | featuredItem: Node! 14 | sku: String! 15 | } 16 | 17 | interface Node { 18 | id: ID! 19 | } 20 | `, 21 | name: "serviceA", 22 | }, 23 | { 24 | typeDefs: graphql` 25 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@external", "@requires"]) 26 | 27 | extend type Product { 28 | sku: String! @external 29 | price: Int! @requires(fields: "sku") 30 | } 31 | `, 32 | name: "serviceB", 33 | }, 34 | ]), 35 | ).toEqual( 36 | expect.objectContaining({ 37 | errors: expect.arrayContaining([ 38 | expect.objectContaining({ 39 | message: expect.stringContaining( 40 | `[serviceA] On type "Product", for @key(fields: "featuredItem { id }"): field "Product.featuredItem" is a Interface type which is not allowed in @key`, 41 | ), 42 | extensions: expect.objectContaining({ 43 | code: "KEY_FIELDS_SELECT_INVALID_TYPE", 44 | }), 45 | }), 46 | ]), 47 | }), 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/KEY_INVALID_FIELDS_TYPE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { 3 | assertCompositionSuccess, 4 | graphql, 5 | testVersions, 6 | } from "../../shared/testkit.js"; 7 | 8 | testVersions((api, version) => { 9 | test("KEY_INVALID_FIELDS_TYPE", () => { 10 | expect( 11 | api.composeServices([ 12 | { 13 | name: "users", 14 | typeDefs: graphql` 15 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 16 | 17 | type Query { 18 | users: [User!]! 19 | } 20 | 21 | type User @key(fields: true) { 22 | id: ID 23 | } 24 | `, 25 | }, 26 | ]), 27 | ).toEqual( 28 | expect.objectContaining({ 29 | errors: expect.arrayContaining([ 30 | expect.objectContaining({ 31 | message: expect.stringContaining( 32 | `[users] On type "User", for @key(fields: true): Invalid value for argument "fields": must be a string.`, 33 | ), 34 | extensions: expect.objectContaining({ 35 | code: "KEY_INVALID_FIELDS_TYPE", 36 | }), 37 | }), 38 | ]), 39 | }), 40 | ); 41 | }); 42 | 43 | assertCompositionSuccess( 44 | api.composeServices([ 45 | { 46 | name: "a", 47 | typeDefs: graphql` 48 | type User @key(fields: ["id", "uuid"]) { 49 | id: ID! 50 | uuid: ID! 51 | name: String 52 | } 53 | 54 | type Query { 55 | users: [User] 56 | } 57 | `, 58 | }, 59 | ]), 60 | ); 61 | }); 62 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/KEY_UNSUPPORTED_ON_INTERFACE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { 3 | graphql, 4 | satisfiesVersionRange, 5 | testVersions, 6 | } from "../../shared/testkit.js"; 7 | 8 | testVersions((api, version) => { 9 | test("KEY_UNSUPPORTED_ON_INTERFACE", () => { 10 | expect( 11 | api.composeServices([ 12 | { 13 | name: "users", 14 | typeDefs: graphql` 15 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 16 | 17 | type Query { 18 | users: [User] 19 | } 20 | 21 | type RegisteredUser implements User @key(fields: "id") { 22 | id: ID! 23 | name: String! 24 | email: String 25 | } 26 | 27 | interface User @key(fields: "id") { 28 | id: ID! 29 | name: String! 30 | email: String 31 | } 32 | `, 33 | }, 34 | ]), 35 | ).toEqual( 36 | satisfiesVersionRange(">= v2.3", version) 37 | ? expect.objectContaining({ 38 | supergraphSdl: expect.any(String), 39 | }) 40 | : expect.objectContaining({ 41 | errors: expect.arrayContaining([ 42 | expect.objectContaining({ 43 | message: expect.stringContaining( 44 | `[users] Cannot use @key on interface "User": @key is not yet supported on interfaces`, 45 | ), 46 | extensions: expect.objectContaining({ 47 | code: "KEY_UNSUPPORTED_ON_INTERFACE", 48 | }), 49 | }), 50 | ]), 51 | }), 52 | ); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/OVERRIDE_FROM_SELF_ERROR.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("OVERRIDE_FROM_SELF_ERROR", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "billing", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key", "@override"] 15 | ) 16 | 17 | type Query { 18 | bills: [Bill] 19 | } 20 | 21 | type Bill @key(fields: "id") { 22 | id: ID! 23 | amount: Int! @override(from: "billing") 24 | } 25 | `, 26 | }, 27 | ]), 28 | ).toEqual( 29 | expect.objectContaining({ 30 | errors: expect.arrayContaining([ 31 | expect.objectContaining({ 32 | message: expect.stringContaining( 33 | `Source and destination subgraphs "billing" are the same for overridden field "Bill.amount"`, 34 | ), 35 | extensions: expect.objectContaining({ 36 | code: "OVERRIDE_FROM_SELF_ERROR", 37 | }), 38 | }), 39 | ]), 40 | }), 41 | ); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/OVERRIDE_ON_INTERFACE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { 3 | graphql, 4 | satisfiesVersionRange, 5 | testVersions, 6 | } from "../../shared/testkit.js"; 7 | 8 | testVersions((api, version) => { 9 | test("OVERRIDE_ON_INTERFACE", () => { 10 | expect( 11 | api.composeServices([ 12 | { 13 | name: "billing", 14 | typeDefs: graphql` 15 | extend schema 16 | @link( 17 | url: "https://specs.apollo.dev/federation/${version}" 18 | import: ["@key", "@override"] 19 | ) 20 | 21 | type Query { 22 | bills: [Bill] 23 | } 24 | 25 | interface Bill @key(fields: "id") { 26 | id: ID! 27 | amount: Int! @override(from: "billing") 28 | } 29 | `, 30 | }, 31 | ]), 32 | ).toEqual( 33 | expect.objectContaining({ 34 | errors: expect.arrayContaining([ 35 | satisfiesVersionRange(">= v2.3", version) 36 | ? expect.objectContaining({ 37 | message: expect.stringContaining( 38 | `@override cannot be used on field "Bill.amount" on subgraph "billing": @override is not supported on interface type fields.`, 39 | ), 40 | extensions: expect.objectContaining({ 41 | code: "OVERRIDE_ON_INTERFACE", 42 | }), 43 | }) 44 | : expect.objectContaining({ 45 | message: expect.stringContaining( 46 | '[billing] Cannot use @key on interface "Bill": @key is not yet supported on interfaces', 47 | ), 48 | extensions: expect.objectContaining({ 49 | code: "KEY_UNSUPPORTED_ON_INTERFACE", 50 | }), 51 | }), 52 | ]), 53 | }), 54 | ); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/PROVIDES_INVALID_FIELDS_TYPE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("PROVIDES_INVALID_FIELDS_TYPE - boolean", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "billing", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key", "@provides"] 15 | ) 16 | 17 | type Payment @key(fields: "id") { 18 | id: ID! 19 | amount: Int! 20 | } 21 | 22 | type Invoice @key(fields: "id") { 23 | id: ID! 24 | amount: Int! 25 | payment: Payment @provides(fields: true) 26 | } 27 | `, 28 | }, 29 | ]), 30 | ).toEqual( 31 | expect.objectContaining({ 32 | errors: expect.arrayContaining([ 33 | expect.objectContaining({ 34 | message: expect.stringContaining( 35 | `[billing] On field "Invoice.payment", for @provides(fields: true): Invalid value for argument "fields": must be a string.`, 36 | ), 37 | extensions: expect.objectContaining({ 38 | code: "PROVIDES_INVALID_FIELDS_TYPE", 39 | }), 40 | }), 41 | ]), 42 | }), 43 | ); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/PROVIDES_ON_NON_OBJECT_FIELD.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("PROVIDES_ON_NON_OBJECT_FIELD", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key", "@provides"] 15 | ) 16 | 17 | type Query { 18 | users: [User] 19 | } 20 | 21 | type RegisteredUser implements User @key(fields: "id") { 22 | id: ID! 23 | name: String! 24 | email: String 25 | } 26 | 27 | interface User @key(fields: "id") { 28 | id: ID! 29 | name: String! 30 | email: String @provides(fields: "name") 31 | } 32 | `, 33 | }, 34 | ]), 35 | ).toEqual( 36 | expect.objectContaining({ 37 | errors: expect.arrayContaining([ 38 | expect.objectContaining({ 39 | message: expect.stringContaining( 40 | `[users] Invalid @provides directive on field "User.email": field has type "String" which is not a Composite Type`, 41 | ), 42 | extensions: expect.objectContaining({ 43 | code: "PROVIDES_ON_NON_OBJECT_FIELD", 44 | }), 45 | }), 46 | ]), 47 | }), 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/PROVIDES_UNSUPPORTED_ON_INTERFACE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("PROVIDES_UNSUPPORTED_ON_INTERFACE", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key", "@provides"] 15 | ) 16 | 17 | type Query { 18 | users: [User] 19 | } 20 | 21 | type RegisteredUser implements User @key(fields: "id") { 22 | id: ID! 23 | name: String! 24 | profile: Profile 25 | } 26 | 27 | interface User @key(fields: "id") { 28 | id: ID! 29 | name: String! 30 | profile: Profile @provides(fields: "name") 31 | } 32 | 33 | type Profile { 34 | name: String 35 | } 36 | `, 37 | }, 38 | ]), 39 | ).toEqual( 40 | expect.objectContaining({ 41 | errors: expect.arrayContaining([ 42 | expect.objectContaining({ 43 | message: expect.stringContaining( 44 | `[users] Cannot use @provides on field "User.profile" of parent type "User": @provides is not yet supported within interfaces`, 45 | ), 46 | extensions: expect.objectContaining({ 47 | code: "PROVIDES_UNSUPPORTED_ON_INTERFACE", 48 | }), 49 | }), 50 | ]), 51 | }), 52 | ); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/REQUIRES_UNSUPPORTED_ON_INTERFACE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("REQUIRES_UNSUPPORTED_ON_INTERFACE", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema 12 | @link( 13 | url: "https://specs.apollo.dev/federation/${version}" 14 | import: ["@key", "@requires"] 15 | ) 16 | 17 | type Query { 18 | users: [User] 19 | } 20 | 21 | type RegisteredUser implements User @key(fields: "id") { 22 | id: ID! 23 | name: String! 24 | email: String 25 | } 26 | 27 | interface User @key(fields: "id") { 28 | id: ID! 29 | name: String! 30 | email: String @requires(fields: "name") 31 | } 32 | `, 33 | }, 34 | ]), 35 | ).toEqual( 36 | expect.objectContaining({ 37 | errors: expect.arrayContaining([ 38 | expect.objectContaining({ 39 | message: expect.stringContaining( 40 | `[users] Cannot use @requires on field "User.email" of parent type "User": @requires is not yet supported within interfaces`, 41 | ), 42 | extensions: expect.objectContaining({ 43 | code: "REQUIRES_UNSUPPORTED_ON_INTERFACE", 44 | }), 45 | }), 46 | ]), 47 | }), 48 | ); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/ROOT_MUTATION_USED.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("ROOT_MUTATION_USED", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | type Mutation { 14 | users: [User!]! 15 | } 16 | 17 | schema { 18 | mutation: RootMutation 19 | } 20 | 21 | type RootMutation { 22 | users: [User!]! 23 | } 24 | 25 | type User @key(fields: "id") { 26 | id: ID 27 | friends: [User!]! 28 | } 29 | `, 30 | }, 31 | ]), 32 | ).toEqual( 33 | expect.objectContaining({ 34 | errors: expect.arrayContaining([ 35 | expect.objectContaining({ 36 | message: expect.stringContaining( 37 | `The schema has a type named "Mutation" but it is not set as the mutation root type ("RootMutation" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name.`, 38 | ), 39 | extensions: expect.objectContaining({ 40 | code: "ROOT_MUTATION_USED", 41 | }), 42 | }), 43 | ]), 44 | }), 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/ROOT_QUERY_USED.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("ROOT_QUERY_USED", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | type Query { 14 | users: [User!]! 15 | } 16 | 17 | schema { 18 | query: RootQuery 19 | } 20 | 21 | type RootQuery { 22 | users: [User!]! 23 | } 24 | 25 | type User @key(fields: "id") { 26 | id: ID 27 | friends: [User!]! 28 | } 29 | `, 30 | }, 31 | ]), 32 | ).toEqual( 33 | expect.objectContaining({ 34 | errors: expect.arrayContaining([ 35 | expect.objectContaining({ 36 | message: expect.stringContaining( 37 | `The schema has a type named "Query" but it is not set as the query root type ("RootQuery" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name.`, 38 | ), 39 | extensions: expect.objectContaining({ 40 | code: "ROOT_QUERY_USED", 41 | }), 42 | }), 43 | ]), 44 | }), 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/ROOT_SUBSCRIPTION_USED.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("ROOT_SUBSCRIPTION_USED", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | type Subscription { 14 | users: [User!]! 15 | } 16 | 17 | schema { 18 | subscription: RootSubscription 19 | } 20 | 21 | type RootSubscription { 22 | users: [User!]! 23 | } 24 | 25 | type User @key(fields: "id") { 26 | id: ID 27 | friends: [User!]! 28 | } 29 | `, 30 | }, 31 | ]), 32 | ).toEqual( 33 | expect.objectContaining({ 34 | errors: expect.arrayContaining([ 35 | expect.objectContaining({ 36 | message: expect.stringContaining( 37 | `The schema has a type named "Subscription" but it is not set as the subscription root type ("RootSubscription" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name.`, 38 | ), 39 | extensions: expect.objectContaining({ 40 | code: "ROOT_SUBSCRIPTION_USED", 41 | }), 42 | }), 43 | ]), 44 | }), 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /__tests__/subgraph/errors/TYPE_DEFINITION_INVALID.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("TYPE_DEFINITION_INVALID", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema 12 | @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key", "FieldSet"]) 13 | 14 | directive @key( 15 | fields: FieldSet! 16 | resolvable: Boolean = true 17 | ) repeatable on OBJECT | INTERFACE 18 | 19 | input FieldSet { 20 | fields: [String!]! 21 | } 22 | 23 | type User @key(fields: "id name ") { 24 | id: ID! 25 | name: String 26 | } 27 | 28 | extend type Query { 29 | user(id: ID!): User 30 | } 31 | `, 32 | }, 33 | ]), 34 | ).toEqual( 35 | expect.objectContaining({ 36 | errors: expect.arrayContaining([ 37 | expect.objectContaining({ 38 | message: `[users] Invalid definition for type FieldSet: FieldSet should be a ScalarType but is defined as a InputObjectType`, 39 | extensions: expect.objectContaining({ 40 | code: "TYPE_DEFINITION_INVALID", 41 | }), 42 | }), 43 | ]), 44 | }), 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /__tests__/supergraph/errors/EMPTY_MERGED_ENUM_TYPE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("EMPTY_MERGED_ENUM_TYPE", () => { 6 | const result = api.composeServices([ 7 | { 8 | name: "a", 9 | typeDefs: graphql` 10 | extend schema 11 | @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@shareable"]) 12 | 13 | type User @shareable { 14 | name: String! 15 | } 16 | 17 | enum UserType { 18 | ADMIN 19 | UNREGULAR 20 | } 21 | `, 22 | }, 23 | { 24 | name: "b", 25 | typeDefs: graphql` 26 | extend schema 27 | @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@shareable"]) 28 | 29 | type User @shareable { 30 | name: String! 31 | } 32 | 33 | enum UserType { 34 | REGULAR 35 | ANONYMOUS 36 | } 37 | 38 | type Query { 39 | users(type: UserType): [User] 40 | } 41 | `, 42 | }, 43 | ]); 44 | 45 | expect(result).toEqual( 46 | expect.objectContaining({ 47 | errors: expect.arrayContaining([ 48 | expect.objectContaining({ 49 | message: `None of the values of enum type "UserType" are defined consistently in all the subgraphs defining that type. As only values common to all subgraphs are merged, this would result in an empty type.`, 50 | extensions: expect.objectContaining({ 51 | code: "EMPTY_MERGED_ENUM_TYPE", 52 | }), 53 | }), 54 | ]), 55 | }), 56 | ); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /__tests__/supergraph/errors/EMPTY_MERGED_INPUT_TYPE.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("EMPTY_MERGED_INPUT_TYPE", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "foo", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | input CreateUserInput { 14 | name: String 15 | email: String 16 | } 17 | 18 | type User @key(fields: "id") { 19 | id: ID! 20 | name: String! 21 | } 22 | 23 | type Query { 24 | users: [User] 25 | } 26 | `, 27 | }, 28 | { 29 | name: "bar", 30 | typeDefs: graphql` 31 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 32 | 33 | extend input CreateUserInput { 34 | tags: [String] 35 | } 36 | 37 | type Drink @key(fields: "id") { 38 | id: ID! 39 | name: String! 40 | } 41 | 42 | type Query { 43 | drinks: [Drink] 44 | } 45 | `, 46 | }, 47 | ]), 48 | ).toEqual( 49 | expect.objectContaining({ 50 | errors: expect.arrayContaining([ 51 | expect.objectContaining({ 52 | message: expect.stringContaining( 53 | `None of the fields of input object type "CreateUserInput" are consistently defined in all the subgraphs defining that type. As only fields common to all subgraphs are merged, this would result in an empty type.`, 54 | ), 55 | extensions: expect.objectContaining({ 56 | code: "EMPTY_MERGED_INPUT_TYPE", 57 | }), 58 | }), 59 | ]), 60 | }), 61 | ); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /__tests__/supergraph/errors/FIELD_ARGUMENT_TYPE_MISMATCH.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("FIELD_ARGUMENT_TYPE_MISMATCH", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | type Query { 14 | users(type: UserType!): [User!]! 15 | } 16 | 17 | type User @key(fields: "id") { 18 | id: ID 19 | type: UserType 20 | } 21 | 22 | enum UserType { 23 | REGULAR 24 | ADMIN 25 | } 26 | `, 27 | }, 28 | { 29 | name: "feed", 30 | typeDefs: graphql` 31 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 32 | 33 | extend type Query { 34 | users(type: String!): [User!]! 35 | } 36 | 37 | extend type User @key(fields: "id") { 38 | id: ID 39 | type: UserType 40 | } 41 | 42 | enum UserType { 43 | REGULAR 44 | ADMIN 45 | } 46 | `, 47 | }, 48 | ]), 49 | ).toEqual( 50 | expect.objectContaining({ 51 | errors: expect.arrayContaining([ 52 | expect.objectContaining({ 53 | message: expect.stringContaining( 54 | `Type of argument "Query.users(type:)" is incompatible across subgraphs: it has type "String!" in subgraph "feed" but type "UserType!" in subgraph "users"`, 55 | ), 56 | extensions: expect.objectContaining({ 57 | code: "FIELD_ARGUMENT_TYPE_MISMATCH", 58 | }), 59 | }), 60 | ]), 61 | }), 62 | ); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /__tests__/supergraph/errors/REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | type Query { 14 | user(id: Int!): User! 15 | } 16 | 17 | type User @key(fields: "id") { 18 | id: Int! 19 | } 20 | `, 21 | }, 22 | { 23 | name: "feed", 24 | typeDefs: graphql` 25 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key", "@external"]) 26 | 27 | type Query { 28 | user: User! 29 | } 30 | 31 | type User @key(fields: "id") { 32 | id: Int! @external 33 | } 34 | `, 35 | }, 36 | ]), 37 | ).toEqual( 38 | expect.objectContaining({ 39 | errors: expect.arrayContaining([ 40 | expect.objectContaining({ 41 | message: expect.stringContaining( 42 | `Argument "Query.user(id:)" is required in some subgraphs but does not appear in all subgraphs: it is required in subgraph "users" but does not appear in subgraph "feed"`, 43 | ), 44 | extensions: expect.objectContaining({ 45 | code: "REQUIRED_ARGUMENT_MISSING_IN_SOME_SUBGRAPH", 46 | }), 47 | }), 48 | ]), 49 | }), 50 | ); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /__tests__/supergraph/errors/TYPE_KIND_MISMATCH.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from "vitest"; 2 | import { graphql, testVersions } from "../../shared/testkit.js"; 3 | 4 | testVersions((api, version) => { 5 | test("TYPE_KIND_MISMATCH", () => { 6 | expect( 7 | api.composeServices([ 8 | { 9 | name: "users", 10 | typeDefs: graphql` 11 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 12 | 13 | type Query { 14 | usernames: [String!]! 15 | } 16 | 17 | type User { 18 | id: ID! 19 | } 20 | `, 21 | }, 22 | { 23 | name: "friends", 24 | typeDefs: graphql` 25 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 26 | 27 | extend interface User { 28 | id: ID! 29 | friends: [User!]! 30 | } 31 | `, 32 | }, 33 | { 34 | name: "pets", 35 | typeDefs: graphql` 36 | extend schema @link(url: "https://specs.apollo.dev/federation/${version}", import: ["@key"]) 37 | 38 | input Pet { 39 | name: String! 40 | } 41 | 42 | extend input User { 43 | id: ID! 44 | pets: [Pet!]! 45 | } 46 | `, 47 | }, 48 | ]), 49 | ).toEqual( 50 | expect.objectContaining({ 51 | errors: expect.arrayContaining([ 52 | expect.objectContaining({ 53 | message: expect.stringContaining( 54 | `Type "User" has mismatched kind: it is defined as Interface Type in subgraph "friends" but InputObject Type in subgraph "pets" and Object Type in subgraph "users"`, 55 | ), 56 | extensions: expect.objectContaining({ 57 | code: "TYPE_KIND_MISMATCH", 58 | }), 59 | }), 60 | ]), 61 | }), 62 | ); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /__tests__/supergraph/join.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "vitest"; 2 | import { 3 | assertCompositionSuccess, 4 | federationVersionToJoinSpecVersion, 5 | graphql, 6 | testImplementations, 7 | } from "../shared/testkit.js"; 8 | 9 | describe("join spec version", () => { 10 | testImplementations((api) => { 11 | test.each(Object.entries(federationVersionToJoinSpecVersion))( 12 | "Federation %s == Join %s", 13 | (fedVersion, joinVersion) => { 14 | const result = api.composeServices([ 15 | { 16 | name: "a", 17 | typeDefs: graphql` 18 | extend schema 19 | @link(url: "https://specs.apollo.dev/federation/${fedVersion}" import: ["@key"]) 20 | 21 | type User @key(fields: "id") { 22 | id: ID! 23 | name: String! 24 | } 25 | 26 | type Query { 27 | users: [User] 28 | } 29 | `, 30 | }, 31 | ]); 32 | 33 | assertCompositionSuccess(result); 34 | 35 | expect(result.supergraphSdl).toMatch( 36 | `@link(url: "https://specs.apollo.dev/join/${joinVersion}", for: EXECUTION)`, 37 | ); 38 | }, 39 | ); 40 | 41 | test("Federation v1.0 == Join v0.3", () => { 42 | const result = api.composeServices([ 43 | { 44 | name: "a", 45 | typeDefs: graphql` 46 | type User @key(fields: "id") { 47 | id: ID! 48 | name: String! 49 | } 50 | 51 | type Query { 52 | users: [User] 53 | } 54 | `, 55 | }, 56 | ]); 57 | 58 | assertCompositionSuccess(result); 59 | 60 | expect(result.supergraphSdl).toMatch( 61 | `@link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)`, 62 | ); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>the-guild-org/shared-config:renovate"] 4 | } 5 | -------------------------------------------------------------------------------- /src/graphql/contains-supergraph-spec.ts: -------------------------------------------------------------------------------- 1 | import { Kind } from "graphql"; 2 | import { 3 | extraFederationDirectiveNames, 4 | extraFederationTypeNames, 5 | getSupergraphSpecNodes, 6 | } from "./supergraph-spec.js"; 7 | 8 | let containsSupergraphSpecRegex: RegExp | null = null; 9 | 10 | export function containsSupergraphSpec(sdl: string): boolean { 11 | if (containsSupergraphSpecRegex !== null) { 12 | return containsSupergraphSpecRegex.test(sdl); 13 | } 14 | 15 | const patterns: string[] = []; 16 | 17 | for (const { name, kind } of getSupergraphSpecNodes()) { 18 | if (kind === Kind.DIRECTIVE) { 19 | // "@NAME" for directives 20 | patterns.push(`@${name}`); 21 | } else { 22 | // "[NAME" or " NAME" for scalars, enums and inputs 23 | patterns.push(`\\[${name}`, `\\s${name}`); 24 | } 25 | } 26 | 27 | extraFederationTypeNames.forEach((name) => { 28 | patterns.push(`\\[${name}`, `\\s${name}`); 29 | }); 30 | 31 | extraFederationDirectiveNames.forEach((name) => { 32 | patterns.push(`@${name}`); 33 | }); 34 | 35 | containsSupergraphSpecRegex = new RegExp(patterns.join("|")); 36 | 37 | return containsSupergraphSpecRegex.test(sdl); 38 | } 39 | -------------------------------------------------------------------------------- /src/graphql/helpers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DocumentNode, 3 | Kind, 4 | type DefinitionNode, 5 | type DirectiveDefinitionNode, 6 | } from "graphql"; 7 | 8 | export function isDirectiveDefinition( 9 | node: DefinitionNode, 10 | ): node is DirectiveDefinitionNode { 11 | return node.kind === Kind.DIRECTIVE_DEFINITION; 12 | } 13 | 14 | const kindOrderWeightMap: { 15 | [kind: string]: number; 16 | } = { 17 | [Kind.SCHEMA_DEFINITION]: 0, 18 | [Kind.SCHEMA_EXTENSION]: 1, 19 | [Kind.DIRECTIVE_DEFINITION]: 2, 20 | }; 21 | 22 | export function moveSchemaAndDirectiveDefinitionsToTop( 23 | ast: DocumentNode, 24 | ): DocumentNode { 25 | return { 26 | kind: Kind.DOCUMENT, 27 | definitions: ast.definitions.slice().sort((a, b) => { 28 | const aWeight = kindOrderWeightMap[a.kind] ?? 3; 29 | const bWeight = kindOrderWeightMap[b.kind] ?? 3; 30 | 31 | if (aWeight === bWeight) { 32 | return 0; 33 | } 34 | 35 | return aWeight < bWeight ? -1 : 1; 36 | }), 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./compose.js"; 2 | export * from "./types.js"; 3 | export * from "./validate.js"; 4 | export * from "./utils/link/index.js"; 5 | export { transformSupergraphToPublicSchema } from "./graphql/transform-supergraph-to-public-schema.js"; 6 | export { containsSupergraphSpec } from "./graphql/contains-supergraph-spec.js"; 7 | export { sortSDL } from "./graphql/sort-sdl.js"; 8 | -------------------------------------------------------------------------------- /src/specifications/authenticated.ts: -------------------------------------------------------------------------------- 1 | export const sdl = /* GraphQL */ ` 2 | directive @authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM 3 | `; 4 | -------------------------------------------------------------------------------- /src/specifications/cost.ts: -------------------------------------------------------------------------------- 1 | export const sdl = (names: { 2 | cost: string; 3 | listSize: string; 4 | }) => /* GraphQL */ ` 5 | directive @${names.cost}( 6 | weight: Int! 7 | ) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR 8 | 9 | directive @${names.listSize}( 10 | assumedSize: Int 11 | slicingArguments: [String!] 12 | sizedFields: [String!] 13 | requireOneSlicingArgument: Boolean = true 14 | ) on FIELD_DEFINITION 15 | `; 16 | -------------------------------------------------------------------------------- /src/specifications/inaccessible.ts: -------------------------------------------------------------------------------- 1 | import { parse } from "graphql"; 2 | import { isDirectiveDefinition } from "../graphql/helpers.js"; 3 | 4 | export const sdl = /* GraphQL */ ` 5 | directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ENUM | ENUM_VALUE | SCALAR | INPUT_OBJECT | INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION 6 | `; 7 | 8 | export const typeDefs = parse(sdl); 9 | export const directive = typeDefs.definitions.filter(isDirectiveDefinition)[0]; 10 | -------------------------------------------------------------------------------- /src/specifications/policy.ts: -------------------------------------------------------------------------------- 1 | export const sdl = /* GraphQL */ ` 2 | directive @policy( 3 | policies: [[policy__Policy!]!]! 4 | ) on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR 5 | 6 | scalar policy__Policy 7 | `; 8 | -------------------------------------------------------------------------------- /src/specifications/requires-scopes.ts: -------------------------------------------------------------------------------- 1 | export const sdl = /* GraphQL */ ` 2 | directive @requiresScopes( 3 | scopes: [[requiresScopes__Scope!]!]! 4 | ) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM 5 | 6 | scalar requiresScopes__Scope 7 | `; 8 | -------------------------------------------------------------------------------- /src/specifications/tag.ts: -------------------------------------------------------------------------------- 1 | import { parse } from "graphql"; 2 | import { isDirectiveDefinition } from "../graphql/helpers.js"; 3 | 4 | export const sdl = /* GraphQL */ ` 5 | directive @tag( 6 | name: String! 7 | ) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA 8 | `; 9 | 10 | export const typeDefs = parse(sdl); 11 | 12 | export const directive = typeDefs.definitions.filter(isDirectiveDefinition)[0]; 13 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/elements/context.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError } from "graphql"; 2 | import type { SubgraphValidationContext } from "../../validation-context.js"; 3 | 4 | export function ContextDirectiveRules( 5 | context: SubgraphValidationContext, 6 | ): ASTVisitor { 7 | if (context.satisfiesVersionRange(">= v2.8")) { 8 | if ( 9 | context.federationImports.some( 10 | (i) => i.name === "@context" && i.kind === "directive", 11 | ) 12 | ) { 13 | context.reportError( 14 | new GraphQLError("@context directive is not yet supported.", { 15 | extensions: { 16 | code: "UNSUPPORTED_FEATURE", 17 | }, 18 | }), 19 | ); 20 | } 21 | } 22 | 23 | return {}; 24 | } 25 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/elements/extends.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, Kind } from "graphql"; 2 | import { validateDirectiveAgainstOriginal } from "../../../helpers.js"; 3 | import type { SubgraphValidationContext } from "../../validation-context.js"; 4 | 5 | export function ExtendsRules(context: SubgraphValidationContext): ASTVisitor { 6 | return { 7 | DirectiveDefinition(node) { 8 | validateDirectiveAgainstOriginal(node, "extends", context); 9 | }, 10 | Directive(node) { 11 | if (!context.isAvailableFederationDirective("extends", node)) { 12 | return; 13 | } 14 | 15 | const typeDef = context.typeNodeInfo.getTypeDef(); 16 | 17 | if ( 18 | !typeDef || 19 | !( 20 | typeDef.kind === Kind.OBJECT_TYPE_DEFINITION || 21 | typeDef.kind === Kind.INTERFACE_TYPE_DEFINITION 22 | ) 23 | ) { 24 | return; // Let regular validation handle this, it should be applied on a field 25 | } 26 | 27 | if (typeDef.kind === Kind.OBJECT_TYPE_DEFINITION) { 28 | context.stateBuilder.objectType.setExtension( 29 | typeDef.name.value, 30 | "@extends", 31 | ); 32 | } else { 33 | context.stateBuilder.interfaceType.setExtension(typeDef.name.value); 34 | } 35 | 36 | const fields = typeDef.fields; 37 | 38 | for (const field of fields ?? []) { 39 | // TODO: T11 make sure it's actually correct to mark extended types as used 40 | context.markAsUsed( 41 | "@extends", 42 | typeDef.kind, 43 | typeDef.name.value, 44 | field.name.value, 45 | ); 46 | } 47 | }, 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/elements/field-set.ts: -------------------------------------------------------------------------------- 1 | import { ASTNode, ASTVisitor, GraphQLError } from "graphql"; 2 | import type { SubgraphValidationContext } from "../../validation-context.js"; 3 | 4 | export function FieldSetRules(context: SubgraphValidationContext): ASTVisitor { 5 | function validateFieldSet< 6 | T extends { 7 | name: { value: string }; 8 | } & ASTNode, 9 | >(node: T, receivedType: string) { 10 | if ( 11 | node.name.value === "FieldSet" && 12 | context.isAvailableFederationType("FieldSet") 13 | ) { 14 | context.reportError( 15 | new GraphQLError( 16 | `Invalid definition for type FieldSet: FieldSet should be a ScalarType but is defined as a ${receivedType}`, 17 | { 18 | nodes: node, 19 | extensions: { code: "TYPE_DEFINITION_INVALID" }, 20 | }, 21 | ), 22 | ); 23 | } 24 | } 25 | 26 | return { 27 | ScalarTypeDefinition(node) { 28 | if ( 29 | node.name.value === "FieldSet" && 30 | context.isAvailableFederationType("FieldSet") 31 | ) { 32 | context.markAsFederationDefinitionReplacement("FieldSet"); 33 | } 34 | }, 35 | ObjectTypeDefinition(node) { 36 | validateFieldSet(node, "ObjectType"); 37 | }, 38 | InterfaceTypeDefinition(node) { 39 | validateFieldSet(node, "InterfaceType"); 40 | }, 41 | UnionTypeDefinition(node) { 42 | validateFieldSet(node, "UnionType"); 43 | }, 44 | EnumTypeDefinition(node) { 45 | validateFieldSet(node, "EnumType"); 46 | }, 47 | InputObjectTypeDefinition(node) { 48 | validateFieldSet(node, "InputObjectType"); 49 | }, 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/elements/from-context.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError } from "graphql"; 2 | import type { SubgraphValidationContext } from "../../validation-context.js"; 3 | 4 | export function FromContextDirectiveRules( 5 | context: SubgraphValidationContext, 6 | ): ASTVisitor { 7 | if (context.satisfiesVersionRange(">= v2.8")) { 8 | if ( 9 | context.federationImports.some( 10 | (i) => i.name === "@fromContext" && i.kind === "directive", 11 | ) 12 | ) { 13 | context.reportError( 14 | new GraphQLError("@fromContext directive is not yet supported.", { 15 | extensions: { 16 | code: "UNSUPPORTED_FEATURE", 17 | }, 18 | }), 19 | ); 20 | } 21 | } 22 | 23 | return {}; 24 | } 25 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/elements/interface-object.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError, Kind } from "graphql"; 2 | import { validateDirectiveAgainstOriginal } from "../../../helpers.js"; 3 | import type { SubgraphValidationContext } from "../../validation-context.js"; 4 | 5 | export function InterfaceObjectRules( 6 | context: SubgraphValidationContext, 7 | ): ASTVisitor { 8 | return { 9 | DirectiveDefinition(node) { 10 | validateDirectiveAgainstOriginal(node, "interfaceObject", context); 11 | }, 12 | Directive(node) { 13 | if (!context.isAvailableFederationDirective("interfaceObject", node)) { 14 | return; 15 | } 16 | 17 | if (context.satisfiesVersionRange("< v2.3")) { 18 | context.reportError( 19 | new GraphQLError( 20 | `@interfaceObject is not yet supported. See https://github.com/graphql-hive/federation-composition/issues/7`, 21 | { 22 | extensions: { code: "UNSUPPORTED_FEATURE" }, 23 | }, 24 | ), 25 | ); 26 | return; 27 | } 28 | 29 | const typeDef = context.typeNodeInfo.getTypeDef(); 30 | 31 | if (!typeDef) { 32 | return; 33 | } 34 | 35 | if ( 36 | typeDef.kind !== Kind.OBJECT_TYPE_DEFINITION && 37 | typeDef.kind !== Kind.OBJECT_TYPE_EXTENSION 38 | ) { 39 | // handled by directive location validation 40 | return; 41 | } 42 | 43 | if (!typeDef.directives?.some((d) => d.name.value === "key")) { 44 | context.reportError( 45 | new GraphQLError( 46 | `The @interfaceObject directive can only be applied to entity types but type "${typeDef.name.value}" has no @key in this subgraph.`, 47 | { 48 | extensions: { code: "INTERFACE_OBJECT_USAGE_ERROR" }, 49 | }, 50 | ), 51 | ); 52 | } 53 | }, 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/known-argument-names-on-directives-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, DocumentNode, GraphQLError, Kind } from "graphql"; 2 | 3 | export function KnownArgumentNamesOnDirectivesRule(context: { 4 | reportError: (error: GraphQLError) => void; 5 | getDocument: () => DocumentNode; 6 | }): ASTVisitor { 7 | const directiveArgs = new Map>(); 8 | 9 | const astDefinitions = context.getDocument().definitions; 10 | for (const def of astDefinitions) { 11 | if (def.kind === Kind.DIRECTIVE_DEFINITION) { 12 | const argsNodes = def.arguments ?? []; 13 | 14 | directiveArgs.set( 15 | def.name.value, 16 | new Set(argsNodes.map((arg) => arg.name.value)), 17 | ); 18 | } 19 | } 20 | 21 | return { 22 | Directive(directiveNode) { 23 | const directiveName = directiveNode.name.value; 24 | const knownArgs = directiveArgs.get(directiveName); 25 | 26 | if (directiveNode.arguments && knownArgs) { 27 | for (const argNode of directiveNode.arguments) { 28 | const argName = argNode.name.value; 29 | if (!knownArgs.has(argName)) { 30 | context.reportError( 31 | new GraphQLError( 32 | `Unknown argument "${argName}" on directive "@${directiveName}".`, 33 | { 34 | nodes: argNode, 35 | extensions: { 36 | code: "INVALID_GRAPHQL", 37 | }, 38 | }, 39 | ), 40 | ); 41 | } 42 | } 43 | } 44 | }, 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/known-root-type-rule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTNode, 3 | ASTVisitor, 4 | GraphQLError, 5 | isTypeDefinitionNode, 6 | isTypeExtensionNode, 7 | TypeDefinitionNode, 8 | TypeExtensionNode, 9 | } from "graphql"; 10 | import type { SubgraphValidationContext } from "../validation-context.js"; 11 | 12 | export function KnownRootTypeRule( 13 | context: SubgraphValidationContext, 14 | ): ASTVisitor { 15 | const { definitions } = context.getDocument(); 16 | const typeNames = new Set( 17 | definitions 18 | .filter(isTypeDefinitionOrExtensionNode) 19 | .map((def) => def.name.value), 20 | ); 21 | 22 | return { 23 | SchemaDefinition(node) { 24 | node.operationTypes.forEach((operationType) => { 25 | if (!typeNames.has(operationType.type.name.value)) { 26 | context.reportError( 27 | new GraphQLError( 28 | `Cannot set schema ${operationType.operation} root to unknown type ${operationType.type.name.value}`, 29 | { 30 | extensions: { 31 | code: "INVALID_GRAPHQL", 32 | }, 33 | }, 34 | ), 35 | ); 36 | } 37 | }); 38 | }, 39 | }; 40 | } 41 | 42 | function isTypeDefinitionOrExtensionNode( 43 | node: ASTNode, 44 | ): node is TypeDefinitionNode | TypeExtensionNode { 45 | return isTypeDefinitionNode(node) || isTypeExtensionNode(node); 46 | } 47 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/known-type-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTNode, 3 | ASTVisitor, 4 | GraphQLError, 5 | isTypeDefinitionNode, 6 | isTypeExtensionNode, 7 | isTypeSystemDefinitionNode, 8 | isTypeSystemExtensionNode, 9 | specifiedScalarTypes, 10 | TypeDefinitionNode, 11 | TypeExtensionNode, 12 | } from "graphql"; 13 | import type { SubgraphValidationContext } from "../validation-context.js"; 14 | 15 | function isTypeDefinitionOrExtensionNode( 16 | node: ASTNode, 17 | ): node is TypeDefinitionNode | TypeExtensionNode { 18 | return isTypeDefinitionNode(node) || isTypeExtensionNode(node); 19 | } 20 | 21 | export function KnownTypeNamesRule( 22 | context: SubgraphValidationContext, 23 | ): ASTVisitor { 24 | const { definitions } = context.getDocument(); 25 | 26 | const typeNames = new Set( 27 | definitions 28 | .filter(isTypeDefinitionOrExtensionNode) 29 | .map((def) => def.name.value), 30 | ); 31 | 32 | return { 33 | NamedType(node, _1, parent, _2, ancestors) { 34 | const typeName = node.name.value; 35 | if (!typeNames.has(typeName)) { 36 | const definitionNode = ancestors[2] ?? parent; 37 | const isSDL = definitionNode != null && isSDLNode(definitionNode); 38 | if (isSDL && standardTypeNames.has(typeName)) { 39 | return; 40 | } 41 | 42 | context.reportError( 43 | new GraphQLError(`Unknown type ${typeName}`, { 44 | nodes: node, 45 | extensions: { 46 | code: "INVALID_GRAPHQL", 47 | }, 48 | }), 49 | ); 50 | } 51 | }, 52 | }; 53 | } 54 | 55 | const standardTypeNames = new Set( 56 | [...specifiedScalarTypes].map((type) => type.name), 57 | ); 58 | 59 | function isSDLNode(value: ASTNode | ReadonlyArray): boolean { 60 | return ( 61 | "kind" in value && 62 | (isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value)) 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/lone-schema-definition-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError } from "graphql"; 2 | 3 | export function LoneSchemaDefinitionRule(context: { 4 | reportError: (error: GraphQLError) => void; 5 | }): ASTVisitor { 6 | let schemaDefinitionsCount = 0; 7 | return { 8 | SchemaDefinition() { 9 | if (schemaDefinitionsCount > 0) { 10 | context.reportError( 11 | new GraphQLError("Must provide only one schema definition.", { 12 | extensions: { 13 | code: "INVALID_GRAPHQL", 14 | }, 15 | }), 16 | ); 17 | } 18 | ++schemaDefinitionsCount; 19 | }, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/query-root-type-inaccessible-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError, OperationTypeNode } from "graphql"; 2 | import type { SubgraphValidationContext } from "../validation-context.js"; 3 | 4 | export function QueryRootTypeInaccessibleRule( 5 | context: SubgraphValidationContext, 6 | ): ASTVisitor { 7 | let rootTypeName = "Query"; 8 | 9 | return { 10 | SchemaDefinition(node) { 11 | const nonQueryType = node.operationTypes?.find( 12 | (operationType) => 13 | operationType.operation === OperationTypeNode.QUERY && 14 | operationType.type.name.value !== "Query", 15 | ); 16 | 17 | if (nonQueryType) { 18 | rootTypeName = nonQueryType.type.name.value; 19 | } 20 | }, 21 | SchemaExtension(node) { 22 | const nonQueryType = node.operationTypes?.find( 23 | (operationType) => 24 | operationType.operation === OperationTypeNode.QUERY && 25 | operationType.type.name.value !== "Query", 26 | ); 27 | 28 | if (nonQueryType) { 29 | rootTypeName = nonQueryType.type.name.value; 30 | } 31 | }, 32 | ObjectTypeDefinition(node) { 33 | const name = node.name.value; 34 | 35 | if (name !== rootTypeName) { 36 | return; 37 | } 38 | 39 | if ( 40 | node.directives?.some((directive) => 41 | context.isAvailableFederationDirective("inaccessible", directive), 42 | ) 43 | ) { 44 | context.reportError( 45 | new GraphQLError( 46 | `Type "Query" is @inaccessible but is the root query type, which must be in the API schema.`, 47 | { 48 | nodes: node, 49 | extensions: { code: "QUERY_ROOT_TYPE_INACCESSIBLE" }, 50 | }, 51 | ), 52 | ); 53 | } 54 | }, 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/reserved-subgraph-name-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError } from "graphql"; 2 | import type { SubgraphValidationContext } from "../validation-context.js"; 3 | 4 | export function ReservedSubgraphNameRule( 5 | context: SubgraphValidationContext, 6 | ): ASTVisitor { 7 | if (context.getSubgraphName() === "_") { 8 | context.reportError( 9 | new GraphQLError(`Invalid name _ for a subgraph: this name is reserved`, { 10 | extensions: { 11 | code: "INVALID_SUBGRAPH_NAME", 12 | }, 13 | }), 14 | ); 15 | } 16 | 17 | return {}; 18 | } 19 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-argument-definition-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTVisitor, 3 | FieldDefinitionNode, 4 | GraphQLError, 5 | InputValueDefinitionNode, 6 | NameNode, 7 | } from "graphql"; 8 | 9 | export function UniqueArgumentDefinitionNamesRule(context: { 10 | reportError: (error: GraphQLError) => void; 11 | }): ASTVisitor { 12 | return { 13 | DirectiveDefinition(directiveNode) { 14 | const argumentNodes = directiveNode.arguments ?? []; 15 | 16 | return checkArgUniqueness(`@${directiveNode.name.value}`, argumentNodes); 17 | }, 18 | InterfaceTypeDefinition: checkArgUniquenessPerField, 19 | InterfaceTypeExtension: checkArgUniquenessPerField, 20 | ObjectTypeDefinition: checkArgUniquenessPerField, 21 | ObjectTypeExtension: checkArgUniquenessPerField, 22 | }; 23 | 24 | function checkArgUniquenessPerField(typeNode: { 25 | readonly name: NameNode; 26 | readonly fields?: ReadonlyArray | undefined; 27 | }) { 28 | const typeName = typeNode.name.value; 29 | const fieldNodes = typeNode.fields ?? []; 30 | 31 | for (const fieldDef of fieldNodes) { 32 | const fieldName = fieldDef.name.value; 33 | const argumentNodes = fieldDef.arguments ?? []; 34 | 35 | checkArgUniqueness(`${typeName}.${fieldName}`, argumentNodes); 36 | } 37 | 38 | return false; 39 | } 40 | 41 | function checkArgUniqueness( 42 | parentName: string, 43 | argumentNodes: ReadonlyArray, 44 | ) { 45 | const visitedArgumentNames = new Set(); 46 | 47 | for (const argDef of argumentNodes) { 48 | if (visitedArgumentNames.has(argDef.name.value)) { 49 | context.reportError( 50 | new GraphQLError( 51 | `Argument "${parentName}(${argDef.name.value}:)" can only be defined once.`, 52 | { 53 | extensions: { 54 | code: "INVALID_GRAPHQL", 55 | }, 56 | }, 57 | ), 58 | ); 59 | } else { 60 | visitedArgumentNames.add(argDef.name.value); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-argument-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { ArgumentNode, ASTVisitor, GraphQLError } from "graphql"; 2 | 3 | export function UniqueArgumentNamesRule(context: { 4 | reportError: (error: GraphQLError) => void; 5 | }): ASTVisitor { 6 | return { 7 | Field: checkArgUniqueness, 8 | Directive: checkArgUniqueness, 9 | }; 10 | 11 | function checkArgUniqueness(parentNode: { 12 | arguments?: ReadonlyArray | undefined; 13 | }) { 14 | const argumentNodes = parentNode.arguments ?? []; 15 | const seenArgs = new Set(); 16 | 17 | for (const argumentNode of argumentNodes) { 18 | if (seenArgs.has(argumentNode.name.value)) { 19 | context.reportError( 20 | new GraphQLError( 21 | `There can be only one argument named "${argumentNode.name.value}".`, 22 | { 23 | extensions: { 24 | code: "INVALID_GRAPHQL", 25 | }, 26 | }, 27 | ), 28 | ); 29 | } else { 30 | seenArgs.add(argumentNode.name.value); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-directive-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError } from "graphql"; 2 | 3 | export function UniqueDirectiveNamesRule(context: { 4 | reportError: (error: GraphQLError) => void; 5 | }): ASTVisitor { 6 | const knownDirectiveNameNodes = new Set(); 7 | 8 | return { 9 | DirectiveDefinition(node) { 10 | const directiveName = node.name.value; 11 | const existingNameNode = knownDirectiveNameNodes.has(directiveName); 12 | 13 | if (existingNameNode) { 14 | context.reportError( 15 | new GraphQLError( 16 | `There can be only one directive named "@${directiveName}".`, 17 | { 18 | extensions: { 19 | code: "INVALID_GRAPHQL", 20 | }, 21 | }, 22 | ), 23 | ); 24 | } else { 25 | knownDirectiveNameNodes.add(directiveName); 26 | } 27 | }, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-enum-value-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTVisitor, 3 | EnumTypeDefinitionNode, 4 | EnumTypeExtensionNode, 5 | GraphQLError, 6 | } from "graphql"; 7 | 8 | export function UniqueEnumValueNamesRule(context: { 9 | reportError: (error: GraphQLError) => void; 10 | }): ASTVisitor { 11 | const knownValueNames = new Map>(); 12 | 13 | return { 14 | EnumTypeDefinition: checkValueUniqueness, 15 | EnumTypeExtension: checkValueUniqueness, 16 | }; 17 | 18 | function checkValueUniqueness( 19 | node: EnumTypeDefinitionNode | EnumTypeExtensionNode, 20 | ) { 21 | const typeName = node.name.value; 22 | 23 | if (!knownValueNames.has(typeName)) { 24 | knownValueNames.set(typeName, new Set()); 25 | } 26 | 27 | const valueNodes = node.values ?? []; 28 | const valueNames = knownValueNames.get(typeName)!; 29 | 30 | for (const valueDef of valueNodes) { 31 | const valueName = valueDef.name.value; 32 | 33 | if (valueNames.has(valueName)) { 34 | context.reportError( 35 | new GraphQLError( 36 | `Enum value "${typeName}.${valueName}" can only be defined once.`, 37 | { 38 | extensions: { 39 | code: "INVALID_GRAPHQL", 40 | }, 41 | }, 42 | ), 43 | ); 44 | } else { 45 | valueNames.add(valueName); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-field-definition-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTVisitor, 3 | FieldDefinitionNode, 4 | GraphQLError, 5 | InputValueDefinitionNode, 6 | NameNode, 7 | } from "graphql"; 8 | 9 | export function UniqueFieldDefinitionNamesRule(context: { 10 | reportError: (error: GraphQLError) => void; 11 | }): ASTVisitor { 12 | const knownFieldNames = new Map>(); 13 | 14 | return { 15 | InputObjectTypeDefinition: checkFieldUniqueness, 16 | InputObjectTypeExtension: checkFieldUniqueness, 17 | InterfaceTypeDefinition: checkFieldUniqueness, 18 | InterfaceTypeExtension: checkFieldUniqueness, 19 | ObjectTypeDefinition: checkFieldUniqueness, 20 | ObjectTypeExtension: checkFieldUniqueness, 21 | }; 22 | 23 | function checkFieldUniqueness(node: { 24 | readonly name: NameNode; 25 | readonly fields?: 26 | | ReadonlyArray 27 | | undefined; 28 | }) { 29 | const typeName = node.name.value; 30 | 31 | if (!knownFieldNames.has(typeName)) { 32 | knownFieldNames.set(typeName, new Set()); 33 | } 34 | 35 | const fieldNodes = node.fields ?? []; 36 | const fieldNames = knownFieldNames.get(typeName)!; 37 | 38 | for (const fieldDef of fieldNodes) { 39 | const fieldName = fieldDef.name.value; 40 | 41 | if (fieldNames.has(fieldName)) { 42 | context.reportError( 43 | new GraphQLError( 44 | `Field "${typeName}.${fieldName}" can only be defined once.`, 45 | { 46 | extensions: { 47 | code: "INVALID_GRAPHQL", 48 | }, 49 | }, 50 | ), 51 | ); 52 | } else { 53 | fieldNames.add(fieldName); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-input-field-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError } from "graphql"; 2 | 3 | export function UniqueInputFieldNamesRule(context: { 4 | reportError: (error: GraphQLError) => void; 5 | }): ASTVisitor { 6 | const knownNameStack: Array> = []; 7 | let knownNames = new Set(); 8 | 9 | return { 10 | ObjectValue: { 11 | enter() { 12 | knownNameStack.push(knownNames); 13 | knownNames = new Set(); 14 | }, 15 | leave() { 16 | const prevKnownNames = knownNameStack.pop(); 17 | 18 | if (!prevKnownNames) { 19 | throw new Error("Assertion failed: nothing else in the stack"); 20 | } 21 | 22 | knownNames = prevKnownNames; 23 | }, 24 | }, 25 | ObjectField(node) { 26 | const fieldName = node.name.value; 27 | if (knownNames.has(fieldName)) { 28 | context.reportError( 29 | new GraphQLError( 30 | `There can be only one input field named "${fieldName}".`, 31 | { 32 | extensions: { 33 | code: "INVALID_GRAPHQL", 34 | }, 35 | }, 36 | ), 37 | ); 38 | } else { 39 | knownNames.add(fieldName); 40 | } 41 | }, 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-operation-types-rule.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ASTVisitor, 3 | GraphQLError, 4 | OperationTypeNode, 5 | SchemaDefinitionNode, 6 | SchemaExtensionNode, 7 | } from "graphql"; 8 | 9 | export function UniqueOperationTypesRule(context: { 10 | reportError: (error: GraphQLError) => void; 11 | }): ASTVisitor { 12 | const definedOperationTypes = new Set(); 13 | 14 | return { 15 | SchemaDefinition: checkOperationTypes, 16 | SchemaExtension: checkOperationTypes, 17 | }; 18 | 19 | function checkOperationTypes( 20 | node: SchemaDefinitionNode | SchemaExtensionNode, 21 | ) { 22 | const operationTypesNodes = node.operationTypes || []; 23 | 24 | for (const operationType of operationTypesNodes) { 25 | const operation = operationType.operation; 26 | const alreadyDefinedOperationType = definedOperationTypes.has(operation); 27 | 28 | if (alreadyDefinedOperationType) { 29 | context.reportError( 30 | new GraphQLError( 31 | `There can be only one ${operation} type in schema.`, 32 | { 33 | extensions: { 34 | code: "INVALID_GRAPHQL", 35 | }, 36 | }, 37 | ), 38 | ); 39 | } else { 40 | definedOperationTypes.add(operation); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/subgraph/validation/rules/unique-type-names-rule.ts: -------------------------------------------------------------------------------- 1 | import { ASTVisitor, GraphQLError, TypeDefinitionNode } from "graphql"; 2 | 3 | export function UniqueTypeNamesRule(context: { 4 | reportError: (error: GraphQLError) => void; 5 | }): ASTVisitor { 6 | const knownTypeNames = new Set(); 7 | 8 | return { 9 | ScalarTypeDefinition: checkTypeName, 10 | ObjectTypeDefinition: checkTypeName, 11 | InterfaceTypeDefinition: checkTypeName, 12 | UnionTypeDefinition: checkTypeName, 13 | EnumTypeDefinition: checkTypeName, 14 | InputObjectTypeDefinition: checkTypeName, 15 | }; 16 | 17 | function checkTypeName(node: TypeDefinitionNode) { 18 | const typeName = node.name.value; 19 | 20 | if (knownTypeNames.has(typeName)) { 21 | context.reportError( 22 | new GraphQLError(`There can be only one type named "${typeName}".`, { 23 | extensions: { 24 | code: "INVALID_GRAPHQL", 25 | }, 26 | }), 27 | ); 28 | } else { 29 | knownTypeNames.add(typeName); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/supergraph/composition/common.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ConstDirectiveNode, 3 | DirectiveDefinitionNode, 4 | DirectiveNode, 5 | TypeDefinitionNode, 6 | } from "graphql"; 7 | import type { FederationVersion } from "../../specifications/federation.js"; 8 | import { SubgraphState } from "../../subgraph/state.js"; 9 | import type { SupergraphState } from "../state.js"; 10 | 11 | export type MapByGraph = Map; 12 | 13 | export interface Key { 14 | fields: string; 15 | resolvable: boolean; 16 | } 17 | 18 | export interface Graph { 19 | name: string; 20 | id: string; 21 | version: FederationVersion; 22 | url?: string; 23 | } 24 | 25 | export interface TypeBuilder { 26 | visitSubgraphState( 27 | graph: Graph, 28 | state: Map, 29 | typeName: string, 30 | type: T, 31 | ): void; 32 | composeSupergraphNode( 33 | type: S, 34 | graphMap: Map, 35 | helpers: { 36 | graphNameToId(graphName: string): string | null; 37 | supergraphState: SupergraphState; 38 | }, 39 | ): TypeDefinitionNode | DirectiveDefinitionNode; 40 | } 41 | 42 | export function convertToConst(nodes: DirectiveNode[]): ConstDirectiveNode[] { 43 | return nodes as ConstDirectiveNode[]; 44 | } 45 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/field-argument-default-mismatch-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function FieldArgumentDefaultMismatchRule( 6 | context: SupergraphValidationContext, 7 | ): SupergraphVisitorMap { 8 | return { 9 | ObjectTypeFieldArg(objectState, fieldState, argState) { 10 | if (typeof argState.defaultValue !== "string") { 11 | return; 12 | } 13 | 14 | const defaultValueToGraphs = new Map(); 15 | 16 | argState.byGraph.forEach((arg, graphName) => { 17 | if (typeof arg.defaultValue === "string") { 18 | const existing = defaultValueToGraphs.get(arg.defaultValue); 19 | 20 | if (existing) { 21 | existing.push(graphName); 22 | } else { 23 | defaultValueToGraphs.set(arg.defaultValue, [graphName]); 24 | } 25 | } 26 | }); 27 | 28 | if (defaultValueToGraphs.size > 1) { 29 | const groups = Array.from(defaultValueToGraphs.entries()).map( 30 | ([defaultValue, graphs]) => { 31 | const plural = graphs.length > 1 ? "s" : ""; 32 | return `default value ${defaultValue} in subgraph${plural} "${graphs 33 | .map(context.graphIdToName) 34 | .join('", "')}"`; 35 | }, 36 | ); 37 | const [first, second, ...rest] = groups; 38 | context.reportError( 39 | new GraphQLError( 40 | `Argument "${objectState.name}.${fieldState.name}(${ 41 | argState.name 42 | }:)" has incompatible default values across subgraphs: it has ${first} but ${second}${ 43 | rest.length ? ` and ${rest.join(" and ")}` : "" 44 | }`, 45 | { 46 | extensions: { 47 | code: "FIELD_ARGUMENT_DEFAULT_MISMATCH", 48 | }, 49 | }, 50 | ), 51 | ); 52 | } 53 | }, 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/input-field-default-mismatch-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function InputFieldDefaultMismatchRule( 6 | context: SupergraphValidationContext, 7 | ): SupergraphVisitorMap { 8 | return { 9 | InputObjectTypeField(inputObjectState, fieldState) { 10 | if (typeof fieldState.defaultValue !== "string") { 11 | return; 12 | } 13 | 14 | const defaultValueToGraphs = new Map(); 15 | 16 | fieldState.byGraph.forEach((field, graphName) => { 17 | if (typeof field.defaultValue === "string") { 18 | const existing = defaultValueToGraphs.get(field.defaultValue); 19 | 20 | if (existing) { 21 | existing.push(graphName); 22 | } else { 23 | defaultValueToGraphs.set(field.defaultValue, [graphName]); 24 | } 25 | } 26 | }); 27 | 28 | if (defaultValueToGraphs.size > 1) { 29 | const groups = Array.from(defaultValueToGraphs.entries()).map( 30 | ([defaultValue, graphs]) => { 31 | const plural = graphs.length > 1 ? "s" : ""; 32 | return `default value ${defaultValue} in subgraph${plural} "${graphs 33 | .map(context.graphIdToName) 34 | .join('", "')}"`; 35 | }, 36 | ); 37 | const [first, second, ...rest] = groups; 38 | context.reportError( 39 | new GraphQLError( 40 | `Input field "${inputObjectState.name}.${ 41 | fieldState.name 42 | }" has incompatible default values across subgraphs: it has ${first} but ${second}${ 43 | rest.length ? ` and ${rest.join(" and ")}` : "" 44 | }`, 45 | { 46 | extensions: { 47 | code: "INPUT_FIELD_DEFAULT_MISMATCH", 48 | }, 49 | }, 50 | ), 51 | ); 52 | } 53 | }, 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/input-object-values-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function InputObjectValuesRule( 6 | context: SupergraphValidationContext, 7 | ): SupergraphVisitorMap { 8 | return { 9 | InputObjectType(inputObjectTypeState) { 10 | const fieldsInCommon: string[] = []; 11 | const total = inputObjectTypeState.byGraph.size; 12 | for (const [fieldName, fieldState] of inputObjectTypeState.fields) { 13 | // If it's not used in all the subgraphs, it's missing in some of them 14 | if (fieldState.byGraph.size === total) { 15 | fieldsInCommon.push(fieldName); 16 | } 17 | } 18 | if (fieldsInCommon.length === 0) { 19 | context.reportError( 20 | new GraphQLError( 21 | `None of the fields of input object type "${inputObjectTypeState.name}" are consistently defined in all the subgraphs defining that type. As only fields common to all subgraphs are merged, this would result in an empty type.`, 22 | { 23 | extensions: { 24 | code: "EMPTY_MERGED_INPUT_TYPE", 25 | }, 26 | }, 27 | ), 28 | ); 29 | } 30 | }, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/interface-object-usage-error.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function InterfaceObjectUsageErrorRule( 6 | context: SupergraphValidationContext, 7 | ): SupergraphVisitorMap { 8 | return { 9 | InterfaceType(interfaceState) { 10 | if (!interfaceState.hasInterfaceObject) { 11 | return; 12 | } 13 | 14 | for (const [_, interfaceStateInGraph] of interfaceState.byGraph) { 15 | if (!interfaceStateInGraph.isInterfaceObject) { 16 | return; 17 | } 18 | } 19 | 20 | context.reportError( 21 | new GraphQLError( 22 | `Type "${interfaceState.name}" is declared with @interfaceObject in all the subgraphs in which is is defined`, 23 | { 24 | extensions: { 25 | code: "INTERFACE_OBJECT_USAGE_ERROR", 26 | }, 27 | }, 28 | ), 29 | ); 30 | }, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/link-import-name-mismatch-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { andList } from "../../../utils/format.js"; 3 | import type { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function LinkImportNameMismatchRule( 6 | context: SupergraphValidationContext, 7 | ) { 8 | // "": { "": [""] } 9 | const namesToSubgraphs = new Map>(); 10 | 11 | const namesToCheck = ["@cost", "@listSize"]; 12 | 13 | for (const [subgraphId, subgraphState] of context.subgraphStates) { 14 | for (const imp of subgraphState.federation.imports) { 15 | if (!namesToCheck.includes(imp.name)) { 16 | continue; 17 | } 18 | 19 | let existing = namesToSubgraphs.get(imp.name); 20 | 21 | if (!existing) { 22 | namesToSubgraphs.set(imp.name, new Map()); 23 | existing = namesToSubgraphs.get(imp.name)!; 24 | } 25 | 26 | const name = imp.alias ?? imp.name; 27 | let existingName = existing.get(name); 28 | 29 | if (!Array.isArray(existingName)) { 30 | existing.set(name, []); 31 | existingName = existing.get(name)!; 32 | } 33 | 34 | existingName.push(subgraphId); 35 | } 36 | } 37 | 38 | for (const [originalName, aliases] of namesToSubgraphs) { 39 | if (aliases.size <= 1) { 40 | continue; 41 | } 42 | 43 | context.reportError( 44 | new GraphQLError( 45 | `The import name "${originalName}" is imported with mismatched name between subgraphs: it is imported as ` + 46 | andList( 47 | Array.from(aliases).map( 48 | ([name, subgraphIds]) => 49 | ` "${name}" in subgraph${subgraphIds.length > 1 ? "s" : ""} ${andList(subgraphIds.map(context.graphIdToName), false, '"')}`, 50 | ), 51 | ), 52 | { 53 | extensions: { 54 | code: "LINK_IMPORT_NAME_MISMATCH", 55 | }, 56 | }, 57 | ), 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/no-inaccessible-on-implemented-interface-fields-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphState } from "../../state.js"; 4 | import type { SupergraphValidationContext } from "../validation-context.js"; 5 | 6 | /** 7 | * Fail on `@inaccessible` on object type fields if the corresponding interface field does not have `@inaccessible` applied. 8 | */ 9 | export function NoInaccessibleOnImplementedInterfaceFieldsRule( 10 | context: SupergraphValidationContext, 11 | supergraphState: SupergraphState, 12 | ): SupergraphVisitorMap { 13 | return { 14 | ObjectTypeField(objectTypeState, fieldState) { 15 | if (fieldState.inaccessible && objectTypeState.interfaces.size) { 16 | for (const interfaceName of objectTypeState.interfaces) { 17 | const interfaceType = 18 | supergraphState.interfaceTypes.get(interfaceName); 19 | if (!interfaceType) { 20 | continue; 21 | } 22 | const interfaceField = interfaceType.fields.get(fieldState.name); 23 | if (!interfaceField) { 24 | continue; 25 | } 26 | 27 | if (interfaceField.inaccessible === false) { 28 | const objectTypeFieldSchemaCoordinate = 29 | objectTypeState.name + "." + fieldState.name; 30 | const interfaceFieldSchemaCoordinate = 31 | interfaceName + "." + fieldState.name; 32 | context.reportError( 33 | new GraphQLError( 34 | `Field "${objectTypeFieldSchemaCoordinate}" is @inaccessible but implements the interface field "${interfaceFieldSchemaCoordinate}", which is in the API schema.`, 35 | { 36 | extensions: { 37 | code: "IMPLEMENTED_BY_INACCESSIBLE", 38 | }, 39 | }, 40 | ), 41 | ); 42 | } 43 | } 44 | } 45 | }, 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/required-argument-or-field-is-not-inaccessible-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function RequiredArgumentOrFieldIsNotInaccessibleRule( 6 | context: SupergraphValidationContext, 7 | ): SupergraphVisitorMap { 8 | return { 9 | InputObjectTypeField(inputObjectState, fieldState) { 10 | if ( 11 | !inputObjectState.inaccessible && 12 | fieldState.inaccessible && 13 | fieldState.type.endsWith("!") 14 | ) { 15 | context.reportError( 16 | new GraphQLError( 17 | `Input field "${inputObjectState.name}.${fieldState.name}" is @inaccessible but is a required input field of its type.`, 18 | { 19 | extensions: { 20 | code: "REQUIRED_INACCESSIBLE", 21 | }, 22 | }, 23 | ), 24 | ); 25 | } 26 | }, 27 | ObjectTypeFieldArg(objectState, fieldState, argState) { 28 | if ( 29 | !fieldState.inaccessible && 30 | argState.inaccessible && 31 | argState.type.endsWith("!") 32 | ) { 33 | context.reportError( 34 | new GraphQLError( 35 | `Argument "${objectState.name}.${fieldState.name}(${argState.name}:)" is @inaccessible but is a required argument of its field.`, 36 | { 37 | extensions: { 38 | code: "REQUIRED_INACCESSIBLE", 39 | }, 40 | }, 41 | ), 42 | ); 43 | } 44 | }, 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/required-input-field-missing-in-some-subgraph-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphVisitorMap } from "../../composition/visitor.js"; 3 | import { SupergraphValidationContext } from "../validation-context.js"; 4 | 5 | export function RequiredInputFieldMissingInSomeSubgraphRule( 6 | context: SupergraphValidationContext, 7 | ): SupergraphVisitorMap { 8 | return { 9 | InputObjectTypeField(inputObjectState, fieldState) { 10 | if (fieldState.type.endsWith("!")) { 11 | // if the input object is defined in a single graph, this rule can be ignored 12 | if (inputObjectState.byGraph.size === 1) { 13 | return; 14 | } 15 | 16 | // if the field is defined in all graphs, this rule can be ignored 17 | if (inputObjectState.byGraph.size === fieldState.byGraph.size) { 18 | return; 19 | } 20 | 21 | const graphsWithRequiredField = Array.from(fieldState.byGraph) 22 | .filter(([_, field]) => field.type.endsWith("!")) 23 | .map(([graph]) => graph); 24 | const graphsWithoutField = Array.from( 25 | inputObjectState.byGraph.keys(), 26 | ).filter((graph) => !fieldState.byGraph.has(graph)); 27 | const requiredIn = `subgraph${ 28 | graphsWithRequiredField.length > 1 ? "s" : "" 29 | } "${graphsWithRequiredField.map(context.graphIdToName).join('", "')}"`; 30 | const missingIn = `subgraph${graphsWithoutField.length > 1 ? "s" : ""} "${graphsWithoutField 31 | .map(context.graphIdToName) 32 | .join('", "')}"`; 33 | context.reportError( 34 | new GraphQLError( 35 | `Input object field "${inputObjectState.name}.${fieldState.name}" is required in some subgraphs but does not appear in all subgraphs: it is required in ${requiredIn} but does not appear in ${missingIn}`, 36 | { 37 | extensions: { 38 | code: "REQUIRED_INPUT_FIELD_MISSING_IN_SOME_SUBGRAPH", 39 | }, 40 | }, 41 | ), 42 | ); 43 | } 44 | }, 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/required-query-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphValidationContext } from "../validation-context.js"; 3 | 4 | export function RequiredQueryRule(context: SupergraphValidationContext) { 5 | if ( 6 | Array.from(context.subgraphStates.values()).every( 7 | (subgraph) => typeof subgraph.schema.queryType === "undefined", 8 | ) 9 | ) { 10 | context.reportError( 11 | new GraphQLError( 12 | `No queries found in any subgraph: a supergraph must have a query root type.`, 13 | { 14 | extensions: { 15 | code: "NO_QUERIES", 16 | }, 17 | }, 18 | ), 19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/satisfiablity/constants.ts: -------------------------------------------------------------------------------- 1 | export const SUPERGRAPH_ID = Symbol("__supergraph__"); 2 | export const MERGEDGRAPH_ID = Symbol("__mergedgraph__"); 3 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/satisfiablity/helpers.ts: -------------------------------------------------------------------------------- 1 | export function occurrences(str: string, subString: string) { 2 | if (subString.length <= 0) { 3 | return str.length + 1; 4 | } 5 | 6 | let n = 0, 7 | pos = 0, 8 | step = subString.length; 9 | 10 | while (true) { 11 | pos = str.indexOf(subString, pos); 12 | if (pos >= 0) { 13 | ++n; 14 | pos += step; 15 | } else break; 16 | } 17 | return n; 18 | } 19 | 20 | export function scoreKeyFields(keyFields: string) { 21 | const fields = occurrences(keyFields, " ") + 1; 22 | const innerSelectionSets = occurrences(keyFields, "{") * 3; 23 | 24 | return fields + innerSelectionSets; 25 | } 26 | 27 | export type Lazy = { 28 | get(): T; 29 | invalidate(): void; 30 | }; 31 | 32 | export function lazy(factory: () => T) { 33 | let value: T | undefined; 34 | 35 | return { 36 | get() { 37 | if (value === undefined) { 38 | value = factory(); 39 | } 40 | 41 | return value; 42 | }, 43 | invalidate() { 44 | value = undefined; 45 | }, 46 | }; 47 | } 48 | 49 | export class OverrideLabels { 50 | private state: Record; 51 | 52 | constructor(state?: Record) { 53 | this.state = state ?? {}; 54 | } 55 | 56 | set(key: string, value: boolean) { 57 | this.state[key] = value; 58 | return this; 59 | } 60 | 61 | get(key: string) { 62 | return this.state[key]; 63 | } 64 | 65 | matches(other: OverrideLabels) { 66 | for (const key in this.state) { 67 | if (this.state[key] !== other.state[key]) { 68 | return false; 69 | } 70 | } 71 | 72 | return true; 73 | } 74 | 75 | clone() { 76 | return new OverrideLabels({ 77 | ...this.state, 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/supergraph/validation/rules/subgraph-name-rule.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import { SupergraphValidationContext } from "../validation-context.js"; 3 | 4 | export function SubgraphNameRule(context: SupergraphValidationContext) { 5 | for (const [_, subgraph] of context.subgraphStates) { 6 | const id = subgraph.graph.id; 7 | if (id.startsWith("__")) { 8 | context.reportError( 9 | new GraphQLError( 10 | `Name "${id}" must not begin with "__", which is reserved by GraphQL introspection.`, 11 | { 12 | extensions: { 13 | code: "INVALID_GRAPHQL", 14 | }, 15 | }, 16 | ), 17 | ); 18 | } 19 | } 20 | 21 | return {}; 22 | } 23 | -------------------------------------------------------------------------------- /src/supergraph/validation/validation-context.ts: -------------------------------------------------------------------------------- 1 | import { GraphQLError } from "graphql"; 2 | import type { SubgraphState } from "../../subgraph/state.js"; 3 | 4 | export type SupergraphValidationContext = ReturnType< 5 | typeof createSupergraphValidationContext 6 | >; 7 | 8 | export function createSupergraphValidationContext( 9 | subgraphStates: Map, 10 | ) { 11 | let reportedErrors: GraphQLError[] = []; 12 | 13 | const subgraphNameToIdMap: Record = {}; 14 | 15 | for (const [id, state] of subgraphStates) { 16 | subgraphNameToIdMap[state.graph.name] = id; 17 | } 18 | 19 | return { 20 | subgraphStates, 21 | graphIdToName(id: string) { 22 | const found = subgraphStates.get(id); 23 | 24 | if (!found) { 25 | throw new Error(`Could not find subgraph with id ${id}`); 26 | } 27 | 28 | return found.graph.name; 29 | }, 30 | graphNameToId(name: string) { 31 | const found = subgraphNameToIdMap[name]; 32 | 33 | return found ?? null; 34 | }, 35 | reportError(error: GraphQLError) { 36 | reportedErrors.push(error); 37 | }, 38 | collectReportedErrors() { 39 | const errors = reportedErrors; 40 | 41 | reportedErrors = []; 42 | 43 | return errors; 44 | }, 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { DocumentNode } from "graphql"; 2 | 3 | export interface ServiceDefinition { 4 | typeDefs: DocumentNode; 5 | name: string; 6 | url?: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/format.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Given [ A, B, C ] return 3 | * commaBeforeConjunction: true -> 'A, B, and C'. 4 | * commaBeforeConjunction: false -> 'A, B and C'. 5 | */ 6 | export function andList( 7 | items: readonly string[], 8 | commaBeforeConjunction = true, 9 | wrapper?: string, 10 | ): string { 11 | return formatList("and", items, commaBeforeConjunction, wrapper); 12 | } 13 | 14 | function formatList( 15 | conjunction: string, 16 | items: readonly string[], 17 | commaBeforeConjunction = true, 18 | wrapper?: string, 19 | ): string { 20 | if (items.length === 0) { 21 | return ""; 22 | } 23 | 24 | switch (items.length) { 25 | case 1: 26 | return withWrapper(items[0], wrapper); 27 | case 2: 28 | return ( 29 | withWrapper(items[0], wrapper) + 30 | " " + 31 | conjunction + 32 | " " + 33 | withWrapper(items[1], wrapper) 34 | ); 35 | } 36 | 37 | const allButLast = items 38 | .slice(0, -1) 39 | .map((item) => withWrapper(item, wrapper)); 40 | const lastItem = withWrapper(items.at(-1)!, wrapper); 41 | return ( 42 | allButLast.join(", ") + 43 | (commaBeforeConjunction ? ", " : " ") + 44 | conjunction + 45 | " " + 46 | lastItem 47 | ); 48 | } 49 | 50 | function withWrapper(text: string, wrapper?: string): string { 51 | if (!wrapper) { 52 | return text; 53 | } 54 | 55 | return wrapper + text + wrapper; 56 | } 57 | -------------------------------------------------------------------------------- /src/utils/helpers.ts: -------------------------------------------------------------------------------- 1 | export function isDefined(value: T | undefined | null): value is T { 2 | return value !== undefined && value !== null; 3 | } 4 | 5 | export function ensureValue( 6 | value: T | undefined | null, 7 | message: string, 8 | ): T { 9 | if (isDefined(value)) { 10 | return value; 11 | } 12 | 13 | throw new Error(message); 14 | } 15 | 16 | export function mathMax(firstValue: number, secondValue: null | number) { 17 | if (secondValue === null) { 18 | return firstValue; 19 | } 20 | 21 | return Math.max(firstValue, secondValue); 22 | } 23 | 24 | export function mathMaxNullable( 25 | left: number | null | undefined, 26 | right: number | null | undefined, 27 | ) { 28 | if (typeof left === "number") { 29 | return mathMax(left, right ?? null); 30 | } 31 | 32 | if (typeof right === "number") { 33 | return mathMax(right, left ?? null); 34 | } 35 | 36 | return null; 37 | } 38 | 39 | export function nullableArrayUnion( 40 | left: T[] | null | undefined, 41 | right: T[] | null | undefined, 42 | ) { 43 | if (!Array.isArray(left) && !Array.isArray(right)) { 44 | return null; 45 | } 46 | 47 | const uniqueSet = new Set(); 48 | 49 | if (Array.isArray(left)) { 50 | left.forEach((v) => uniqueSet.add(v)); 51 | } 52 | 53 | if (Array.isArray(right)) { 54 | right.forEach((v) => uniqueSet.add(v)); 55 | } 56 | 57 | return Array.from(uniqueSet); 58 | } 59 | -------------------------------------------------------------------------------- /src/utils/link/link-import.ts: -------------------------------------------------------------------------------- 1 | import { ConstValueNode, Kind } from "graphql"; 2 | 3 | export class FederatedLinkImport { 4 | constructor( 5 | public name: string, 6 | public as: string | null, 7 | ) {} 8 | 9 | public toString(): string { 10 | return this.as 11 | ? `{ name: "${this.name}", as: "${this.as}" }` 12 | : `"${this.name}"`; 13 | } 14 | 15 | static fromTypedefs(node: ConstValueNode): FederatedLinkImport[] { 16 | if (node.kind == Kind.LIST) { 17 | const imports = node.values.map((v) => { 18 | if (v.kind === Kind.STRING) { 19 | return new FederatedLinkImport(v.value, null); 20 | } 21 | if (v.kind === Kind.OBJECT) { 22 | let name: string = ""; 23 | let as: string | null = null; 24 | 25 | v.fields.forEach((f) => { 26 | if (f.name.value === "name") { 27 | if (f.value.kind !== Kind.STRING) { 28 | throw new Error( 29 | `Expected string value for @link "name" field but got "${f.value.kind}"`, 30 | ); 31 | } 32 | name = f.value.value; 33 | } else if (f.name.value === "as") { 34 | if (f.value.kind !== Kind.STRING) { 35 | throw new Error( 36 | `Expected string value for @link "as" field but got "${f.value.kind}"`, 37 | ); 38 | } 39 | as = f.value.value; 40 | } 41 | }); 42 | return new FederatedLinkImport(name, as); 43 | } 44 | throw new Error( 45 | `Unexpected value kind "${v.kind}" in @link import declaration`, 46 | ); 47 | }); 48 | return imports; 49 | } 50 | throw new Error(`Expected a list of @link imports but got "${node.kind}"`); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/utils/state.ts: -------------------------------------------------------------------------------- 1 | export function stripTypeModifiers(type: string) { 2 | return type.replaceAll("!", "").replaceAll("[", "").replaceAll("]", ""); 3 | } 4 | 5 | export function stripNonNull(type: string) { 6 | return type.replace(/\!$/, ""); 7 | } 8 | 9 | export function stripList(type: string) { 10 | return type.replace(/^\[/, "").replace(/\]$/, ""); 11 | } 12 | 13 | export function isNonNull(type: string) { 14 | return type.endsWith("!"); 15 | } 16 | 17 | export function isList(type: string) { 18 | return type.endsWith("]"); 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/version.ts: -------------------------------------------------------------------------------- 1 | import { FederationVersion } from "../specifications/federation.js"; 2 | 3 | type UnsupportedVersion = "v2.7" | "v2.8"; 4 | 5 | export function satisfiesVersionRange( 6 | version: FederationVersion, 7 | range: `${"<" | ">=" | ">"} ${FederationVersion | UnsupportedVersion}`, 8 | ) { 9 | const [sign, ver] = range.split(" ") as [ 10 | "<" | ">=" | ">", 11 | FederationVersion | UnsupportedVersion, 12 | ]; 13 | const versionInRange = parseFloat(ver.replace("v", "")); 14 | const detectedVersion = parseFloat(version.replace("v", "")); 15 | 16 | if (sign === "<") { 17 | return detectedVersion < versionInRange; 18 | } 19 | 20 | if (sign === ">") { 21 | return detectedVersion > versionInRange; 22 | } 23 | 24 | return detectedVersion >= versionInRange; 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "./src", 4 | "target": "ES2022", 5 | "module": "ES2022", 6 | "moduleResolution": "node", 7 | "declaration": true, 8 | "declarationMap": true, 9 | "sourceMap": true, 10 | "outDir": "./dist", 11 | "removeComments": true, 12 | "isolatedModules": true, 13 | "esModuleInterop": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "strict": true 16 | }, 17 | "files": ["src/index.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "ES2022", 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "outDir": "./dist", 9 | "removeComments": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "resolveJsonModule": true, 13 | "jsx": "react-jsx", 14 | "forceConsistentCasingInFileNames": true, 15 | "allowSyntheticDefaultImports": true, 16 | "strict": true 17 | }, 18 | "include": ["src", "__tests__"] 19 | } 20 | -------------------------------------------------------------------------------- /vitest.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | include: ["src/**/*.spec.ts", "__tests__/**/*.spec.ts"], 6 | setupFiles: ["./__tests__/shared/setup.ts"], 7 | }, 8 | }); 9 | --------------------------------------------------------------------------------